diff options
author | Aleksander Morgado <aleksandermj@chromium.org> | 2024-05-08 09:54:37 +0000 |
---|---|---|
committer | Aleksander Morgado <aleksandermj@chromium.org> | 2024-05-29 09:05:04 +0000 |
commit | 97cab9f37e0ce9229bad9d75d7df83d9e3bf6620 (patch) | |
tree | 2e0d839de79ebd419fd44f1721494103fdfb659e /src | |
parent | 50755b07d3d5e5c49337fcec7b1ee2fede3d428c (diff) |
broadband-modem: implement loading initial EPS bearer settings
The main issue here is how to select the id of the context that is
used for attach in the modem.
We will assume that the lowest cid value for the IP range returned in
the CGDCONT=? test is the one used for the attach context. This
assumption works with modems following the 3GPP specs (with cid=0) and
also in Qualcomm based modems (with cid=1).
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem.c | 135 | ||||
-rw-r--r-- | src/mm-iface-modem-3gpp-profile-manager.c | 6 |
2 files changed, 141 insertions, 0 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 41906c2e..291978ef 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -209,6 +209,8 @@ struct _MMBroadbandModemPrivate { MMModem3gppFacility modem_3gpp_ignored_facility_locks; MMBaseBearer *modem_3gpp_initial_eps_bearer; MMModem3gppPacketServiceState modem_3gpp_packet_service_state; + gboolean initial_eps_bearer_cid_support_checked; + gint initial_eps_bearer_cid; /*<--- Modem 3GPP Profile Manager interface --->*/ /* Properties */ @@ -2918,6 +2920,136 @@ modem_load_access_technologies (MMIfaceModem *self, } /*****************************************************************************/ +/* Load initial EPS bearer settings currently configured in modem (3GPP interface) */ + +static MMBearerProperties * +modem_3gpp_load_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self, + GAsyncResult *res, + GError **error) +{ + return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error)); +} + +static void +load_initial_eps_bearer_get_profile_ready (MMIfaceModem3gppProfileManager *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + g_autoptr(MM3gppProfile) profile = NULL; + MMBearerProperties *props; + + profile = mm_iface_modem_3gpp_profile_manager_get_profile_finish (self, res, &error); + if (!profile) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + props = mm_bearer_properties_new_from_profile (profile, &error); + if (!props) + g_task_return_error (task, error); + else + g_task_return_pointer (task, props, g_object_unref); + g_object_unref (task); +} + +static void +load_initial_eps_bearer_profile (GTask *task) +{ + MMBroadbandModem *self; + + self = g_task_get_source_object (task); + g_assert (self->priv->initial_eps_bearer_cid_support_checked); + + if (self->priv->initial_eps_bearer_cid < 0) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, + "initial EPS bearer context management unsupported"); + g_object_unref (task); + return; + } + + /* Note that we may be calling this before initializing the 3GPP profile manager interface, + * but it should not be an issue, because the interface initialization exclusively checks + * for the feature support and takes care of creating the DBus skeleton. There is currently + * no explicit state initialized that is required for operations later on. Ideally, though, + * an interface method should not be used unless it is initialized, but in this case it's + * problematic because the profile manager interface is initialized always *after* the 3GPP + * interface. */ + mm_iface_modem_3gpp_profile_manager_get_profile ( + MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self), + self->priv->initial_eps_bearer_cid, + (GAsyncReadyCallback) load_initial_eps_bearer_get_profile_ready, + task); +} + +static void +initial_eps_bearer_cid_cgdcont_test_ready (MMBaseModem *_self, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModem *self = MM_BROADBAND_MODEM (_self); + const gchar *response; + g_autoptr(GError) error = NULL; + + g_assert (self->priv->initial_eps_bearer_cid < 0); + + response = mm_base_modem_at_command_full_finish (_self, res, &error); + if (!response) + mm_obj_dbg (self, "failed +CGDCONT format check : %s", error->message); + else { + GList *format_list; + guint min_cid; + + format_list = mm_3gpp_parse_cgdcont_test_response (response, self, &error); + if (error) + mm_obj_dbg (self, "error parsing +CGDCONT test response: %s", error->message); + else if (!mm_3gpp_pdp_context_format_list_find_range (format_list, MM_BEARER_IP_FAMILY_IPV4, &min_cid, NULL)) { + /* We check for IPv4 following the assumption that modems will generally support v4, while + * v6 is considered optional. If we ever find a modem supporting v6 exclusively and not v4 + * we would need to update this logic to also check for v6. */ + mm_obj_dbg (self, "context format check for IP not found"); + } else { + mm_obj_dbg (self, "initial EPS bearer context cid found: %u", min_cid); + self->priv->initial_eps_bearer_cid = (gint) min_cid; + } + mm_3gpp_pdp_context_format_list_free (format_list); + } + + load_initial_eps_bearer_profile (task); +} + +static void +modem_3gpp_load_initial_eps_bearer_settings (MMIfaceModem3gpp *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModem *self = MM_BROADBAND_MODEM (_self); + GTask *task; + + task = g_task_new (self, NULL, callback, user_data); + + /* Lookup which is supposed to be the initial EPS bearer context cid. + * - As per 3GPP specs, it should be cid=0 + * - Qualcomm based modems default this to cid=1 + */ + if (G_UNLIKELY (!self->priv->initial_eps_bearer_cid_support_checked)) { + self->priv->initial_eps_bearer_cid_support_checked = TRUE; + g_assert (self->priv->initial_eps_bearer_cid < 0); + mm_obj_dbg (self, "looking for the initial EPS bearer context cid,,,"); + mm_base_modem_at_command (MM_BASE_MODEM (self), + "+CGDCONT=?", + 3, + TRUE, /* cached */ + (GAsyncReadyCallback)initial_eps_bearer_cid_cgdcont_test_ready, + task); + return; + } + + load_initial_eps_bearer_profile (task); +} + +/*****************************************************************************/ /* Setup/Cleanup unsolicited events (3GPP interface) */ static gboolean @@ -13372,6 +13504,7 @@ mm_broadband_modem_init (MMBroadbandModem *self) self->priv->modem_cmer_disable_mode = MM_3GPP_CMER_MODE_NONE; self->priv->modem_cmer_ind = MM_3GPP_CMER_IND_NONE; self->priv->flow_control = MM_FLOW_CONTROL_NONE; + self->priv->initial_eps_bearer_cid = -1; } static void @@ -13543,6 +13676,8 @@ iface_modem_3gpp_init (MMIfaceModem3gppInterface *iface) iface->load_enabled_facility_locks_finish = modem_3gpp_load_enabled_facility_locks_finish; iface->load_eps_ue_mode_operation = modem_3gpp_load_eps_ue_mode_operation; iface->load_eps_ue_mode_operation_finish = modem_3gpp_load_eps_ue_mode_operation_finish; + iface->load_initial_eps_bearer_settings = modem_3gpp_load_initial_eps_bearer_settings; + iface->load_initial_eps_bearer_settings_finish = modem_3gpp_load_initial_eps_bearer_settings_finish; /* Enabling steps */ iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events; diff --git a/src/mm-iface-modem-3gpp-profile-manager.c b/src/mm-iface-modem-3gpp-profile-manager.c index 45a12bb0..01d3c791 100644 --- a/src/mm-iface-modem-3gpp-profile-manager.c +++ b/src/mm-iface-modem-3gpp-profile-manager.c @@ -878,6 +878,9 @@ mm_iface_modem_3gpp_profile_manager_set_profile (MMIfaceModem3gppProfileManager } /*****************************************************************************/ +/* Get a single profile. + * NOTE: this method may be called before the interface is initialized. + */ MM3gppProfile * mm_iface_modem_3gpp_profile_manager_get_profile_finish (MMIfaceModem3gppProfileManager *self, @@ -963,6 +966,9 @@ mm_iface_modem_3gpp_profile_manager_get_profile (MMIfaceModem3gppProfileManager } /*****************************************************************************/ +/* List all profiles. + * NOTE: this method may be called before the interface is initialized. + */ typedef struct { GList *profiles; |