diff options
-rw-r--r-- | cli/mmcli-modem-simple.c | 14 | ||||
-rw-r--r-- | include/ModemManager-enums.h | 24 | ||||
-rw-r--r-- | src/mm-base-bearer.c | 19 | ||||
-rw-r--r-- | src/mm-iface-modem-3gpp.c | 75 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 14 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 24 |
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)); |