diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2021-04-06 16:07:09 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2021-04-29 10:13:22 +0000 |
commit | 5d2db5de9823301ad49abe2406351889bef3bf92 (patch) | |
tree | c13c5f8ad8cdabb555a96f816da0de1249823c40 /src/mm-bearer-mbim.c | |
parent | 72879e4095bde2ee354a61f475ebc8bc847541c5 (diff) |
bearer-mbim: implement connection logic using existing profiles
Unlike other implementations, with MBIM we cannot tell the modem to
connect a given profile by its profile number, which is a bit strange,
but it looks like there is no way to do that. So, if the user requests
to connect a given profile, what we do is load the profile settings by
querying the modem, and use those settings in the connect request.
Diffstat (limited to 'src/mm-bearer-mbim.c')
-rw-r--r-- | src/mm-bearer-mbim.c | 372 |
1 files changed, 215 insertions, 157 deletions
diff --git a/src/mm-bearer-mbim.c b/src/mm-bearer-mbim.c index efe90ef1..2f7fb23b 100644 --- a/src/mm-bearer-mbim.c +++ b/src/mm-bearer-mbim.c @@ -27,6 +27,7 @@ #include <libmm-glib.h> #include "mm-iface-modem.h" +#include "mm-iface-modem-3gpp-profile-manager.h" #include "mm-modem-helpers-mbim.h" #include "mm-port-enums-types.h" #include "mm-bearer-mbim.h" @@ -196,8 +197,8 @@ reload_stats (MMBaseBearer *self, typedef enum { CONNECT_STEP_FIRST, + CONNECT_STEP_LOAD_PROFILE_SETTINGS, CONNECT_STEP_PACKET_SERVICE, - CONNECT_STEP_PROVISIONED_CONTEXTS, CONNECT_STEP_SETUP_LINK, CONNECT_STEP_SETUP_LINK_MASTER_UP, CONNECT_STEP_CHECK_DISCONNECTED, @@ -209,12 +210,19 @@ typedef enum { typedef struct { MMPortMbim *mbim; - MMBearerProperties *properties; + MMBroadbandModemMbim *modem; ConnectStep step; MMPort *data; + MMBearerConnectResult *connect_result; + /* settings to use */ + gint profile_id; + gchar *apn; + MbimContextType context_type; + gchar *user; + gchar *password; + MbimAuthProtocol auth; MbimContextIpType requested_ip_type; MbimContextIpType activated_ip_type; - MMBearerConnectResult *connect_result; /* multiplex support */ guint session_id; gchar *link_prefix_hint; @@ -232,11 +240,15 @@ connect_context_free (ConnectContext *ctx) g_clear_object (&ctx->link); g_free (ctx->link_prefix_hint); + g_free (ctx->apn); + g_free (ctx->user); + g_free (ctx->password); + g_clear_pointer (&ctx->connect_result, (GDestroyNotify)mm_bearer_connect_result_unref); g_clear_object (&ctx->data); - g_object_unref (ctx->properties); g_object_unref (ctx->mbim); + g_object_unref (ctx->modem); g_slice_free (ConnectContext, ctx); } @@ -564,6 +576,9 @@ ip_configuration_query_ready (MbimDevice *device, ipv4_config, ipv6_config); mm_bearer_connect_result_set_multiplexed (ctx->connect_result, !!ctx->link); + + if (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) + mm_bearer_connect_result_set_profile_id (ctx->connect_result, ctx->profile_id); } if (error) { @@ -796,53 +811,6 @@ setup_link_ready (MMPortMbim *mbim, } static void -provisioned_contexts_query_ready (MbimDevice *device, - GAsyncResult *res, - GTask *task) -{ - MMBearerMbim *self; - ConnectContext *ctx; - g_autoptr(GError) error = NULL; - g_autoptr(MbimMessage) response = NULL; - guint32 provisioned_contexts_count; - g_autoptr(MbimProvisionedContextElementArray) provisioned_contexts = 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_provisioned_contexts_response_parse ( - response, - &provisioned_contexts_count, - &provisioned_contexts, - &error)) { - guint32 i; - - mm_obj_dbg (self, "provisioned contexts found (%u):", provisioned_contexts_count); - for (i = 0; i < provisioned_contexts_count; i++) { - MbimProvisionedContextElement *el = provisioned_contexts[i]; - g_autofree gchar *uuid_str = NULL; - - uuid_str = mbim_uuid_get_printable (&el->context_type); - mm_obj_dbg (self, "[%u] context type: %s", el->context_id, mbim_context_type_get_string (mbim_uuid_to_context_type (&el->context_type))); - mm_obj_dbg (self, " uuid: %s", uuid_str); - mm_obj_dbg (self, " access string: %s", el->access_string ? el->access_string : ""); - mm_obj_dbg (self, " username: %s", el->user_name ? el->user_name : ""); - mm_obj_dbg (self, " password: %s", el->password ? el->password : ""); - mm_obj_dbg (self, " compression: %s", mbim_compression_get_string (el->compression)); - mm_obj_dbg (self, " auth: %s", mbim_auth_protocol_get_string (el->auth_protocol)); - } - } else - mm_obj_dbg (self, "error listing provisioned contexts: %s", error->message); - - /* Keep on */ - ctx->step++; - connect_context_step (task); -} - -static void packet_service_set_ready (MbimDevice *device, GAsyncResult *res, GTask *task) @@ -913,6 +881,95 @@ packet_service_set_ready (MbimDevice *device, connect_context_step (task); } +static gboolean +load_settings_from_profile (MMBearerMbim *self, + ConnectContext *ctx, + MM3gppProfile *profile, + GError **error) +{ + MMBearerAllowedAuth bearer_auth; + MMBearerApnType apn_type; + GError *inner_error = NULL; + + /* APN settings */ + ctx->apn = g_strdup (mm_3gpp_profile_get_apn (profile)); + apn_type = mm_3gpp_profile_get_apn_type (profile); + if (apn_type == MM_BEARER_APN_TYPE_NONE) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "APN type in profile is not initialized"); + return FALSE; + } + ctx->context_type = mm_bearer_apn_type_to_mbim_context_type (apn_type, self, &inner_error); + if (inner_error) { + g_propagate_error (error, inner_error); + return FALSE; + } + + /* Auth settings */ + ctx->user = g_strdup (mm_3gpp_profile_get_user (profile)); + ctx->password = g_strdup (mm_3gpp_profile_get_password (profile)); + if (!ctx->user && !ctx->password) { + ctx->auth = MBIM_AUTH_PROTOCOL_NONE; + } else { + bearer_auth = mm_3gpp_profile_get_allowed_auth (profile); + ctx->auth = mm_bearer_allowed_auth_to_mbim_auth_protocol (bearer_auth, self, &inner_error); + if (inner_error) { + g_propagate_error (error, inner_error); + return FALSE; + } + } + + /* This IP type reading is applicable only when the profile comes + * from the input bearer properties, as there is no IP type stored + * in the device profiles. Therefore, only read it if it hasn't been + * read yet */ + if (ctx->requested_ip_type == MBIM_CONTEXT_IP_TYPE_DEFAULT) { + MMBearerIpFamily ip_type; + + ip_type = mm_3gpp_profile_get_ip_type (profile); + mm_3gpp_normalize_ip_family (&ip_type); + ctx->requested_ip_type = mm_bearer_ip_family_to_mbim_context_ip_type (ip_type, &inner_error); + if (inner_error) { + g_propagate_error (error, inner_error); + return FALSE; + } + } + + return TRUE; +} + +static void +get_profile_ready (MMIfaceModem3gppProfileManager *modem, + GAsyncResult *res, + GTask *task) +{ + MMBearerMbim *self; + ConnectContext *ctx; + GError *error = NULL; + g_autoptr(MM3gppProfile) profile = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + profile = mm_iface_modem_3gpp_profile_manager_get_profile_finish (modem, res, &error); + if (!profile) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (!load_settings_from_profile (self, ctx, profile, &error)) { + g_prefix_error (&error, "Couldn't load settings from profile: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* Keep on */ + ctx->step++; + connect_context_step (task); +} + static void connect_context_step (GTask *task) { @@ -934,6 +991,19 @@ connect_context_step (GTask *task) ctx->step++; /* Fall through */ + case CONNECT_STEP_LOAD_PROFILE_SETTINGS: + if (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) { + mm_obj_dbg (self, "loading connection settings from profile '%d'...", ctx->profile_id); + mm_iface_modem_3gpp_profile_manager_get_profile ( + MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (ctx->modem), + ctx->profile_id, + (GAsyncReadyCallback)get_profile_ready, + task); + return; + } + ctx->step++; + /* Fall through */ + case CONNECT_STEP_PACKET_SERVICE: mm_obj_dbg (self, "activating packet service..."); message = mbim_message_packet_service_set_new (MBIM_PACKET_SERVICE_ACTION_ATTACH, NULL); @@ -945,17 +1015,6 @@ connect_context_step (GTask *task) task); return; - case CONNECT_STEP_PROVISIONED_CONTEXTS: - mm_obj_dbg (self, "listing provisioned contexts..."); - message = mbim_message_provisioned_contexts_query_new (NULL); - mbim_device_command (mm_port_mbim_peek_device (ctx->mbim), - message, - 10, - NULL, - (GAsyncReadyCallback)provisioned_contexts_query_ready, - task); - return; - case CONNECT_STEP_SETUP_LINK: /* if a link prefix hint is available, it's because we should be doing * multiplexing */ @@ -1025,55 +1084,19 @@ connect_context_step (GTask *task) task); return; - case CONNECT_STEP_CONNECT: { - const gchar *apn; - const gchar *user; - const gchar *password; - MbimAuthProtocol auth; - MMBearerIpFamily ip_family; - GError *error = NULL; - - /* Setup parameters to use */ - - apn = mm_bearer_properties_get_apn (ctx->properties); - user = mm_bearer_properties_get_user (ctx->properties); - password = mm_bearer_properties_get_password (ctx->properties); - - if (!user && !password) { - auth = MBIM_AUTH_PROTOCOL_NONE; - } else { - MMBearerAllowedAuth bearer_auth; - - bearer_auth = mm_bearer_properties_get_allowed_auth (ctx->properties); - auth = mm_bearer_allowed_auth_to_mbim_auth_protocol (bearer_auth, self, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - } - - ip_family = mm_bearer_properties_get_ip_type (ctx->properties); - mm_3gpp_normalize_ip_family (&ip_family); - ctx->requested_ip_type = mm_bearer_ip_family_to_mbim_context_ip_type (ip_family, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - mm_obj_dbg (self, "launching %s connection with APN '%s' in session %u...", - mbim_context_ip_type_get_string (ctx->requested_ip_type), apn, ctx->session_id); + case CONNECT_STEP_CONNECT: + mm_obj_dbg (self, "launching %s connection in session %u...", + mbim_context_ip_type_get_string (ctx->requested_ip_type), ctx->session_id); message = mbim_message_connect_set_new ( ctx->session_id, MBIM_ACTIVATION_COMMAND_ACTIVATE, - apn ? apn : "", - user ? user : "", - password ? password : "", + ctx->apn ? ctx->apn : "", + ctx->user ? ctx->user : "", + ctx->password ? ctx->password : "", MBIM_COMPRESSION_NONE, - auth, + ctx->auth, ctx->requested_ip_type, - mbim_uuid_from_context_type (MBIM_CONTEXT_TYPE_INTERNET), + mbim_uuid_from_context_type (ctx->context_type), NULL); mbim_device_command (mm_port_mbim_peek_device (ctx->mbim), message, @@ -1082,7 +1105,6 @@ connect_context_step (GTask *task) (GAsyncReadyCallback)connect_set_ready, task); return; - } case CONNECT_STEP_IP_CONFIGURATION: mm_obj_dbg (self, "querying IP configuration..."); @@ -1143,74 +1165,113 @@ connect_context_step (GTask *task) g_assert_not_reached (); } +static gboolean +load_settings_from_bearer (MMBearerMbim *self, + ConnectContext *ctx, + MMBearerProperties *properties, + GError **error) +{ + MMBearerMultiplexSupport multiplex; + gboolean multiplex_supported = TRUE; + const gchar *data_port_driver; + + data_port_driver = mm_kernel_device_get_driver (mm_port_peek_kernel_device (ctx->data)); + if (!g_strcmp0 (data_port_driver, "mhi_net")) + multiplex_supported = FALSE; + + /* If no multiplex setting given by the user, assume requested */ + multiplex = mm_bearer_properties_get_multiplex (properties); + if (multiplex_supported && + (multiplex == MM_BEARER_MULTIPLEX_SUPPORT_UNKNOWN || + multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUESTED || + multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED)) { + /* the link prefix hint given must be modem-specific */ + ctx->link_prefix_hint = g_strdup_printf ("mbimmux%u.", mm_base_modem_get_dbus_id (MM_BASE_MODEM (ctx->modem))); + } + + if (!multiplex_supported && multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "Multiplexing required but not supported by %s", data_port_driver); + return FALSE; + } + + /* If profile id is given, we'll load all settings from the stored profile, + * so ignore any other setting received in the bearer properties */ + ctx->profile_id = mm_bearer_properties_get_profile_id (properties); + if (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) { + MMBearerIpFamily ip_type; + GError *inner_error = NULL; + + /* If we're loading settings from a profile, still read the ip-type + * from the user input, as that is not stored in the profile */ + ip_type = mm_bearer_properties_get_ip_type (properties); + mm_3gpp_normalize_ip_family (&ip_type); + ctx->requested_ip_type = mm_bearer_ip_family_to_mbim_context_ip_type (ip_type, &inner_error); + if (inner_error) { + g_propagate_error (error, inner_error); + return FALSE; + } + return TRUE; + } + + /* If not loading from a stored profile, initialize the + * APN type to 'internet' by default, which is what we've done + * until now. */ + if (mm_bearer_properties_get_apn_type (properties) == MM_BEARER_APN_TYPE_NONE) + mm_bearer_properties_set_apn_type (properties, MM_BEARER_APN_TYPE_DEFAULT); + + /* Use the implicit profile settings in the bearer properties */ + if (!load_settings_from_profile (self, ctx, mm_bearer_properties_peek_3gpp_profile (properties), error)) + return FALSE; + + /* Is this a 3GPP only modem and no APN or profile id was given? If so, error */ + if (mm_iface_modem_is_3gpp_only (MM_IFACE_MODEM (ctx->modem)) && !ctx->apn) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "3GPP connection logic requires APN or profile id setting"); + return FALSE; + } + + return TRUE; +} + static void _connect (MMBaseBearer *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { - ConnectContext *ctx; - MMPort *data; - MMPortMbim *mbim; - const gchar *apn; - GTask *task; - MMBearerMultiplexSupport multiplex; - g_autoptr(MMBaseModem) modem = NULL; - const gchar *data_port_driver; - gboolean multiplex_supported = TRUE; + ConnectContext *ctx; + MMPort *data; + MMPortMbim *mbim; + GTask *task; + GError *error = NULL; + g_autoptr(MMBaseModem) modem = NULL; + g_autoptr(MMBearerProperties) properties = NULL; if (!peek_ports (self, &mbim, &data, callback, user_data)) return; + task = g_task_new (self, cancellable, callback, user_data); + g_object_get (self, - MM_BASE_BEARER_MODEM, &modem, + MM_BASE_BEARER_MODEM, &modem, + MM_BASE_BEARER_CONFIG, &properties, NULL); g_assert (modem); - /* Check whether we have an APN */ - apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (self))); - - /* Is this a 3GPP only modem and no APN was given? If so, error */ - if (mm_iface_modem_is_3gpp_only (MM_IFACE_MODEM (modem)) && !apn) { - g_task_report_new_error ( - self, - callback, - user_data, - _connect, - MM_CORE_ERROR, - MM_CORE_ERROR_INVALID_ARGS, - "3GPP connection logic requires APN setting"); - return; - } - ctx = g_slice_new0 (ConnectContext); + ctx->modem = g_object_ref (modem); ctx->mbim = g_object_ref (mbim); ctx->data = g_object_ref (data); ctx->step = CONNECT_STEP_FIRST; ctx->requested_ip_type = MBIM_CONTEXT_IP_TYPE_DEFAULT; ctx->activated_ip_type = MBIM_CONTEXT_IP_TYPE_DEFAULT; + g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free); - g_object_get (self, - MM_BASE_BEARER_CONFIG, &ctx->properties, - NULL); - - data_port_driver = mm_kernel_device_get_driver (mm_port_peek_kernel_device (data)); - if (!g_strcmp0 (data_port_driver, "mhi_net")) - multiplex_supported = FALSE; - - multiplex = mm_bearer_properties_get_multiplex (ctx->properties); - - /* If no multiplex setting given by the user, assume requested */ - if (multiplex_supported && - (multiplex == MM_BEARER_MULTIPLEX_SUPPORT_UNKNOWN || - multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUESTED || - multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED)) { - /* the link prefix hint given must be modem-specific */ - ctx->link_prefix_hint = g_strdup_printf ("mbimmux%u.", mm_base_modem_get_dbus_id (MM_BASE_MODEM (modem))); - } - - if (!multiplex_supported && multiplex == MM_BEARER_MULTIPLEX_SUPPORT_REQUIRED) { - mm_obj_err (self, "Multiplexing required but not supported by %s", data_port_driver); + if (!load_settings_from_bearer (MM_BEARER_MBIM (self), ctx, properties, &error)) { + g_prefix_error (&error, "Invalid bearer properties: "); + g_task_return_error (task, error); + g_object_unref (task); return; } @@ -1219,9 +1280,6 @@ _connect (MMBaseBearer *self, mm_port_subsys_get_string (mm_port_get_subsys (data)), mm_port_get_device (data)); - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_task_data (task, ctx, (GDestroyNotify)connect_context_free); - /* Run! */ connect_context_step (task); } |