diff options
-rw-r--r-- | plugins/cinterion/mm-broadband-bearer-cinterion.c | 37 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-bearer-cinterion.h | 7 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-cinterion.c | 563 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.c | 52 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.h | 9 | ||||
-rw-r--r-- | plugins/cinterion/tests/test-modem-helpers-cinterion.c | 66 |
6 files changed, 722 insertions, 12 deletions
diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.c b/plugins/cinterion/mm-broadband-bearer-cinterion.c index 3ee8623d..ceeb49be 100644 --- a/plugins/cinterion/mm-broadband-bearer-cinterion.c +++ b/plugins/cinterion/mm-broadband-bearer-cinterion.c @@ -197,15 +197,30 @@ parse_auth_type (MMBearerAllowedAuth mm_auth) } } +MMBearerAllowedAuth +mm_auth_type_from_cinterion_auth_type (guint cinterion_auth) +{ + switch (cinterion_auth) { + case BEARER_CINTERION_AUTH_NONE: + return MM_BEARER_ALLOWED_AUTH_NONE; + case BEARER_CINTERION_AUTH_PAP: + return MM_BEARER_ALLOWED_AUTH_PAP; + case BEARER_CINTERION_AUTH_CHAP: + return MM_BEARER_ALLOWED_AUTH_CHAP; + default: + return MM_BEARER_ALLOWED_AUTH_UNKNOWN; + } +} + /* Cinterion authentication is done with the command AT^SGAUTH, whose syntax depends on the modem family, as follow: - AT^SGAUTH=<cid>[, <auth_type>[, <user>, <passwd>]] for the IMT family - AT^SGAUTH=<cid>[, <auth_type>[, <passwd>, <user>]] for the rest */ -static gchar * -build_auth_string (MMBroadbandBearerCinterion *self, - MMCinterionModemFamily modem_family, - MMBearerProperties *config, - guint cid) +gchar * +mm_broadband_bearer_cinterion_build_auth_string (gpointer log_object, + MMCinterionModemFamily modem_family, + MMBearerProperties *config, + guint cid) { MMBearerAllowedAuth auth; BearerCinterionAuthType encoded_auth = BEARER_CINTERION_AUTH_UNKNOWN; @@ -227,7 +242,7 @@ build_auth_string (MMBroadbandBearerCinterion *self, /* When 'none' requested, we won't require user/password */ if (encoded_auth == BEARER_CINTERION_AUTH_NONE) { if (has_user || has_passwd) - mm_obj_warn (self, "APN user/password given but 'none' authentication requested"); + mm_obj_warn (log_object, "APN user/password given but 'none' authentication requested"); if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) return g_strdup_printf ("^SGAUTH=%u,%d,\"\",\"\"", cid, encoded_auth); return g_strdup_printf ("^SGAUTH=%u,%d", cid, encoded_auth); @@ -240,7 +255,7 @@ build_auth_string (MMBroadbandBearerCinterion *self, return NULL; /* If user/passwd given, default to CHAP (more common than PAP) */ - mm_obj_dbg (self, "APN user/password given but no authentication type explicitly requested: defaulting to 'CHAP'"); + mm_obj_dbg (log_object, "APN user/password given but no authentication type explicitly requested: defaulting to 'CHAP'"); encoded_auth = BEARER_CINTERION_AUTH_CHAP; } @@ -422,10 +437,10 @@ dial_3gpp_context_step (GTask *task) case DIAL_3GPP_CONTEXT_STEP_AUTH: { gchar *command; - command = build_auth_string (self, - mm_broadband_modem_cinterion_get_family (MM_BROADBAND_MODEM_CINTERION (ctx->modem)), - mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)), - ctx->cid); + command = mm_broadband_bearer_cinterion_build_auth_string (self, + mm_broadband_modem_cinterion_get_family (MM_BROADBAND_MODEM_CINTERION (ctx->modem)), + mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)), + ctx->cid); if (command) { mm_obj_dbg (self, "dial step %u/%u: authenticating...", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST); diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.h b/plugins/cinterion/mm-broadband-bearer-cinterion.h index d514759d..d63e5b70 100644 --- a/plugins/cinterion/mm-broadband-bearer-cinterion.h +++ b/plugins/cinterion/mm-broadband-bearer-cinterion.h @@ -51,4 +51,11 @@ void mm_broadband_bearer_cinterion_new (MMBroadbandModemCinterio MMBaseBearer *mm_broadband_bearer_cinterion_new_finish (GAsyncResult *res, GError **error); +gchar *mm_broadband_bearer_cinterion_build_auth_string (gpointer log_object, + MMCinterionModemFamily modem_family, + MMBearerProperties *config, + guint cid); + +MMBearerAllowedAuth mm_auth_type_from_cinterion_auth_type (guint cinterion_auth); + #endif /* MM_BROADBAND_BEARER_CINTERION_H */ diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c index 412339ab..95b9ed0d 100644 --- a/plugins/cinterion/mm-broadband-modem-cinterion.c +++ b/plugins/cinterion/mm-broadband-modem-cinterion.c @@ -971,6 +971,559 @@ modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self, task); } +typedef enum { + INITIAL_EPS_CONTEXT_STEP_FIRST = 0, + INITIAL_EPS_CONTEXT_STEP_CHECK_MODE, + INITIAL_EPS_CONTEXT_STEP_RF_OFF, + INITIAL_EPS_CONTEXT_STEP_PROFILE, + INITIAL_EPS_CONTEXT_STEP_APN, + INITIAL_EPS_CONTEXT_STEP_AUTH, + INITIAL_EPS_CONTEXT_STEP_RF_ON, + INITIAL_EPS_CONTEXT_STEP_LAST, +} InitialEpsStep; + +typedef struct { + MMBearerProperties *properties; + InitialEpsStep step; + guint cid; + guint initial_cfun_mode; + GError *error; + void (*step_function) (GTask *task); + gboolean get_current_status; +} InitialEpsContext; + +static void +initial_eps_context_free (InitialEpsContext *ctx) +{ + g_object_unref (ctx->properties); + g_slice_free (InitialEpsContext, ctx); +} + +/*****************************************************************************/ +/* Set initial EPS bearer settings */ + +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 +initial_eps_common_cmd_check (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + InitialEpsContext *ctx; + + ctx = (InitialEpsContext *) g_task_get_task_data (task); + + mm_base_modem_at_command_finish (self, res, &error); + + if (error) { + mm_obj_warn (self, "%s", error->message); + /* do not overwrite original error */ + if (!ctx->error) + ctx->error = error; + else + g_error_free (error); + } + + /* Go to next step */ + ctx->step++; + ctx->step_function (task); +} + +static void +set_cid_from_mno_profile (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + const gchar *response; + InitialEpsContext *ctx; + + ctx = (InitialEpsContext *) g_task_get_task_data (task); + response = mm_base_modem_at_command_finish (self, res, NULL); + /* in case of error, it means that the MNO profiles are not supported + * and therefore that the default CID=1 is ok. */ + if (response != NULL) + mm_cinterion_provcfg_response_to_cid (response, + MM_BROADBAND_MODEM_CINTERION (self)->priv->modem_family, + mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), + self, + &ctx->cid); + + /* Go to next step */ + ctx->step++; + ctx->step_function (task); +} + +static void +check_cfun_mode (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + const gchar *response; + g_autoptr(GRegex) r = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + InitialEpsContext *ctx; + guint mode; + + ctx = (InitialEpsContext *) g_task_get_task_data (task); + response = mm_base_modem_at_command_finish (self, res, &error); + /* in case of error, abort - something wrong with the modem */ + if (error) + goto error; + + r = g_regex_new ("\\+CFUN:\\s*(\\d+)", 0, 0, NULL); + g_assert (r != NULL); + g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL); + if (!g_match_info_matches (match_info)) { + error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "unmatched CFUN response: %s", response); + goto error; + } + + if (!mm_get_uint_from_match_info (match_info, 1, &mode)) { + error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "couldn't retrieve current mode from CFUN? response: %s", response); + goto error; + } + + mm_obj_dbg (self, "current cfun mode: %u", mode); + + if (mode != 1 && mode != 4) { + error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "cannot setup the default LTE bearer at this time: the SIM must be powered"); + goto error; + } + + ctx->initial_cfun_mode = mode; + ctx->step++; + ctx->step_function (task); + return; + +error: + mm_obj_warn (self, "%s", error->message); + g_task_return_error (task, error); + g_object_unref (task); +} + +static void +modem_3gpp_set_initial_eps_bearer_settings_step (GTask *task) +{ + MMIfaceModem3gpp *self; + InitialEpsContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + /* in case of error, skip all steps and restore radio if needed */ + if (ctx->error && ctx->step < INITIAL_EPS_CONTEXT_STEP_RF_ON) + ctx->step = INITIAL_EPS_CONTEXT_STEP_RF_ON; + + switch (ctx->step) { + case INITIAL_EPS_CONTEXT_STEP_FIRST: + /* set defaults */ + ctx->cid = 1; + ctx->step++; + /* fall through */ + + case INITIAL_EPS_CONTEXT_STEP_CHECK_MODE: + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "+CFUN?", + 5, + FALSE, + (GAsyncReadyCallback)check_cfun_mode, + task); + return; + + case INITIAL_EPS_CONTEXT_STEP_RF_OFF: + if (ctx->initial_cfun_mode != 4) { + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "+CFUN=4", + 5, + FALSE, + (GAsyncReadyCallback)initial_eps_common_cmd_check, + task); + return; + } + ctx->step++; + /* fall through */ + + case INITIAL_EPS_CONTEXT_STEP_PROFILE: + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "^SCFG=\"MEopMode/Prov/Cfg\"", + 20, + FALSE, + (GAsyncReadyCallback)set_cid_from_mno_profile, + task); + return; + + case INITIAL_EPS_CONTEXT_STEP_APN: { + const gchar *apn; + g_autofree gchar *quoted_apn = NULL; + g_autofree gchar *apn_cmd = NULL; + const gchar *ip_family_str; + MMBearerIpFamily ip_family; + + ip_family = mm_bearer_properties_get_ip_type (ctx->properties); + if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY) + ip_family = MM_BEARER_IP_FAMILY_IPV4; + + if (ip_family != MM_BEARER_IP_FAMILY_IPV4) { + /* we must have the same settings as in dial_3gpp_context_step() + * for the case when the CID is re-used for the connection PDN */ + mm_obj_dbg (self, "Only IPv4 is supported by this modem"); + ip_family = MM_BEARER_IP_FAMILY_IPV4; + } + + ip_family_str = mm_3gpp_get_pdp_type_from_ip_family (ip_family); + apn = mm_bearer_properties_get_apn (ctx->properties); + mm_obj_dbg (self, "context CID=%d with APN '%s' and PDP type '%s'", ctx->cid, apn, ip_family_str); + quoted_apn = mm_port_serial_at_quote_string (apn); + apn_cmd = g_strdup_printf ("+CGDCONT=%u,\"%s\",%s", ctx->cid, ip_family_str, quoted_apn); + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + apn_cmd, + 20, + FALSE, + (GAsyncReadyCallback)initial_eps_common_cmd_check, + task); + return; + } + + case INITIAL_EPS_CONTEXT_STEP_AUTH: { + g_autofree gchar *auth_cmd = NULL; + + auth_cmd = mm_broadband_bearer_cinterion_build_auth_string (self, + MM_BROADBAND_MODEM_CINTERION (self)->priv->modem_family, + ctx->properties, + ctx->cid); + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + auth_cmd, + 20, + FALSE, + (GAsyncReadyCallback)initial_eps_common_cmd_check, + task); + return; + } + + case INITIAL_EPS_CONTEXT_STEP_RF_ON: + if (ctx->initial_cfun_mode == 1) { + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "+CFUN=1", + 5, + FALSE, + (GAsyncReadyCallback)initial_eps_common_cmd_check, + task); + return; + } + ctx->step++; + /* fall through */ + + case INITIAL_EPS_CONTEXT_STEP_LAST: + if (ctx->error) + g_task_return_error (task, ctx->error); + else + 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) +{ + GTask *task; + InitialEpsContext *ctx; + + task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (InitialEpsContext); + g_task_set_task_data (task, ctx, (GDestroyNotify) initial_eps_context_free); + + /* Setup context */ + ctx->properties = g_object_ref (properties); + ctx->step = INITIAL_EPS_CONTEXT_STEP_FIRST; + ctx->step_function = modem_3gpp_set_initial_eps_bearer_settings_step; + + modem_3gpp_set_initial_eps_bearer_settings_step (task); +} + +/*****************************************************************************/ +/* Initial EPS bearer info loading -> current dynamic configuration */ + +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 +get_apn_from_cgdcont (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + const gchar *response; + InitialEpsContext *ctx; + GList *context_list; + GList *l; + + ctx = (InitialEpsContext *) g_task_get_task_data (task); + response = mm_base_modem_at_command_finish (self, res, NULL); + /* in case of error, skip */ + if (!response) + goto end; + + context_list = mm_3gpp_parse_cgdcont_read_response (response, NULL); + if (!context_list) + goto end; + + for (l = context_list; l; l = g_list_next (l)) { + MM3gppPdpContext *pdp = l->data; + + if (pdp->cid == ctx->cid) { + mm_bearer_properties_set_ip_type (ctx->properties, pdp->pdp_type); + mm_bearer_properties_set_apn (ctx->properties, pdp->apn ? pdp->apn : ""); + } + } + mm_3gpp_pdp_context_list_free (context_list); + +end: + /* Go to next step */ + ctx->step++; + ctx->step_function (task); +} + +static void +get_apn_from_cgcontrdp (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + const gchar *response; + InitialEpsContext *ctx; + gchar *apn = NULL; + + ctx = (InitialEpsContext *) g_task_get_task_data (task); + response = mm_base_modem_at_command_finish (self, res, NULL); + /* in case of error, skip */ + mm_obj_dbg (self, "response: %s", response); + if (response && mm_3gpp_parse_cgcontrdp_response (response, NULL, NULL, &apn, NULL, NULL, NULL, NULL, NULL, NULL)) { + mm_bearer_properties_set_apn (ctx->properties, apn); + g_free (apn); + } + + /* Go to next step */ + ctx->step++; + ctx->step_function (task); +} + +/* at^sgauth? + * ^SGAUTH: 1,2,"vf" + * ^SGAUTH: 3,0,"" + * ^SGAUTH: 4,0 + * + * OK + */ +static void +get_auth_params (MMBaseModem *self, + GAsyncResult *res, + GTask *task) +{ + const gchar *response; + InitialEpsContext *ctx; + g_autoptr(GRegex) r = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + + ctx = (InitialEpsContext *) g_task_get_task_data (task); + response = mm_base_modem_at_command_finish (self, res, NULL); + + /* in case of error, skip */ + if (response != NULL) + mm_obj_dbg (self, "response: %s", response); + + r = g_regex_new ("\\^SGAUTH:\\s*(\\d+),(\\d+),?\"?([a-zA-Z0-9_-]+)?\"?", 0, 0, NULL); + g_assert (r != NULL); + g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL); + while (g_match_info_matches (match_info)) { + guint cid = 0; + guint cinterion_auth_type = 0; + g_autofree gchar *username = NULL; + + mm_get_uint_from_match_info (match_info, 1, &cid); + mm_get_uint_from_match_info (match_info, 2, &cinterion_auth_type); + username = mm_get_string_unquoted_from_match_info (match_info, 3); + if (cid == ctx->cid) { + mm_bearer_properties_set_allowed_auth (ctx->properties, mm_auth_type_from_cinterion_auth_type (cinterion_auth_type)); + if (username) + mm_bearer_properties_set_user (ctx->properties, username); + } + g_match_info_next (match_info, NULL); + } + + /* Go to next step */ + ctx->step++; + ctx->step_function (task); +} + +static void +modem_3gpp_load_initial_eps_step (GTask *task) +{ + MMIfaceModem3gpp *self; + InitialEpsContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case INITIAL_EPS_CONTEXT_STEP_FIRST: + /* set defaults */ + ctx->cid = 1; + ctx->step++; + /* fall through */ + + case INITIAL_EPS_CONTEXT_STEP_CHECK_MODE: + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "+CFUN?", + 5, + FALSE, + (GAsyncReadyCallback)check_cfun_mode, + task); + return; + + case INITIAL_EPS_CONTEXT_STEP_RF_OFF: + ctx->step++; + /* fall through */ + + case INITIAL_EPS_CONTEXT_STEP_PROFILE: + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "^SCFG=\"MEopMode/Prov/Cfg\"", + 20, + FALSE, + (GAsyncReadyCallback)set_cid_from_mno_profile, + task); + return; + + case INITIAL_EPS_CONTEXT_STEP_APN: { + if (ctx->get_current_status) + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "+CGDCONT?", + 20, + FALSE, + (GAsyncReadyCallback)get_apn_from_cgdcont, + task); + else { + g_autofree gchar *cmd = NULL; + + cmd = g_strdup_printf ("+CGCONTRDP=%u", ctx->cid); + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "+CGCONTRDP", + 20, + FALSE, + (GAsyncReadyCallback)get_apn_from_cgcontrdp, + task); + } + return; + } + + case INITIAL_EPS_CONTEXT_STEP_AUTH: { + mm_base_modem_at_command ( + MM_BASE_MODEM (self), + "^SGAUTH?", + 20, + FALSE, + (GAsyncReadyCallback)get_auth_params, + task); + return; + } + + case INITIAL_EPS_CONTEXT_STEP_RF_ON: + ctx->step++; + /* fall through */ + + case INITIAL_EPS_CONTEXT_STEP_LAST: + g_task_return_pointer (task, ctx->properties, g_object_unref); + g_object_unref (task); + return; + default: + g_assert_not_reached (); + } +} + +static void +modem_3gpp_load_initial_eps_bearer (MMIfaceModem3gpp *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + InitialEpsContext *ctx; + MMBearerProperties *properties; + + task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (InitialEpsContext); + g_task_set_task_data (task, ctx, (GDestroyNotify) initial_eps_context_free); + properties = mm_bearer_properties_new (); + + /* Setup context */ + ctx->properties = g_object_ref (properties); + ctx->step = INITIAL_EPS_CONTEXT_STEP_FIRST; + ctx->step_function = modem_3gpp_load_initial_eps_step; + ctx-> get_current_status = TRUE; + + modem_3gpp_load_initial_eps_step (task); +} + +/*****************************************************************************/ +/* Initial EPS bearer settings loading -> set configuration */ + +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 +modem_3gpp_load_initial_eps_bearer_settings (MMIfaceModem3gpp *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + InitialEpsContext *ctx; + MMBearerProperties *properties; + + task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (InitialEpsContext); + g_task_set_task_data (task, ctx, (GDestroyNotify) initial_eps_context_free); + properties = mm_bearer_properties_new (); + + /* Setup context */ + ctx->properties = g_object_ref (properties); + ctx->step = INITIAL_EPS_CONTEXT_STEP_FIRST; + ctx->step_function = modem_3gpp_load_initial_eps_step; + ctx-> get_current_status = FALSE; + + modem_3gpp_load_initial_eps_step (task); +} + /*****************************************************************************/ /* Load supported modes (Modem interface) */ @@ -1319,7 +1872,7 @@ scfg_set_ready_sequence (MMBaseModem *_self, self = g_task_get_source_object (task); for (i = 0; self->priv->cmds[i].command; i++) mm_base_modem_at_command_alloc_clear (&self->priv->cmds[i]); - g_free(self->priv->cmds); + g_free (self->priv->cmds); self->priv->cmds = NULL; mm_base_modem_at_sequence_finish (_self, res, &ctx, &error); @@ -2031,6 +2584,14 @@ iface_modem_3gpp_init (MMIfaceModem3gpp *iface) iface->setup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish; iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events; iface->cleanup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish; + + 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 diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c index 095e396c..bff03a90 100644 --- a/plugins/cinterion/mm-modem-helpers-cinterion.c +++ b/plugins/cinterion/mm-modem-helpers-cinterion.c @@ -1398,3 +1398,55 @@ mm_cinterion_smoni_response_to_signal_info (const gchar *response, return TRUE; } + +/*****************************************************************************/ +/* provider cfg information to CID number for EPS initial settings */ + +/* + * at^scfg="MEopMode/Prov/Cfg" + * ^SCFG: "MEopMode/Prov/Cfg","vdfde" + * ^SCFG: "MEopMode/Prov/Cfg","attus" + * ^SCFG: "MEopMode/Prov/Cfg","2" -> PLS8-X vzw + * ^SCFG: "MEopMode/Prov/Cfg","vzwdcus" -> PLAS9-x vzw + * ^SCFG: "MEopMode/Prov/Cfg","tmode" -> t-mob germany + * OK + */ +void +mm_cinterion_provcfg_response_to_cid (const gchar *response, + MMCinterionModemFamily modem_family, + MMModemCharset charset, + gpointer log_object, + guint *cid) +{ + g_autoptr(GRegex) r = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + g_autofree GError *inner_error = NULL; + + r = g_regex_new ("\\^SCFG:\\s*\"MEopMode/Prov/Cfg\",\\s*\"([0-9a-zA-Z]*)\"", 0, 0, NULL); + g_assert (r != NULL); + g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); + if (inner_error) + return; + if (g_match_info_matches (match_info)) { + g_autofree gchar *mno = NULL; + + mno = mm_get_string_unquoted_from_match_info (match_info, 1); + if (mno && modem_family == MM_CINTERION_MODEM_FAMILY_IMT) { + mno = mm_charset_take_and_convert_to_utf8 (mno, charset); + mm_obj_dbg (log_object, "current mno: %s", mno); + } + + /* for Cinterion LTE modules, some CID numbers have special meaning. + * This is dictated by the chipset and by the MNO: + * - the chipset uses a special one, CID 1, as a LTE combined attach chipset + * - the MNOs can define the sequence and number of APN to be used for their network. + * This takes priority over the chipset preferences, and therefore for some of them + * the CID for the initial EPS context must be changed. + */ + if (g_strcmp0 (mno, "2") == 0 || g_strcmp0 (mno, "vzwdcus") == 0) + *cid = 3; + else if (g_strcmp0 (mno, "tmode") == 0) + *cid = 2; + /* in all other cases no change to the preset value */ + } +} diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.h b/plugins/cinterion/mm-modem-helpers-cinterion.h index c35c5b3c..76e0d43e 100644 --- a/plugins/cinterion/mm-modem-helpers-cinterion.h +++ b/plugins/cinterion/mm-modem-helpers-cinterion.h @@ -163,4 +163,13 @@ gboolean mm_cinterion_smoni_response_to_signal_info (const gchar *response, MMSignal **out_lte, GError **error); +/*****************************************************************************/ +/* ^SCFG="MEopMode/Prov/Cfg" helper */ + +void mm_cinterion_provcfg_response_to_cid (const gchar *response, + MMCinterionModemFamily modem_family, + MMModemCharset charset, + gpointer log_object, + guint *cid); + #endif /* MM_MODEM_HELPERS_CINTERION_H */ diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c index 35123283..14ce4c38 100644 --- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c +++ b/plugins/cinterion/tests/test-modem-helpers-cinterion.c @@ -1596,6 +1596,71 @@ test_smoni_response_to_signal (void) } } +/*****************************************************************************/ +/* Test ^SCFG="MEopMode/Prov/Cfg" responses */ + +typedef struct { + const gchar *str; + MMCinterionModemFamily modem_family; + guint initial_cid; + gdouble expected_cid; +} ProvcfgResponseTest; + + +static const ProvcfgResponseTest provcfg_response_tests[] = { + { + + .str = "^SCFG: \"MEopMode/Prov/Cfg\",\"vdfde\"", + .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, + .initial_cid = 1, + .expected_cid = 1, + }, + { + + .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"attus\"", + .modem_family = MM_CINTERION_MODEM_FAMILY_IMT, + .initial_cid = 1, + .expected_cid = 1, + }, + { + + .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"2\"", + .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, + .initial_cid = 1, + .expected_cid = 3, + }, + { + + .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"vzwdcus\"", + .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, + .initial_cid = 1, + .expected_cid = 3, + }, + { + + .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"tmode\"", + .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, + .initial_cid = 1, + .expected_cid = 2, + } +}; + +static void +test_provcfg_response (void) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (provcfg_response_tests); i++) { + guint cid = provcfg_response_tests[i].initial_cid; + + mm_cinterion_provcfg_response_to_cid (provcfg_response_tests[i].str, + provcfg_response_tests[i].modem_family, + MM_MODEM_CHARSET_GSM, + NULL, + &cid); + g_assert_cmpuint (cid, ==, provcfg_response_tests[i].expected_cid); + } +} /*****************************************************************************/ @@ -1629,6 +1694,7 @@ int main (int argc, char **argv) g_test_add_func ("/MM/cinterion/ctzu/urc/full", test_ctzu_urc_full); g_test_add_func ("/MM/cinterion/smoni/query_response", test_smoni_response); g_test_add_func ("/MM/cinterion/smoni/query_response_to_signal", test_smoni_response_to_signal); + g_test_add_func ("/MM/cinterion/scfg/provcfg", test_provcfg_response); return g_test_run (); } |