aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2021-11-27 22:59:29 +0100
committerAleksander Morgado <aleksander@aleksander.es>2021-12-24 14:06:11 +0100
commitb90d64192aad518ca027265f5680314af75d2f12 (patch)
treeeb4091b164ff2b6af2ac40069cb6314d1b7e8f39 /src
parent6ba245cedccb9678e0d340280db154e7f2803734 (diff)
broadband-modem-mbim: support profile properties from MbimProvisionedContextElementV2
Microsoft defined a new extended version of the "provisioned contexts" operation from the generic MBIM basic connect service. This extended version adds several new settings that can be stored in the profile (e.g. IP type, media type, roaming allowance...). But this new version has a huge drawback; we cannot specify single profiles via their unique id while we perform update/delete operations in the modem. Instead, Microsoft explains that we should use the context type to identify the target context; but this will ONLY work if we have one context defined for each type. As soon as we have multiple contexts of the same type, this operation may fail or otherwise update multiple contexts at once.
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem-mbim.c406
-rw-r--r--src/mm-modem-helpers-mbim.c196
-rw-r--r--src/mm-modem-helpers-mbim.h27
3 files changed, 574 insertions, 55 deletions
diff --git a/src/mm-broadband-modem-mbim.c b/src/mm-broadband-modem-mbim.c
index 93b74e60..e94b957b 100644
--- a/src/mm-broadband-modem-mbim.c
+++ b/src/mm-broadband-modem-mbim.c
@@ -116,6 +116,7 @@ struct _MMBroadbandModemMbimPrivate {
/* Supported features */
gboolean is_profile_management_supported;
+ gboolean is_profile_management_ext_supported;
gboolean is_pco_supported;
gboolean is_lte_attach_info_supported;
gboolean is_nr5g_registration_settings_supported;
@@ -2632,6 +2633,9 @@ query_device_services_ready (MbimDevice *device,
} else if (device_services[i]->cids[j] == MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_REGISTRATION_PARAMETERS) {
mm_obj_dbg (self, "5GNR registration settings are supported");
self->priv->is_nr5g_registration_settings_supported = TRUE;
+ } else if (device_services[i]->cids[j] == MBIM_CID_MS_BASIC_CONNECT_EXTENSIONS_PROVISIONED_CONTEXTS) {
+ mm_obj_dbg (self, "Profile management extension is supported");
+ self->priv->is_profile_management_ext_supported = TRUE;
}
}
continue;
@@ -6036,7 +6040,7 @@ enable_unsolicited_events_3gpp_profile_manager (MMIfaceModem3gppProfileManager *
/* Check format (3gppProfileManager interface) */
static gboolean
-modem_3gpp_profile_manager_check_format_finish (MMIfaceModem3gppProfileManager *self,
+modem_3gpp_profile_manager_check_format_finish (MMIfaceModem3gppProfileManager *_self,
GAsyncResult *res,
gboolean *new_id,
gint *min_profile_id,
@@ -6045,6 +6049,8 @@ modem_3gpp_profile_manager_check_format_finish (MMIfaceModem3gppProfileManager
MM3gppProfileCmpFlags *profile_cmp_flags,
GError **error)
{
+ MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
+
if (!g_task_propagate_boolean (G_TASK (res), error)) {
g_assert_not_reached ();
return FALSE;
@@ -6059,11 +6065,17 @@ modem_3gpp_profile_manager_check_format_finish (MMIfaceModem3gppProfileManager
/* use default string comparison method */
if (apn_cmp)
*apn_cmp = NULL;
- if (profile_cmp_flags)
- *profile_cmp_flags = (MM_3GPP_PROFILE_CMP_FLAGS_NO_IP_TYPE |
- MM_3GPP_PROFILE_CMP_FLAGS_NO_ACCESS_TYPE_PREFERENCE |
- MM_3GPP_PROFILE_CMP_FLAGS_NO_ROAMING_ALLOWANCE |
- MM_3GPP_PROFILE_CMP_FLAGS_NO_PROFILE_SOURCE);
+ if (profile_cmp_flags) {
+ if (!self->priv->is_profile_management_ext_supported)
+ *profile_cmp_flags = (MM_3GPP_PROFILE_CMP_FLAGS_NO_IP_TYPE |
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_ACCESS_TYPE_PREFERENCE |
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_ROAMING_ALLOWANCE |
+ MM_3GPP_PROFILE_CMP_FLAGS_NO_PROFILE_SOURCE);
+ else
+ /* when using the MS extensions, we support all IP type, access type
+ * preference, roaming allowance and profile source */
+ *profile_cmp_flags = 0;
+ }
return TRUE;
}
@@ -6132,6 +6144,60 @@ provisioned_context_element_to_3gpp_profile (MbimProvisionedContextElement *elem
return profile;
}
+static MM3gppProfile *
+provisioned_context_element_v2_to_3gpp_profile (MMBroadbandModemMbim *self,
+ MbimProvisionedContextElementV2 *element)
+{
+ MM3gppProfile *profile;
+ MMBearerApnType apn_type;
+ GError *error = NULL;
+ gboolean enabled;
+ MMBearerRoamingAllowance roaming_allowance;
+ MMBearerAccessTypePreference access_type_preference;
+ MMBearerProfileSource profile_source;
+
+ apn_type = mm_bearer_apn_type_from_mbim_context_type (mbim_uuid_to_context_type (&element->context_type));
+ if (apn_type == MM_BEARER_APN_TYPE_NONE)
+ return NULL;
+
+ profile = mm_3gpp_profile_new ();
+ mm_3gpp_profile_set_profile_id (profile, element->context_id);
+ mm_3gpp_profile_set_apn (profile, element->access_string);
+ mm_3gpp_profile_set_apn_type (profile, apn_type);
+ mm_3gpp_profile_set_user (profile, element->user_name);
+ mm_3gpp_profile_set_password (profile, element->password);
+ mm_3gpp_profile_set_allowed_auth (profile, (mm_bearer_allowed_auth_from_mbim_auth_protocol (element->auth_protocol)));
+
+ if (!mm_boolean_from_mbim_context_state (element->state, &enabled, &error)) {
+ mm_obj_dbg (self, "ignoring enable setting: %s", error->message);
+ g_clear_error (&error);
+ } else
+ mm_3gpp_profile_set_enabled (profile, enabled);
+
+ roaming_allowance = mm_bearer_roaming_allowance_from_mbim_context_roaming_control (element->roaming, &error);
+ if (roaming_allowance == MM_BEARER_ROAMING_ALLOWANCE_NONE) {
+ mm_obj_dbg (self, "ignoring roaming allowance: %s", error->message);
+ g_clear_error (&error);
+ } else
+ mm_3gpp_profile_set_roaming_allowance (profile, roaming_allowance);
+
+ if (!mm_bearer_access_type_preference_from_mbim_context_media_type (element->media_type, &access_type_preference, &error)) {
+ mm_obj_dbg (self, "ignoring access type preference: %s", error->message);
+ g_clear_error (&error);
+ } else
+ mm_3gpp_profile_set_access_type_preference (profile, access_type_preference);
+
+ profile_source = mm_bearer_profile_source_from_mbim_context_source (element->source, &error);
+ if (profile_source == MM_BEARER_PROFILE_SOURCE_UNKNOWN) {
+ mm_obj_dbg (self, "ignoring profile source: %s", error->message);
+ g_clear_error (&error);
+ } else
+ mm_3gpp_profile_set_profile_source (profile, profile_source);
+
+ /* compression unused, and ip-type not provided */
+ return profile;
+}
+
static void
profile_manager_provisioned_contexts_query_ready (MbimDevice *device,
GAsyncResult *res,
@@ -6139,42 +6205,84 @@ profile_manager_provisioned_contexts_query_ready (MbimDevice *device,
{
ListProfilesContext *ctx;
GError *error = NULL;
+ guint i;
guint32 provisioned_contexts_count = 0;
g_autoptr(MbimMessage) response = NULL;
g_autoptr(MbimProvisionedContextElementArray) provisioned_contexts = NULL;
- ctx = g_slice_new0 (ListProfilesContext);
- g_task_set_task_data (task, ctx, (GDestroyNotify) list_profiles_context_free);
+ ctx = g_task_get_task_data (task);
response = mbim_device_command_finish (device, res, &error);
- if (response &&
- mbim_message_response_get_result (response,
- MBIM_MESSAGE_TYPE_COMMAND_DONE,
- &error) &&
- mbim_message_provisioned_contexts_response_parse (response,
- &provisioned_contexts_count,
- &provisioned_contexts,
- &error)) {
- guint i;
+ if (!response ||
+ !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) ||
+ !mbim_message_provisioned_contexts_response_parse (response,
+ &provisioned_contexts_count,
+ &provisioned_contexts,
+ &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
- for (i = 0; i < provisioned_contexts_count; i++) {
- MM3gppProfile *profile;
+ for (i = 0; i < provisioned_contexts_count; i++) {
+ MM3gppProfile *profile;
- profile = provisioned_context_element_to_3gpp_profile (provisioned_contexts[i]);
- if (profile)
- ctx->profiles = g_list_append (ctx->profiles, profile);
- }
- g_task_return_boolean (task, TRUE);
- } else
+ profile = provisioned_context_element_to_3gpp_profile (provisioned_contexts[i]);
+ if (profile)
+ ctx->profiles = g_list_append (ctx->profiles, profile);
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+profile_manager_provisioned_contexts_v2_query_ready (MbimDevice *device,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemMbim *self;
+ ListProfilesContext *ctx;
+ GError *error = NULL;
+ guint i;
+ guint32 provisioned_contexts_count = 0;
+ g_autoptr(MbimMessage) response = NULL;
+ g_autoptr(MbimProvisionedContextElementV2Array) provisioned_contexts_v2 = NULL;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ response = mbim_device_command_finish (device, res, &error);
+ if (!response ||
+ !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error) ||
+ !mbim_message_ms_basic_connect_extensions_provisioned_contexts_response_parse (response,
+ &provisioned_contexts_count,
+ &provisioned_contexts_v2,
+ &error)) {
g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ for (i = 0; i < provisioned_contexts_count; i++) {
+ MM3gppProfile *profile;
+
+ profile = provisioned_context_element_v2_to_3gpp_profile (self, provisioned_contexts_v2[i]);
+ if (profile)
+ ctx->profiles = g_list_append (ctx->profiles, profile);
+ }
+
+ g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
-modem_3gpp_profile_manager_list_profiles (MMIfaceModem3gppProfileManager *self,
+modem_3gpp_profile_manager_list_profiles (MMIfaceModem3gppProfileManager *_self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
+ ListProfilesContext *ctx;
MbimDevice *device;
GTask *task;
g_autoptr(MbimMessage) message = NULL;
@@ -6183,10 +6291,23 @@ modem_3gpp_profile_manager_list_profiles (MMIfaceModem3gppProfileManager *self,
return;
task = g_task_new (self, NULL, callback, user_data);
+ ctx = g_slice_new0 (ListProfilesContext);
+ g_task_set_task_data (task, ctx, (GDestroyNotify) list_profiles_context_free);
mm_obj_dbg (self, "querying provisioned contexts...");
- message = mbim_message_provisioned_contexts_query_new (NULL);
+ if (self->priv->is_profile_management_ext_supported) {
+ message = mbim_message_ms_basic_connect_extensions_provisioned_contexts_query_new (NULL);
+ mbim_device_command (device,
+ message,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)profile_manager_provisioned_contexts_v2_query_ready,
+ task);
+ return;
+ }
+
+ message = mbim_message_provisioned_contexts_query_new (NULL);
mbim_device_command (device,
message,
10,
@@ -6226,25 +6347,26 @@ profile_manager_provisioned_contexts_set_ready (MbimDevice *device,
}
static void
-modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self,
+modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *_self,
MM3gppProfile *profile,
GAsyncReadyCallback callback,
gpointer user_data)
{
- MbimDevice *device;
- GTask *task;
- GError *error = NULL;
- gint profile_id;
- MMBearerApnType apn_type;
- MMBearerAllowedAuth allowed_auth;
- MbimAuthProtocol auth_protocol = MBIM_AUTH_PROTOCOL_NONE;
- MbimContextType context_type;
- const MbimUuid *context_type_uuid;
- const gchar *apn;
- const gchar *user;
- const gchar *password;
- g_autofree gchar *apn_type_str = NULL;
- g_autoptr(MbimMessage) message = NULL;
+ MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
+ MbimDevice *device;
+ GTask *task;
+ GError *error = NULL;
+ gint profile_id;
+ MMBearerApnType apn_type;
+ MMBearerAllowedAuth allowed_auth;
+ MbimAuthProtocol auth_protocol = MBIM_AUTH_PROTOCOL_NONE;
+ MbimContextType context_type;
+ const MbimUuid *context_type_uuid;
+ const gchar *apn;
+ const gchar *user;
+ const gchar *password;
+ g_autofree gchar *apn_type_str = NULL;
+ g_autoptr(MbimMessage) message = NULL;
if (!peek_device (self, &device, callback, user_data))
return;
@@ -6260,6 +6382,7 @@ modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self,
apn_type = mm_3gpp_profile_get_apn_type (profile);
context_type = mm_bearer_apn_type_to_mbim_context_type (apn_type, self, &error);
if (error) {
+ g_prefix_error (&error, "Failed to convert mbim context type from apn type: ");
g_task_return_error (task, error);
g_object_unref (task);
return;
@@ -6275,24 +6398,87 @@ modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self,
if ((allowed_auth != MM_BEARER_ALLOWED_AUTH_UNKNOWN) || user || password) {
auth_protocol = mm_bearer_allowed_auth_to_mbim_auth_protocol (allowed_auth, self, &error);
if (error) {
+ g_prefix_error (&error, "Failed to convert mbim auth protocol from allowed auth: ");
g_task_return_error (task, error);
g_object_unref (task);
return;
}
}
- mm_obj_dbg (self, "storing profile '%d': apn '%s', apn type '%s'",
- profile_id, apn, apn_type_str);
+ if (self->priv->is_profile_management_ext_supported) {
+ MbimContextIpType ip_type;
+ MbimContextState state;
+ MbimContextRoamingControl roaming;
+ MbimContextMediaType media_type;
+ MbimContextSource source;
+
+ state = mm_boolean_to_mbim_context_state (mm_3gpp_profile_get_enabled (profile));
+
+ ip_type = mm_bearer_ip_family_to_mbim_context_ip_type (mm_3gpp_profile_get_ip_type (profile), &error);
+ if (error) {
+ g_prefix_error (&error, "Failed to convert mbim context ip type from ip type: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!mm_bearer_roaming_allowance_to_mbim_context_roaming_control (mm_3gpp_profile_get_roaming_allowance (profile), self, &roaming, &error)) {
+ g_prefix_error (&error, "Failed to convert mbim context roaming control from roaming allowance: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!mm_bearer_access_type_preference_to_mbim_context_media_type (mm_3gpp_profile_get_access_type_preference (profile), self, &media_type, &error)) {
+ g_prefix_error (&error, "Failed to convert mbim context media type from access type preference: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!mm_bearer_profile_source_to_mbim_context_source (mm_3gpp_profile_get_profile_source (profile), self, &source, &error)) {
+ g_prefix_error (&error, "Failed to convert mbim context source from profile source: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* We don't pass the profile ID, because the MS extended version does
+ * not support it. This is extremely wrong, and I have no idea how we
+ * can make this work reliably. According to the documentation, the
+ * modem would choose automatically which profile to update based on
+ * the specified context type... but what if we have multiple contexts
+ * of the same type? */
+
+ mm_obj_dbg (self, "using MS extensions to manage provisioned contexts: updating profiles matching context type");
+ mm_obj_dbg (self, "updating profiles with context type '%s'", mbim_context_type_get_string (context_type));
+ message = mbim_message_ms_basic_connect_extensions_provisioned_contexts_set_new (MBIM_CONTEXT_OPERATION_DEFAULT,
+ context_type_uuid,
+ ip_type,
+ state,
+ roaming,
+ media_type,
+ source,
+ apn ? apn : "",
+ user ? user : "",
+ password ? password : "",
+ MBIM_COMPRESSION_NONE,
+ auth_protocol,
+ &error);
+ } else {
+ mm_obj_dbg (self, "storing profile '%d': apn '%s', apn type '%s'",
+ profile_id, apn, apn_type_str);
+ message = mbim_message_provisioned_contexts_set_new (profile_id,
+ context_type_uuid,
+ apn ? apn : "",
+ user ? user : "",
+ password ? password : "",
+ MBIM_COMPRESSION_NONE,
+ auth_protocol,
+ "", /* provider id */
+ &error);
+ }
- message = mbim_message_provisioned_contexts_set_new (profile_id,
- context_type_uuid,
- apn ? apn : "",
- user ? user : "",
- password ? password : "",
- MBIM_COMPRESSION_NONE,
- auth_protocol,
- "", /* provider id */
- &error);
if (error) {
g_task_return_error (task, error);
g_object_unref (task);
@@ -6310,6 +6496,19 @@ modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self,
/*****************************************************************************/
/* Delete profile (3GPP profile management interface) */
+typedef struct {
+ MbimDevice *device;
+ MM3gppProfile *profile;
+} DeleteProfileContext;
+
+static void
+delete_profile_context_free (DeleteProfileContext *ctx)
+{
+ g_object_unref (ctx->device);
+ g_object_unref (ctx->profile);
+ g_slice_free (DeleteProfileContext, ctx);
+}
+
static gboolean
modem_3gpp_profile_manager_delete_profile_finish (MMIfaceModem3gppProfileManager *self,
GAsyncResult *res,
@@ -6335,11 +6534,95 @@ profile_manager_provisioned_contexts_reset_ready (MbimDevice *device,
}
static void
-modem_3gpp_profile_manager_delete_profile (MMIfaceModem3gppProfileManager *self,
+list_profiles_delete_ready (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ g_autoptr(MbimMessage) message = NULL;
+ DeleteProfileContext *ctx;
+ MbimContextType context_type;
+ const MbimUuid *context_type_uuid = NULL;
+ GError *error = NULL;
+ GList *profiles = NULL;
+ MM3gppProfile *found = NULL;
+ GList *l;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!modem_3gpp_profile_manager_list_profiles_finish (self, res, &profiles, &error)) {
+ g_prefix_error (&error, "Couldn't list profiles during delete operation: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ /* look for the exact profile id match */
+ for (l = profiles; l; l = g_list_next (l)) {
+ MM3gppProfile *profile;
+
+ profile = MM_3GPP_PROFILE (l->data);
+ if (mm_3gpp_profile_get_profile_id (profile) == mm_3gpp_profile_get_profile_id (ctx->profile)) {
+ found = profile;
+ break;
+ }
+ }
+
+ if (!found) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't find profile with id '%u'", mm_3gpp_profile_get_profile_id (ctx->profile));
+ g_object_unref (task);
+ g_list_free_full (profiles, g_object_unref);
+ return;
+ }
+
+ context_type = mm_bearer_apn_type_to_mbim_context_type (mm_3gpp_profile_get_apn_type (found), self, &error);
+ if (error) {
+ g_prefix_error (&error, "Failed to convert mbim context type from apn type: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ g_list_free_full (profiles, g_object_unref);
+ return;
+ }
+ context_type_uuid = mbim_uuid_from_context_type (context_type);
+ g_list_free_full (profiles, g_object_unref);
+
+ mm_obj_dbg (self, "using MS extensions to manage provisioned contexts: deleting profiles matching context type");
+ mm_obj_dbg (self, "deleting profiles with context type '%s'", mbim_context_type_get_string (context_type));
+
+ message = mbim_message_ms_basic_connect_extensions_provisioned_contexts_set_new (MBIM_CONTEXT_OPERATION_DELETE,
+ context_type_uuid,
+ MBIM_CONTEXT_IP_TYPE_DEFAULT,
+ MBIM_CONTEXT_STATE_DISABLED,
+ MBIM_CONTEXT_ROAMING_CONTROL_ALLOW_ALL,
+ MBIM_CONTEXT_MEDIA_TYPE_ALL,
+ MBIM_CONTEXT_SOURCE_ADMIN,
+ "", /* access string */
+ "", /* user */
+ "", /* password */
+ MBIM_COMPRESSION_NONE,
+ MBIM_AUTH_PROTOCOL_NONE,
+ &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ mbim_device_command (ctx->device,
+ message,
+ 10,
+ NULL,
+ (GAsyncReadyCallback)profile_manager_provisioned_contexts_reset_ready,
+ task);
+}
+
+static void
+modem_3gpp_profile_manager_delete_profile (MMIfaceModem3gppProfileManager *_self,
MM3gppProfile *profile,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ MMBroadbandModemMbim *self = MM_BROADBAND_MODEM_MBIM (_self);
MbimDevice *device;
GTask *task;
GError *error = NULL;
@@ -6354,8 +6637,21 @@ modem_3gpp_profile_manager_delete_profile (MMIfaceModem3gppProfileManager *self,
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);
+ if (self->priv->is_profile_management_ext_supported) {
+ DeleteProfileContext *ctx;
+ ctx = g_slice_new0 (DeleteProfileContext);
+ ctx->profile = g_object_ref (profile);
+ ctx->device = g_object_ref (device);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)delete_profile_context_free);
+
+ modem_3gpp_profile_manager_list_profiles (_self,
+ (GAsyncReadyCallback)list_profiles_delete_ready,
+ task);
+ return;
+ }
+
+ mm_obj_dbg (self, "deleting profile '%d'", profile_id);
message = mbim_message_provisioned_contexts_set_new (profile_id,
mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_NONE),
"", /* access string */
diff --git a/src/mm-modem-helpers-mbim.c b/src/mm-modem-helpers-mbim.c
index 7502a82d..0afa9356 100644
--- a/src/mm-modem-helpers-mbim.c
+++ b/src/mm-modem-helpers-mbim.c
@@ -612,6 +612,202 @@ mm_bearer_ip_family_to_mbim_context_ip_type (MMBearerIpFamily ip_family,
/*****************************************************************************/
+gboolean
+mm_bearer_roaming_allowance_to_mbim_context_roaming_control (MMBearerRoamingAllowance mask,
+ gpointer log_object,
+ MbimContextRoamingControl *out_value,
+ GError **error)
+{
+ if (mask == MM_BEARER_ROAMING_ALLOWANCE_NONE) {
+ mm_obj_dbg (log_object, "using default (all) roaming allowance");
+ *out_value = MBIM_CONTEXT_ROAMING_CONTROL_ALLOW_ALL;
+ } else if (mask == MM_BEARER_ROAMING_ALLOWANCE_HOME)
+ *out_value =MBIM_CONTEXT_ROAMING_CONTROL_HOME_ONLY;
+ else if (mask == MM_BEARER_ROAMING_ALLOWANCE_PARTNER)
+ *out_value =MBIM_CONTEXT_ROAMING_CONTROL_PARTNER_ONLY;
+ else if (mask == MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER)
+ *out_value =MBIM_CONTEXT_ROAMING_CONTROL_NON_PARTNER_ONLY;
+ else if (mask == (MM_BEARER_ROAMING_ALLOWANCE_HOME | MM_BEARER_ROAMING_ALLOWANCE_PARTNER))
+ *out_value =MBIM_CONTEXT_ROAMING_CONTROL_HOME_AND_PARTNER;
+ else if (mask == (MM_BEARER_ROAMING_ALLOWANCE_HOME | MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER))
+ *out_value =MBIM_CONTEXT_ROAMING_CONTROL_HOME_AND_NON_PARTNER;
+ else if (mask == (MM_BEARER_ROAMING_ALLOWANCE_PARTNER | MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER))
+ *out_value =MBIM_CONTEXT_ROAMING_CONTROL_PARTNER_AND_NON_PARTNER;
+ else if (mask == (MM_BEARER_ROAMING_ALLOWANCE_HOME | MM_BEARER_ROAMING_ALLOWANCE_PARTNER | MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER))
+ *out_value = MBIM_CONTEXT_ROAMING_CONTROL_ALLOW_ALL;
+ else {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported roaming allowance mask: 0x%x", mask);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+MMBearerRoamingAllowance
+mm_bearer_roaming_allowance_from_mbim_context_roaming_control (MbimContextRoamingControl value,
+ GError **error)
+{
+ switch (value) {
+ case MBIM_CONTEXT_ROAMING_CONTROL_HOME_ONLY:
+ return MM_BEARER_ROAMING_ALLOWANCE_HOME;
+ case MBIM_CONTEXT_ROAMING_CONTROL_PARTNER_ONLY:
+ return MM_BEARER_ROAMING_ALLOWANCE_PARTNER;
+ case MBIM_CONTEXT_ROAMING_CONTROL_NON_PARTNER_ONLY:
+ return MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER;
+ case MBIM_CONTEXT_ROAMING_CONTROL_HOME_AND_PARTNER:
+ return (MM_BEARER_ROAMING_ALLOWANCE_HOME | MM_BEARER_ROAMING_ALLOWANCE_PARTNER);
+ case MBIM_CONTEXT_ROAMING_CONTROL_HOME_AND_NON_PARTNER:
+ return (MM_BEARER_ROAMING_ALLOWANCE_HOME | MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER);
+ case MBIM_CONTEXT_ROAMING_CONTROL_PARTNER_AND_NON_PARTNER:
+ return (MM_BEARER_ROAMING_ALLOWANCE_PARTNER | MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER);
+ case MBIM_CONTEXT_ROAMING_CONTROL_ALLOW_ALL:
+ return (MM_BEARER_ROAMING_ALLOWANCE_HOME | MM_BEARER_ROAMING_ALLOWANCE_PARTNER | MM_BEARER_ROAMING_ALLOWANCE_NON_PARTNER);
+ default:
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported roaming control value: 0x%x", value);
+ return MM_BEARER_ROAMING_ALLOWANCE_NONE;
+ }
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_bearer_access_type_preference_to_mbim_context_media_type (MMBearerAccessTypePreference value,
+ gpointer log_object,
+ MbimContextMediaType *out_value,
+ GError **error)
+{
+ switch (value) {
+ case MM_BEARER_ACCESS_TYPE_PREFERENCE_NONE:
+ mm_obj_dbg (log_object, "using default (cellular only) context media type");
+ *out_value = MBIM_CONTEXT_MEDIA_TYPE_CELLULAR_ONLY;
+ return TRUE;
+ case MM_BEARER_ACCESS_TYPE_PREFERENCE_3GPP_ONLY:
+ *out_value = MBIM_CONTEXT_MEDIA_TYPE_CELLULAR_ONLY;
+ return TRUE;
+ case MM_BEARER_ACCESS_TYPE_PREFERENCE_3GPP_PREFERRED:
+ *out_value = MBIM_CONTEXT_MEDIA_TYPE_ALL;
+ return TRUE;
+ case MM_BEARER_ACCESS_TYPE_PREFERENCE_NON_3GPP_ONLY:
+ *out_value = MBIM_CONTEXT_MEDIA_TYPE_WIFI_ONLY;
+ return TRUE;
+ default:
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported roaming control value: 0x%x", value);
+ return FALSE;
+ }
+}
+
+gboolean
+mm_bearer_access_type_preference_from_mbim_context_media_type (MbimContextMediaType value,
+ MMBearerAccessTypePreference *out_value,
+ GError **error)
+{
+ switch (value) {
+ case MBIM_CONTEXT_MEDIA_TYPE_CELLULAR_ONLY:
+ *out_value = MM_BEARER_ACCESS_TYPE_PREFERENCE_3GPP_ONLY;
+ return TRUE;
+ case MBIM_CONTEXT_MEDIA_TYPE_WIFI_ONLY:
+ *out_value = MM_BEARER_ACCESS_TYPE_PREFERENCE_NON_3GPP_ONLY;
+ return TRUE;
+ case MBIM_CONTEXT_MEDIA_TYPE_ALL:
+ *out_value = MM_BEARER_ACCESS_TYPE_PREFERENCE_3GPP_PREFERRED;
+ return TRUE;
+ default:
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported roaming control value: 0x%x", value);
+ return FALSE;
+ }
+}
+
+/*****************************************************************************/
+
+gboolean
+mm_boolean_from_mbim_context_state (MbimContextState value,
+ gboolean *out_value,
+ GError **error)
+{
+ switch (value) {
+ case MBIM_CONTEXT_STATE_DISABLED:
+ *out_value = FALSE;
+ return TRUE;
+ case MBIM_CONTEXT_STATE_ENABLED:
+ *out_value = TRUE;
+ return TRUE;
+ default:
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported context state value: 0x%x", value);
+ return FALSE;
+ }
+
+}
+
+MbimContextState
+mm_boolean_to_mbim_context_state (gboolean value)
+{
+ return (value ? MBIM_CONTEXT_STATE_ENABLED: MBIM_CONTEXT_STATE_DISABLED);
+}
+
+/*****************************************************************************/
+
+MMBearerProfileSource
+mm_bearer_profile_source_from_mbim_context_source (MbimContextSource value,
+ GError **error)
+{
+ switch (value) {
+ case MBIM_CONTEXT_SOURCE_ADMIN:
+ return MM_BEARER_PROFILE_SOURCE_ADMIN;
+ case MBIM_CONTEXT_SOURCE_USER:
+ return MM_BEARER_PROFILE_SOURCE_USER;
+ case MBIM_CONTEXT_SOURCE_OPERATOR:
+ return MM_BEARER_PROFILE_SOURCE_OPERATOR;
+ case MBIM_CONTEXT_SOURCE_MODEM:
+ return MM_BEARER_PROFILE_SOURCE_MODEM;
+ case MBIM_CONTEXT_SOURCE_DEVICE:
+ return MM_BEARER_PROFILE_SOURCE_DEVICE;
+ default:
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported context source value: 0x%x", value);
+ return MM_BEARER_PROFILE_SOURCE_UNKNOWN;
+ }
+}
+
+gboolean
+mm_bearer_profile_source_to_mbim_context_source (MMBearerProfileSource value,
+ gpointer log_object,
+ MbimContextSource *out_value,
+ GError **error)
+{
+ switch (value) {
+ case MM_BEARER_PROFILE_SOURCE_UNKNOWN:
+ mm_obj_dbg (log_object, "using default (admin) context source");
+ *out_value = MBIM_CONTEXT_SOURCE_ADMIN;
+ return TRUE;
+ case MM_BEARER_PROFILE_SOURCE_ADMIN:
+ *out_value = MBIM_CONTEXT_SOURCE_ADMIN;
+ return TRUE;
+ case MM_BEARER_PROFILE_SOURCE_USER:
+ *out_value = MBIM_CONTEXT_SOURCE_USER;
+ return TRUE;
+ case MM_BEARER_PROFILE_SOURCE_OPERATOR:
+ *out_value = MBIM_CONTEXT_SOURCE_OPERATOR;
+ return TRUE;
+ case MM_BEARER_PROFILE_SOURCE_MODEM:
+ *out_value = MBIM_CONTEXT_SOURCE_MODEM;
+ return TRUE;
+ case MM_BEARER_PROFILE_SOURCE_DEVICE:
+ *out_value = MBIM_CONTEXT_SOURCE_DEVICE;
+ return TRUE;
+ default:
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Unsupported profile source value: 0x%x", value);
+ return FALSE;
+ }
+}
+
+/*****************************************************************************/
+
/* index in the array is the code point (8 possible values), and the actual
* value is the lower limit of the error rate range. */
static const gdouble bit_error_rate_ranges[] = { 0.00, 0.20, 0.40, 0.80, 1.60, 3.20, 6.40, 12.80 };
diff --git a/src/mm-modem-helpers-mbim.h b/src/mm-modem-helpers-mbim.h
index 909d0186..abf5413b 100644
--- a/src/mm-modem-helpers-mbim.h
+++ b/src/mm-modem-helpers-mbim.h
@@ -67,6 +67,33 @@ MbimContextType mm_bearer_apn_type_to_mbim_context_type (MMBearerApnT
gpointer log_object,
GError **error);
+gboolean mm_bearer_roaming_allowance_to_mbim_context_roaming_control (MMBearerRoamingAllowance mask,
+ gpointer log_object,
+ MbimContextRoamingControl *out_value,
+ GError **error);
+MMBearerRoamingAllowance mm_bearer_roaming_allowance_from_mbim_context_roaming_control (MbimContextRoamingControl value,
+ GError **error);
+
+gboolean mm_bearer_access_type_preference_to_mbim_context_media_type (MMBearerAccessTypePreference value,
+ gpointer log_object,
+ MbimContextMediaType *out_value,
+ GError **error);
+gboolean mm_bearer_access_type_preference_from_mbim_context_media_type (MbimContextMediaType value,
+ MMBearerAccessTypePreference *out_value,
+ GError **error);
+
+gboolean mm_boolean_from_mbim_context_state (MbimContextState value,
+ gboolean *out_value,
+ GError **error);
+MbimContextState mm_boolean_to_mbim_context_state (gboolean value);
+
+MMBearerProfileSource mm_bearer_profile_source_from_mbim_context_source (MbimContextSource value,
+ GError **error);
+gboolean mm_bearer_profile_source_to_mbim_context_source (MMBearerProfileSource value,
+ gpointer log_object,
+ MbimContextSource *out_value,
+ GError **error);
+
gboolean mm_signal_error_rate_percentage_from_coded_value (guint coded_value,
gdouble *out_percentage,
gboolean is_gsm,