aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/mmcli-modem-simple.c14
-rw-r--r--include/ModemManager-enums.h24
-rw-r--r--src/mm-base-bearer.c19
-rw-r--r--src/mm-iface-modem-3gpp.c75
-rw-r--r--src/mm-modem-helpers.c14
-rw-r--r--src/tests/test-modem-helpers.c24
6 files changed, 140 insertions, 30 deletions
diff --git a/cli/mmcli-modem-simple.c b/cli/mmcli-modem-simple.c
index ed53ad6f..76426694 100644
--- a/cli/mmcli-modem-simple.c
+++ b/cli/mmcli-modem-simple.c
@@ -246,10 +246,13 @@ status_process_reply (MMSimpleStatus *result,
VALIDATE_UNKNOWN (bands_str),
VALIDATE_UNKNOWN (access_tech_str));
- if ((mm_simple_status_get_3gpp_registration_state (result) ==
- MM_MODEM_3GPP_REGISTRATION_STATE_HOME) ||
- (mm_simple_status_get_3gpp_registration_state (result) ==
- MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING)) {
+ switch (mm_simple_status_get_3gpp_registration_state (result)) {
+ case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED:
g_print (" -------------------------\n"
" 3GPP | registration: '%s'\n"
" | operator code: '%s'\n"
@@ -261,6 +264,9 @@ status_process_reply (MMSimpleStatus *result,
VALIDATE_UNKNOWN (mm_simple_status_get_3gpp_operator_name (result)),
mm_modem_3gpp_subscription_state_get_string (
mm_simple_status_get_3gpp_subscription_state (result)));
+ break;
+ default:
+ break;
}
if ((mm_simple_status_get_cdma_cdma1x_registration_state (result) !=
diff --git a/include/ModemManager-enums.h b/include/ModemManager-enums.h
index 57127d6c..c956573d 100644
--- a/include/ModemManager-enums.h
+++ b/include/ModemManager-enums.h
@@ -978,16 +978,26 @@ typedef enum { /*< underscore_name=mm_modem_cdma_rm_protocol >*/
* @MM_MODEM_3GPP_REGISTRATION_STATE_DENIED: Registration denied.
* @MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN: Unknown registration status.
* @MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING: Registered on a roaming network.
+ * @MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY: Registered for "SMS only", home network (applicable only when on LTE).
+ * @MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY: Registered for "SMS only", roaming network (applicable only when on LTE).
+ * @MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY: Emergency services only.
+ * @MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED: Registered for "CSFB not preferred", home network (applicable only when on LTE).
+ * @MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED: Registered for "CSFB not preferred", roaming network (applicable only when on LTE).
*
- * GSM registration code as defined in 3GPP TS 27.007 section 10.1.19.
+ * GSM registration code as defined in 3GPP TS 27.007.
*/
typedef enum { /*< underscore_name=mm_modem_3gpp_registration_state >*/
- MM_MODEM_3GPP_REGISTRATION_STATE_IDLE = 0,
- MM_MODEM_3GPP_REGISTRATION_STATE_HOME = 1,
- MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING = 2,
- MM_MODEM_3GPP_REGISTRATION_STATE_DENIED = 3,
- MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN = 4,
- MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING = 5,
+ MM_MODEM_3GPP_REGISTRATION_STATE_IDLE = 0,
+ MM_MODEM_3GPP_REGISTRATION_STATE_HOME = 1,
+ MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING = 2,
+ MM_MODEM_3GPP_REGISTRATION_STATE_DENIED = 3,
+ MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN = 4,
+ MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING = 5,
+ MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY = 6,
+ MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY = 7,
+ MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY = 8,
+ MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED = 9,
+ MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED = 10,
} MMModem3gppRegistrationState;
/**
diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c
index e4234ea7..14194b9d 100644
--- a/src/mm-base-bearer.c
+++ b/src/mm-base-bearer.c
@@ -54,6 +54,7 @@ typedef enum {
CONNECTION_FORBIDDEN_REASON_NONE,
CONNECTION_FORBIDDEN_REASON_UNREGISTERED,
CONNECTION_FORBIDDEN_REASON_ROAMING,
+ CONNECTION_FORBIDDEN_REASON_EMERGENCY_ONLY,
CONNECTION_FORBIDDEN_REASON_LAST
} ConnectionForbiddenReason;
@@ -120,7 +121,8 @@ struct _MMBaseBearerPrivate {
static const gchar *connection_forbidden_reason_str [CONNECTION_FORBIDDEN_REASON_LAST] = {
"none",
"Not registered in the network",
- "Registered in roaming network, and roaming not allowed"
+ "Registered in roaming network, and roaming not allowed",
+ "Emergency services only",
};
/*****************************************************************************/
@@ -401,15 +403,22 @@ modem_3gpp_registration_state_changed (MMIfaceModem3gpp *modem,
self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_UNREGISTERED;
break;
case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED:
case MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING:
self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_NONE;
break;
case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY:
+ case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED:
if (mm_bearer_properties_get_allow_roaming (mm_base_bearer_peek_config (self)))
self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_NONE;
else
self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_ROAMING;
break;
+ case MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY:
+ self->priv->reason_3gpp = CONNECTION_FORBIDDEN_REASON_EMERGENCY_ONLY;
+ break;
}
/* If no reason to disconnect, or if it's a mixed CDMA+LTE modem without a CDMA reason,
@@ -429,6 +438,14 @@ modem_3gpp_registration_state_changed (MMIfaceModem3gpp *modem,
return;
}
+ /* Modem is registered under emergency services only? */
+ if (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_EMERGENCY_ONLY) {
+ mm_dbg ("Bearer not allowed to connect, emergency services only");
+ reset_deferred_unregistration (self);
+ mm_base_bearer_disconnect_force (self);
+ return;
+ }
+
/* Modem reports being unregistered */
if (self->priv->reason_3gpp == CONNECTION_FORBIDDEN_REASON_UNREGISTERED) {
/* If there is already a notification pending, just return */
diff --git a/src/mm-iface-modem-3gpp.c b/src/mm-iface-modem-3gpp.c
index baf743fb..d38c4ca4 100644
--- a/src/mm-iface-modem-3gpp.c
+++ b/src/mm-iface-modem-3gpp.c
@@ -137,12 +137,11 @@ get_consolidated_reg_state (RegistrationStateContext *ctx)
ctx->eps == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING)
return ctx->eps;
- if (ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING)
- return ctx->cs;
- if (ctx->ps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING)
- return ctx->ps;
- if (ctx->eps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING)
- return ctx->eps;
+ /* Searching? */
+ if (ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING ||
+ ctx->ps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING ||
+ ctx->eps == MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING)
+ return MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING;
/* If one state is DENIED and the others are UNKNOWN, use DENIED */
if (ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED &&
@@ -158,7 +157,41 @@ get_consolidated_reg_state (RegistrationStateContext *ctx)
ctx->eps == MM_MODEM_3GPP_REGISTRATION_STATE_DENIED)
return ctx->eps;
- return ctx->cs;
+ /* Emergency services? */
+ if (ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY ||
+ ctx->ps == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY ||
+ ctx->eps == MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY)
+ return MM_MODEM_3GPP_REGISTRATION_STATE_EMERGENCY_ONLY;
+
+ /* Support for additional registration states reported when on LTE.
+ *
+ * For example, we may see the modem registered in LTE (EPS==HOME), and we
+ * may get "SMS only" reported for CS.
+ *
+ * We give these states a very low priority w.r.t. the other ones as they
+ * are really likely never used (i.e. we would get as consolidated the LTE
+ * registration state, not the CS fall back state).
+ *
+ * We also warn in that case, because ideally we should always report the
+ * LTE registration state first, not this one.
+ */
+ if (ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY ||
+ ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
+ ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
+ ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) {
+ mm_warn ("3GPP CSFB registration state is consolidated: %s",
+ mm_modem_3gpp_registration_state_get_string (ctx->cs));
+ return ctx->cs;
+ }
+
+ /* Idle? */
+ if (ctx->cs == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE ||
+ ctx->ps == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE ||
+ ctx->eps == MM_MODEM_3GPP_REGISTRATION_STATE_IDLE)
+ return MM_MODEM_3GPP_REGISTRATION_STATE_IDLE;
+
+ /* Just unknown at this point */
+ return MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
}
/*****************************************************************************/
@@ -269,7 +302,11 @@ run_registration_checks_ready (MMIfaceModem3gpp *self,
/* If we got registered, end registration checks */
if (current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
- current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
+ current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING ||
+ current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY ||
+ current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
+ current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
+ current_registration_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) {
/* Request immediate access tech update */
mm_iface_modem_refresh_access_technologies (MM_IFACE_MODEM (ctx->self));
mm_dbg ("Modem is currently registered in a 3GPP network");
@@ -1035,6 +1072,10 @@ mm_iface_modem_3gpp_update_access_technologies (MMIfaceModem3gpp *self,
* but only if something valid to report */
if (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED ||
ctx->reloading_registration_info) {
if (access_tech != MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN)
mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self),
@@ -1070,7 +1111,11 @@ mm_iface_modem_3gpp_update_location (MMIfaceModem3gpp *self,
* change to registered), we also allow LAC/CID updates. */
if (ctx->reloading_registration_info ||
state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
- state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
+ state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) {
if (location_area_code > 0 && cell_id > 0)
mm_iface_modem_location_3gpp_update_lac_ci (MM_IFACE_MODEM_LOCATION (self),
location_area_code,
@@ -1123,7 +1168,11 @@ update_non_registered_state (MMIfaceModem3gpp *self,
* registration reject error code. If b), we want to make sure we
* preserve the subscription state */
if (old_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
- old_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING)
+ old_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING ||
+ old_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY ||
+ old_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
+ old_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
+ old_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED)
clear_subscription_state (self);
/* The property in the interface is bound to the property
@@ -1161,7 +1210,11 @@ update_registration_state (MMIfaceModem3gpp *self,
return;
if (new_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
- new_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
+ new_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING ||
+ new_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY ||
+ new_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_SMS_ONLY ||
+ new_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME_CSFB_NOT_PREFERRED ||
+ new_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) {
/* If already reloading registration info, skip it */
if (ctx->reloading_registration_info)
return;
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 8f208000..1d17c05d 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -1428,7 +1428,7 @@ mm_3gpp_parse_creg_response (GMatchInfo *info,
/* Status */
str = g_match_info_fetch (info, istat);
- stat = parse_uint (str, 10, 0, 5, &success);
+ stat = parse_uint (str, 10, 0, G_MAXUINT, &success);
g_free (str);
if (!success) {
g_set_error_literal (error,
@@ -1437,6 +1437,12 @@ mm_3gpp_parse_creg_response (GMatchInfo *info,
return FALSE;
}
+ /* 'roaming (csfb not preferred)' is the last valid state */
+ if (stat > MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING_CSFB_NOT_PREFERRED) {
+ mm_warn ("Registration State '%lu' is unknown", stat);
+ stat = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
+ }
+
/* Location Area Code */
if (ilac) {
/* FIXME: some phones apparently swap the LAC bytes (LG, SonyEricsson,
@@ -1463,12 +1469,6 @@ mm_3gpp_parse_creg_response (GMatchInfo *info,
act = -1;
}
- /* 'roaming' is the last valid state */
- if (stat > MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
- mm_warn ("Registration State '%lu' is unknown", stat);
- stat = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
- }
-
*out_reg_state = (MMModem3gppRegistrationState) stat;
if (stat != MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN) {
/* Don't fill in lac/ci/act if the device's state is unknown */
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index 0d70f051..ab54cd55 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -1027,6 +1027,28 @@ test_creg2_leading_zeros_unsolicited (void *f, gpointer d)
}
static void
+test_creg2_ublox_solicited (void *f, gpointer d)
+{
+ RegTestData *data = (RegTestData *) d;
+ const gchar *reply = "\r\n+CREG: 2,6,\"8B37\",\"0A265185\",7\r\n";
+ /* NOTE: '6' means registered for "SMS only", home network; we just assume UNKNOWN in this case */
+ const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY, 0x8B37, 0x0A265185, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 8, FALSE, FALSE };
+
+ test_creg_match ("Ublox Toby-L2 solicited while on LTE", TRUE, reply, data, &result);
+}
+
+static void
+test_creg2_ublox_unsolicited (void *f, gpointer d)
+{
+ RegTestData *data = (RegTestData *) d;
+ const gchar *reply = "\r\n+CREG: 6,\"8B37\",\"0A265185\",7\r\n";
+ /* NOTE: '6' means registered for "SMS only", home network; we just assume UNKNOWN in this case */
+ const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME_SMS_ONLY, 0x8B37, 0x0A265185, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 6, FALSE, FALSE };
+
+ test_creg_match ("Ublox Toby-L2 unsolicited while on LTE", FALSE, reply, data, &result);
+}
+
+static void
test_cgreg1_solicited (void *f, gpointer d)
{
RegTestData *data = (RegTestData *) d;
@@ -3255,6 +3277,8 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_creg2_leading_zeros_solicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_no_leading_zeros_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_leading_zeros_unsolicited, reg_data));
+ g_test_suite_add (suite, TESTCASE (test_creg2_ublox_solicited, reg_data));
+ g_test_suite_add (suite, TESTCASE (test_creg2_ublox_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_cgreg1_solicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_cgreg1_unsolicited, reg_data));