aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorSven Schwermer <sven.schwermer@disruptive-technologies.com>2022-08-08 11:40:46 +0200
committerAleksander Morgado <aleksandermj@chromium.org>2022-10-17 09:35:31 +0000
commitc509159dfeebffe3cb57284df831b0dba9bc1c60 (patch)
tree8c9c8dcd745421ed0dc3adf8c61ef3d9818cca35 /plugins
parent855977c4c7c1ead7dedd710671ca0359b277c417 (diff)
fibocom: Add initial EPS bearer support
Signed-off-by: Sven Schwermer <sven.schwermer@disruptive-technologies.com>
Diffstat (limited to 'plugins')
-rw-r--r--plugins/fibocom/mm-broadband-modem-fibocom.c393
1 files changed, 390 insertions, 3 deletions
diff --git a/plugins/fibocom/mm-broadband-modem-fibocom.c b/plugins/fibocom/mm-broadband-modem-fibocom.c
index 747d0769..201615d7 100644
--- a/plugins/fibocom/mm-broadband-modem-fibocom.c
+++ b/plugins/fibocom/mm-broadband-modem-fibocom.c
@@ -18,14 +18,18 @@
#include "mm-broadband-modem-fibocom.h"
#include "mm-broadband-bearer-fibocom-ecm.h"
#include "mm-broadband-modem.h"
-#include "mm-iface-modem.h"
#include "mm-base-modem-at.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-3gpp.h"
+#include "mm-iface-modem-3gpp-profile-manager.h"
#include "mm-log.h"
static void iface_modem_init (MMIfaceModem *iface);
+static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemFibocom, mm_broadband_modem_fibocom, MM_TYPE_BROADBAND_MODEM, 0,
- G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init))
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init))
typedef enum {
FEATURE_SUPPORT_UNKNOWN,
@@ -36,6 +40,8 @@ typedef enum {
struct _MMBroadbandModemFibocomPrivate {
FeatureSupport gtrndis_support;
GRegex *sim_ready_regex;
+ FeatureSupport initial_eps_bearer_support;
+ gint initial_eps_bearer_cid;
};
/*****************************************************************************/
@@ -214,6 +220,376 @@ modem_power_off (MMIfaceModem *self,
}
/*****************************************************************************/
+/* Load initial EPS bearer properties (as agreed with network) */
+
+static MMBearerProperties *
+modem_3gpp_load_initial_eps_bearer_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error));
+}
+
+static void
+load_initial_eps_cgcontrdp_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ const gchar *response;
+ g_autofree gchar *apn = NULL;
+ MMBearerProperties *properties;
+
+ response = mm_base_modem_at_command_finish (self, res, &error);
+ if (!response || !mm_3gpp_parse_cgcontrdp_response (response, NULL, NULL, &apn, NULL, NULL, NULL, NULL, NULL, &error))
+ g_task_return_error (task, error);
+ else {
+ properties = mm_bearer_properties_new ();
+ mm_bearer_properties_set_apn (properties, apn);
+ g_task_return_pointer (task, properties, g_object_unref);
+ }
+
+ g_object_unref (task);
+}
+
+static void
+modem_3gpp_load_initial_eps_bearer (MMIfaceModem3gpp *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
+ GTask *task;
+ g_autofree gchar *cmd = NULL;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (self->priv->initial_eps_bearer_support != FEATURE_SUPPORTED) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Initial EPS bearer context ID unknown");
+ g_object_unref (task);
+ return;
+ }
+
+ g_assert (self->priv->initial_eps_bearer_cid >= 0);
+ cmd = g_strdup_printf ("+CGCONTRDP=%d", self->priv->initial_eps_bearer_cid);
+
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ cmd,
+ 3,
+ FALSE,
+ (GAsyncReadyCallback) load_initial_eps_cgcontrdp_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Load initial EPS bearer settings (currently configured in modem) */
+
+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 *properties;
+
+ 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;
+ }
+
+ properties = mm_bearer_properties_new_from_profile (profile, &error);
+ if (!properties)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, properties, g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+modem_3gpp_load_initial_eps_bearer_settings (MMIfaceModem3gpp *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
+ MMPortSerialAt *port;
+ MMKernelDevice *device;
+ GTask *task;
+
+ /* Initial EPS bearer CID initialization run once only */
+ if (G_UNLIKELY (self->priv->initial_eps_bearer_support == FEATURE_SUPPORT_UNKNOWN)) {
+ /* There doesn't seem to be a programmatic way to find the initial EPS
+ * bearer's CID, so we'll use a udev variable. */
+ port = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
+ device = mm_port_peek_kernel_device (MM_PORT (port));
+ if (mm_kernel_device_has_global_property (device, "ID_MM_FIBOCOM_INITIAL_EPS_CID")) {
+ self->priv->initial_eps_bearer_support = FEATURE_SUPPORTED;
+ self->priv->initial_eps_bearer_cid = mm_kernel_device_get_global_property_as_int (
+ device, "ID_MM_FIBOCOM_INITIAL_EPS_CID");
+ }
+ else
+ self->priv->initial_eps_bearer_support = FEATURE_NOT_SUPPORTED;
+ }
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (self->priv->initial_eps_bearer_support != FEATURE_SUPPORTED) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Initial EPS bearer context ID unknown");
+ g_object_unref (task);
+ return;
+ }
+
+ g_assert (self->priv->initial_eps_bearer_cid >= 0);
+ 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);
+}
+
+/*****************************************************************************/
+/* Set initial EPS bearer settings */
+
+typedef enum {
+ SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE = 0,
+ SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_DOWN,
+ SET_INITIAL_EPS_BEARER_SETTINGS_STEP_MODIFY_PROFILE,
+ SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_UP,
+ SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FINISH,
+} SetInitialEpsStep;
+
+typedef struct {
+ MM3gppProfile *profile;
+ SetInitialEpsStep step;
+ MMModemPowerState power_state;
+} SetInitialEpsContext;
+
+static void
+set_initial_eps_context_free (SetInitialEpsContext *ctx)
+{
+ g_object_unref (ctx->profile);
+ g_slice_free (SetInitialEpsContext, ctx);
+}
+
+static gboolean
+modem_3gpp_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void set_initial_eps_step (GTask *task);
+
+static void
+set_initial_eps_bearer_power_up_ready (MMBaseModem *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
+ SetInitialEpsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish (MM_IFACE_MODEM (self), res, &error)) {
+ g_prefix_error (&error, "Couldn't power up modem: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->step++;
+ set_initial_eps_step (task);
+}
+
+static void
+set_initial_eps_bearer_modify_profile_ready (MMIfaceModem3gppProfileManager *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ SetInitialEpsContext *ctx;
+ g_autoptr(MM3gppProfile) stored = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ stored = mm_iface_modem_3gpp_profile_manager_set_profile_finish (self, res, &error);
+ if (!stored) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->step++;
+ set_initial_eps_step (task);
+}
+
+static void
+set_initial_eps_bearer_power_down_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ SetInitialEpsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ if (!MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish (MM_IFACE_MODEM (self), res, &error)) {
+ g_prefix_error (&error, "Couldn't power down modem: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->step++;
+ set_initial_eps_step (task);
+}
+
+static void
+set_initial_eps_bearer_load_power_state_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ SetInitialEpsContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+
+ ctx->power_state = MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish (MM_IFACE_MODEM (self), res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ ctx->step++;
+ set_initial_eps_step (task);
+}
+
+static void
+set_initial_eps_step (GTask *task)
+{
+ MMBroadbandModemFibocom *self;
+ SetInitialEpsContext *ctx;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ switch (ctx->step) {
+ case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE:
+ mm_obj_dbg (self, "querying current power state...");
+ g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state);
+ g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state_finish);
+ MM_IFACE_MODEM_GET_INTERFACE (self)->load_power_state (
+ MM_IFACE_MODEM (self),
+ (GAsyncReadyCallback) set_initial_eps_bearer_load_power_state_ready,
+ task);
+ return;
+
+ case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_DOWN:
+ if (ctx->power_state == MM_MODEM_POWER_STATE_ON) {
+ mm_obj_dbg (self, "powering down before changing initial EPS bearer settings...");
+ g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down);
+ g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down_finish);
+ MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_down (
+ MM_IFACE_MODEM (self),
+ (GAsyncReadyCallback) set_initial_eps_bearer_power_down_ready,
+ task);
+ return;
+ }
+ ctx->step++;
+ /* fall through */
+
+ case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_MODIFY_PROFILE:
+ mm_obj_dbg (self, "modifying initial EPS bearer settings profile...");
+ mm_iface_modem_3gpp_profile_manager_set_profile (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self),
+ ctx->profile,
+ "profile-id",
+ TRUE,
+ (GAsyncReadyCallback) set_initial_eps_bearer_modify_profile_ready,
+ task);
+ return;
+
+ case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_POWER_UP:
+ if (ctx->power_state == MM_MODEM_POWER_STATE_ON) {
+ mm_obj_dbg (self, "powering up after changing initial EPS bearer settings...");
+ g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up);
+ g_assert (MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up_finish);
+ MM_IFACE_MODEM_GET_INTERFACE (self)->modem_power_up (
+ MM_IFACE_MODEM (self),
+ (GAsyncReadyCallback) set_initial_eps_bearer_power_up_ready,
+ task);
+ return;
+ }
+ ctx->step++;
+ /* fall through */
+
+ case SET_INITIAL_EPS_BEARER_SETTINGS_STEP_FINISH:
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+ return;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+modem_3gpp_set_initial_eps_bearer_settings (MMIfaceModem3gpp *_self,
+ MMBearerProperties *properties,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemFibocom *self = MM_BROADBAND_MODEM_FIBOCOM (_self);
+ GTask *task;
+ MM3gppProfile *profile;
+ MMBearerIpFamily ip_family;
+ SetInitialEpsContext *ctx;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ if (self->priv->initial_eps_bearer_support != FEATURE_SUPPORTED) {
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Initial EPS bearer context ID unknown");
+ g_object_unref (task);
+ return;
+ }
+
+ profile = mm_bearer_properties_peek_3gpp_profile (properties);
+ g_assert (self->priv->initial_eps_bearer_cid >= 0);
+ mm_3gpp_profile_set_profile_id (profile, self->priv->initial_eps_bearer_cid);
+ ip_family = mm_3gpp_profile_get_ip_type (profile);
+ if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY)
+ mm_3gpp_profile_set_ip_type (profile, MM_BEARER_IP_FAMILY_IPV4);
+
+ /* Setup context */
+ ctx = g_slice_new0 (SetInitialEpsContext);
+ ctx->profile = g_object_ref (profile);
+ ctx->step = SET_INITIAL_EPS_BEARER_SETTINGS_STEP_LOAD_POWER_STATE;
+ g_task_set_task_data (task, ctx, (GDestroyNotify) set_initial_eps_context_free);
+
+ set_initial_eps_step (task);
+}
+
+/*****************************************************************************/
static void
setup_ports (MMBroadbandModem *_self)
@@ -266,9 +642,9 @@ mm_broadband_modem_fibocom_init (MMBroadbandModemFibocom *self)
MMBroadbandModemFibocomPrivate);
self->priv->gtrndis_support = FEATURE_SUPPORT_UNKNOWN;
-
self->priv->sim_ready_regex = g_regex_new ("\\r\\n\\+SIM READY\\r\\n",
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
+ self->priv->initial_eps_bearer_support = FEATURE_SUPPORT_UNKNOWN;
}
static void
@@ -295,6 +671,17 @@ iface_modem_init (MMIfaceModem *iface)
}
static void
+iface_modem_3gpp_init (MMIfaceModem3gpp *iface)
+{
+ iface->load_initial_eps_bearer = modem_3gpp_load_initial_eps_bearer;
+ iface->load_initial_eps_bearer_finish = modem_3gpp_load_initial_eps_bearer_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;
+ iface->set_initial_eps_bearer_settings = modem_3gpp_set_initial_eps_bearer_settings;
+ iface->set_initial_eps_bearer_settings_finish = modem_3gpp_set_initial_eps_bearer_settings_finish;
+}
+
+static void
mm_broadband_modem_fibocom_class_init (MMBroadbandModemFibocomClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);