3gpp: update registration state enumeration with CSFB related states

Introduce "sms only" and "CSFB not preferred" home/roaming states to be reported
for the CS context, while already registered on LTE.

Based on 3GPP TS 27.007 v13.5.0.
This commit is contained in:
Aleksander Morgado
2016-10-05 13:32:41 +02:00
parent a561f6edf0
commit fe460b2f54
6 changed files with 140 additions and 30 deletions

View File

@@ -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) !=

View File

@@ -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;
/**

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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 */

View File

@@ -1026,6 +1026,28 @@ test_creg2_leading_zeros_unsolicited (void *f, gpointer d)
test_creg_match ("unsolicited CREG=2 with leading zeros in integer fields", FALSE, reply, data, &result);
}
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)
{
@@ -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));