Merge request !1480 from 'creg_urc'

modem-helpers: fix multiple C*REG events in single URC

https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1480

Closes #1087
This commit is contained in:
Dan Williams
2026-09-08 11:55:08 -05:00
4 changed files with 204 additions and 207 deletions
+25 -46
View File
@@ -218,7 +218,7 @@ struct _MMBroadbandModemPrivate {
gboolean modem_3gpp_eps_network_supported; gboolean modem_3gpp_eps_network_supported;
gboolean modem_3gpp_5gs_network_supported; gboolean modem_3gpp_5gs_network_supported;
/* Implementation helpers */ /* Implementation helpers */
GPtrArray *modem_3gpp_registration_regex; GRegex *modem_3gpp_registration_regex;
MMModem3gppFacility modem_3gpp_ignored_facility_locks; MMModem3gppFacility modem_3gpp_ignored_facility_locks;
MMBaseBearer *modem_3gpp_initial_eps_bearer; MMBaseBearer *modem_3gpp_initial_eps_bearer;
MMModem3gppPacketServiceState modem_3gpp_packet_service_state; MMModem3gppPacketServiceState modem_3gpp_packet_service_state;
@@ -5267,32 +5267,28 @@ modem_3gpp_setup_unsolicited_registration_events (MMIfaceModem3gpp *self,
gpointer user_data) gpointer user_data)
{ {
MMPortSerialAt *ports[2]; MMPortSerialAt *ports[2];
GPtrArray *array; g_autoptr(GRegex) regex = NULL;
guint i; guint i;
guint j;
GTask *task; GTask *task;
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
/* Set up CREG unsolicited message handlers in both ports */ /* Set up CREG unsolicited message handlers in both ports */
array = mm_3gpp_creg_regex_get (FALSE); regex = mm_3gpp_creg_regex_get (FALSE);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (!ports[i]) if (!ports[i])
continue; continue;
mm_obj_dbg (self, "setting up 3GPP unsolicited registration messages handlers in %s", mm_obj_dbg (self, "setting up 3GPP unsolicited registration messages handlers in %s",
mm_port_get_device (MM_PORT (ports[i]))); mm_port_get_device (MM_PORT (ports[i])));
for (j = 0; j < array->len; j++) { mm_port_serial_at_add_unsolicited_msg_handler (
mm_port_serial_at_add_unsolicited_msg_handler ( MM_PORT_SERIAL_AT (ports[i]),
MM_PORT_SERIAL_AT (ports[i]), regex,
(GRegex *) g_ptr_array_index (array, j), (MMPortSerialAtUnsolicitedMsgFn)registration_state_changed,
(MMPortSerialAtUnsolicitedMsgFn)registration_state_changed, self,
self, NULL);
NULL);
}
} }
mm_3gpp_creg_regex_destroy (array);
task = g_task_new (self, NULL, callback, user_data); task = g_task_new (self, NULL, callback, user_data);
g_task_return_boolean (task, TRUE); g_task_return_boolean (task, TRUE);
@@ -5316,32 +5312,28 @@ modem_3gpp_cleanup_unsolicited_registration_events (MMIfaceModem3gpp *self,
gpointer user_data) gpointer user_data)
{ {
MMPortSerialAt *ports[2]; MMPortSerialAt *ports[2];
GPtrArray *array; g_autoptr(GRegex) regex = NULL;
guint i; guint i;
guint j;
GTask *task; GTask *task;
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
/* Set up CREG unsolicited message handlers in both ports */ /* Set up CREG unsolicited message handlers in both ports */
array = mm_3gpp_creg_regex_get (FALSE); regex = mm_3gpp_creg_regex_get (FALSE);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (!ports[i]) if (!ports[i])
continue; continue;
mm_obj_dbg (self, "cleaning up unsolicited registration messages handlers in %s", mm_obj_dbg (self, "cleaning up unsolicited registration messages handlers in %s",
mm_port_get_device (MM_PORT (ports[i]))); mm_port_get_device (MM_PORT (ports[i])));
for (j = 0; j < array->len; j++) { mm_port_serial_at_add_unsolicited_msg_handler (
mm_port_serial_at_add_unsolicited_msg_handler ( MM_PORT_SERIAL_AT (ports[i]),
MM_PORT_SERIAL_AT (ports[i]), regex,
(GRegex *) g_ptr_array_index (array, j), NULL,
NULL, NULL,
NULL, NULL);
NULL);
}
} }
mm_3gpp_creg_regex_destroy (array);
task = g_task_new (self, NULL, callback, user_data); task = g_task_new (self, NULL, callback, user_data);
g_task_return_boolean (task, TRUE); g_task_return_boolean (task, TRUE);
@@ -5608,7 +5600,6 @@ registration_status_check_ready (MMBroadbandModem *self,
RunRegistrationChecksContext *ctx; RunRegistrationChecksContext *ctx;
const gchar *response; const gchar *response;
GError *error = NULL; GError *error = NULL;
guint i;
gboolean parsed; gboolean parsed;
gboolean cgreg = FALSE; gboolean cgreg = FALSE;
gboolean cereg = FALSE; gboolean cereg = FALSE;
@@ -5641,18 +5632,10 @@ registration_status_check_ready (MMBroadbandModem *self,
} }
/* Try to match the response */ /* Try to match the response */
for (i = 0; if (!g_regex_match (self->priv->modem_3gpp_registration_regex,
i < self->priv->modem_3gpp_registration_regex->len; response,
i++) { 0,
if (g_regex_match ((GRegex *)g_ptr_array_index (self->priv->modem_3gpp_registration_regex, i), &match_info)) {
response,
0,
&match_info))
break;
g_clear_pointer (&match_info, g_match_info_free);
}
if (!match_info) {
error = g_error_new (MM_CORE_ERROR, error = g_error_new (MM_CORE_ERROR,
MM_CORE_ERROR_FAILED, MM_CORE_ERROR_FAILED,
"Unknown registration status response: '%s'", "Unknown registration status response: '%s'",
@@ -11704,9 +11687,8 @@ setup_ports (MMBroadbandModem *self)
g_autoptr(GRegex) ciev_regex = NULL; g_autoptr(GRegex) ciev_regex = NULL;
g_autoptr(GRegex) cmti_regex = NULL; g_autoptr(GRegex) cmti_regex = NULL;
g_autoptr(GRegex) cusd_regex = NULL; g_autoptr(GRegex) cusd_regex = NULL;
GPtrArray *array; g_autoptr(GRegex) creg_regex = NULL;
guint i; guint i;
guint j;
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self));
@@ -11722,7 +11704,7 @@ setup_ports (MMBroadbandModem *self)
NULL); NULL);
/* Cleanup all unsolicited message handlers in all AT ports */ /* Cleanup all unsolicited message handlers in all AT ports */
array = mm_3gpp_creg_regex_get (FALSE); creg_regex = mm_3gpp_creg_regex_get (FALSE);
ciev_regex = mm_3gpp_ciev_regex_get (); ciev_regex = mm_3gpp_ciev_regex_get ();
cmti_regex = mm_3gpp_cmti_regex_get (); cmti_regex = mm_3gpp_cmti_regex_get ();
cusd_regex = mm_3gpp_cusd_regex_get (); cusd_regex = mm_3gpp_cusd_regex_get ();
@@ -11731,14 +11713,11 @@ setup_ports (MMBroadbandModem *self)
if (!ports[i]) if (!ports[i])
continue; continue;
for (j = 0; j < array->len; j++) mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), creg_regex, NULL, NULL, NULL);
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), (GRegex *)g_ptr_array_index (array, j), NULL, NULL, NULL);
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), ciev_regex, NULL, NULL, NULL); mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), ciev_regex, NULL, NULL, NULL);
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), cmti_regex, NULL, NULL, NULL); mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), cmti_regex, NULL, NULL, NULL);
mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), cusd_regex, NULL, NULL, NULL); mm_port_serial_at_add_unsolicited_msg_handler (MM_PORT_SERIAL_AT (ports[i]), cusd_regex, NULL, NULL, NULL);
} }
mm_3gpp_creg_regex_destroy (array);
} }
/*****************************************************************************/ /*****************************************************************************/
@@ -14284,7 +14263,7 @@ finalize (GObject *object)
ports_context_unref (self->priv->in_call_ports_ctx); ports_context_unref (self->priv->in_call_ports_ctx);
if (self->priv->modem_3gpp_registration_regex) if (self->priv->modem_3gpp_registration_regex)
mm_3gpp_creg_regex_destroy (self->priv->modem_3gpp_registration_regex); g_regex_unref (self->priv->modem_3gpp_registration_regex);
g_free (self->priv->carrier_config_mapping); g_free (self->priv->carrier_config_mapping);
+129 -122
View File
@@ -900,35 +900,24 @@ static const gchar *creg_regex[] = {
[13] = "\\+(C5GREG):\\s*([0-9]+)\\s*,\\s*([0-9+])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", [13] = "\\+(C5GREG):\\s*([0-9]+)\\s*,\\s*([0-9+])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)",
}; };
GPtrArray * GRegex *
mm_3gpp_creg_regex_get (gboolean solicited) mm_3gpp_creg_regex_get (gboolean solicited)
{ {
GPtrArray *array; g_autoptr(GString) pattern = NULL;
guint i; guint i;
array = g_ptr_array_sized_new (G_N_ELEMENTS (creg_regex)); pattern = g_string_sized_new(4096);
for (i = 0; i < G_N_ELEMENTS (creg_regex); i++) { for (i = 0; i < G_N_ELEMENTS (creg_regex); i++) {
GRegex *regex;
g_autofree gchar *pattern = NULL;
if (solicited) { if (solicited) {
pattern = g_strdup_printf ("%s$", creg_regex[i]); g_string_append_printf (pattern, "%s$|", creg_regex[i]);
regex = g_regex_new (pattern, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
} else { } else {
pattern = g_strdup_printf ("\\r\\n%s\\r\\n", creg_regex[i]); g_string_append_printf (pattern, "\\r\\n%s\\r\\n|", creg_regex[i]);
regex = g_regex_new (pattern, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
} }
g_assert (regex);
g_ptr_array_add (array, regex);
} }
return array; /* truncate last | char */
} g_string_truncate (pattern, pattern->len - 1);
return g_regex_new (pattern->str, G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
void
mm_3gpp_creg_regex_destroy (GPtrArray *array)
{
g_ptr_array_foreach (array, (GFunc) g_regex_unref, NULL);
g_ptr_array_free (array, TRUE);
} }
/*************************************************************************/ /*************************************************************************/
@@ -2013,20 +2002,6 @@ mm_3gpp_parse_cgact_read_response (const gchar *reply,
/*************************************************************************/ /*************************************************************************/
static gboolean
item_is_lac_not_stat (GMatchInfo *info, guint32 item)
{
gchar *str;
gboolean is_lac = FALSE;
/* A <stat> will always be a digit < 100, without quotes */
str = g_match_info_fetch (info, item);
g_assert (str);
is_lac = (strchr (str, '"') || strlen (str) > 2);
g_free (str);
return is_lac;
}
gboolean gboolean
mm_3gpp_parse_creg_response (GMatchInfo *info, mm_3gpp_parse_creg_response (GMatchInfo *info,
gpointer log_object, gpointer log_object,
@@ -2042,7 +2017,7 @@ mm_3gpp_parse_creg_response (GMatchInfo *info,
gint n_matches, act = -1; gint n_matches, act = -1;
guint stat = 0; guint stat = 0;
guint64 lac = 0, ci = 0; guint64 lac = 0, ci = 0;
guint istat = 0, ilac = 0, ici = 0, iact = 0; guint ireg = 0, istat = 0, ilac = 0, ici = 0, iact = 0;
gchar *str; gchar *str;
g_assert (info != NULL); g_assert (info != NULL);
@@ -2054,98 +2029,130 @@ mm_3gpp_parse_creg_response (GMatchInfo *info,
g_assert (out_cereg != NULL); g_assert (out_cereg != NULL);
g_assert (out_c5greg != NULL); g_assert (out_c5greg != NULL);
str = g_match_info_fetch (info, 1); /* Each regex in the array adds to the number of matches (e.g. first regex
* will match in indices 1 and 2, but second regex will use indices 3/4/5
* etc), so we "just" need to process each regex in order */
n_matches = g_match_info_get_match_count (info);
switch (n_matches) {
case 3:
/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */
/* [0] = "\\+(CREG|CGREG|CEREG|C5GREG):\\s*0*([0-9])", */
ireg = n_matches - 2;
istat = n_matches - 1;
break;
case 6:
/* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */
/* [1] = "\\+(CREG|CGREG|CEREG|C5GREG):\\s*0*([0-9]),\\s*0*([0-9])", */
ireg = n_matches - 3;
istat = n_matches - 1;
break;
case 10:
/* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */
/* [2] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", */
ireg = n_matches - 4;
istat = n_matches - 3;
ilac = n_matches - 2;
ici = n_matches - 1;
break;
case 15:
case 20:
/* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */
/* [3] = "\\+(CREG|CGREG|CEREG):\\s*([0-9]),\\s*([0-9])\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)", */
/* [4] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*(\"[^,]*\")\\s*,\\s*(\"[^,\\s]*\")", */
ireg = n_matches - 5;
istat = n_matches - 3;
ilac = n_matches - 2;
ici = n_matches - 1;
break;
case 25:
case 30:
/* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */
/* [5] = "\\+(CREG|CGREG|CEREG):\\s*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9])", */
/* [6] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])\\s*,\\s*(\"[^,\\s]*\")\\s*,\\s*(\"[^,\\s]*\")\\s*,\\s*0*([0-9])", */
ireg = n_matches - 5;
istat = n_matches - 4;
ilac = n_matches - 3;
ici = n_matches - 2;
iact = n_matches - 1;
break;
case 36:
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */
/* [7] = "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])", */
ireg = n_matches - 6;
istat = n_matches - 4;
ilac = n_matches - 3;
ici = n_matches - 2;
iact = n_matches - 1;
break;
case 42:
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */
/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */
/* [8] = "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*", */
ireg = n_matches - 6;
istat = n_matches - 4;
ilac = n_matches - 3;
ici = n_matches - 2;
iact = n_matches - 1;
break;
case 48:
/* +CREG: <stat>,<lac>,<ci>,<AcT>,<RAC> (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */
/* [9] = "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])\\s*,\\s*([^,\\s]*)", */
ireg = n_matches - 6;
istat = n_matches - 5;
ilac = n_matches - 4;
ici = n_matches - 3;
iact = n_matches - 2;
break;
case 54:
/* +CEREG: <stat>,<lac>,<rac>,<ci>,<AcT> (ETSI 27.007 v8.6 CREG=2 unsolicited with RAC) */
/* [10] = "\\+(CEREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])", */
ireg = n_matches - 6;
istat = n_matches - 5;
ilac = n_matches - 4;
ici = n_matches - 2;
iact = n_matches - 1;
break;
case 61:
/* +CEREG: <n>,<stat>,<lac>,<rac>,<ci>,<AcT> (ETSI 27.007 v8.6 CREG=2 solicited with RAC) */
/* [11] = "\\+(CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])", */
ireg = n_matches - 7;
istat = n_matches - 5;
ilac = n_matches - 4;
ici = n_matches - 2;
iact = n_matches - 1;
break;
case 68:
/* +C5GREG: <stat>,<lac>,<ci>,<AcT>,<Allowed_NSSAI_length>,<Allowed_NSSAI> (ETSI 27.007 CREG=2 unsolicited) */
/* [12] = "\\+(C5GREG):\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", */
ireg = n_matches - 7;
istat = n_matches - 6;
ilac = n_matches - 5;
ici = n_matches - 4;
iact = n_matches - 3;
break;
case 76:
/* +C5GREG: <n>,<stat>,<lac>,<ci>,<AcT>,<Allowed_NSSAI_length>,<Allowed_NSSAI> (ETSI 27.007 solicited) */
/* [13] = "\\+(C5GREG):\\s*([0-9]+)\\s*,\\s*([0-9+])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([0-9]+)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)", */
ireg = n_matches - 8;
istat = n_matches - 6;
ilac = n_matches - 5;
ici = n_matches - 4;
iact = n_matches - 3;
break;
default:
g_set_error_literal (error,
MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not parse the registration status response (invalid match count)");
return FALSE;
}
/* Reg type */
str = g_match_info_fetch (info, ireg);
*out_cgreg = (str && strstr (str, "CGREG")) ? TRUE : FALSE; *out_cgreg = (str && strstr (str, "CGREG")) ? TRUE : FALSE;
*out_cereg = (str && strstr (str, "CEREG")) ? TRUE : FALSE; *out_cereg = (str && strstr (str, "CEREG")) ? TRUE : FALSE;
*out_c5greg = (str && strstr (str, "C5GREG")) ? TRUE : FALSE; *out_c5greg = (str && strstr (str, "C5GREG")) ? TRUE : FALSE;
g_free (str); g_free (str);
/* Normally the number of matches could be used to determine what each
* item is, but we have overlap in one case.
*/
n_matches = g_match_info_get_match_count (info);
if (n_matches == 3) {
/* CREG=1: +CREG: <stat> */
istat = 2;
} else if (n_matches == 4) {
/* Solicited response: +CREG: <n>,<stat> */
istat = 3;
} else if (n_matches == 5) {
/* CREG=2 (GSM 07.07): +CREG: <stat>,<lac>,<ci> */
istat = 2;
ilac = 3;
ici = 4;
} else if (n_matches == 6) {
/* CREG=2 (ETSI 27.007): +CREG: <stat>,<lac>,<ci>,<AcT>
* CREG=2 (non-standard): +CREG: <n>,<stat>,<lac>,<ci>
*/
/* Check if the third item is the LAC to distinguish the two cases */
if (item_is_lac_not_stat (info, 3)) {
istat = 2;
ilac = 3;
ici = 4;
iact = 5;
} else {
istat = 3;
ilac = 4;
ici = 5;
}
} else if (n_matches == 7) {
/* CREG=2 (solicited): +CREG: <n>,<stat>,<lac>,<ci>,<AcT>
* CREG=2 (unsolicited with RAC): +CREG: <stat>,<lac>,<ci>,<AcT>,<RAC>
* CEREG=2 (solicited): +CEREG: <n>,<stat>,<lac>,<ci>,<AcT>
* CEREG=2 (unsolicited with RAC): +CEREG: <stat>,<lac>,<rac>,<ci>,<AcT>
*/
if (*out_cereg) {
/* Check if the third item is the LAC to distinguish the two cases */
if (item_is_lac_not_stat (info, 3)) {
istat = 2;
ilac = 3;
} else {
istat = 3;
ilac = 4;
}
ici = 5;
iact = 6;
} else {
/* Check if the third item is the LAC to distinguish the two cases */
if (item_is_lac_not_stat (info, 3)) {
istat = 2;
ilac = 3;
ici = 4;
iact = 5;
} else {
istat = 3;
ilac = 4;
ici = 5;
iact = 6;
}
}
} else if (n_matches == 8) {
/* CEREG=2 (solicited with RAC): +CEREG: <n>,<stat>,<lac>,<rac>,<ci>,<AcT>
* C5GREG=2 (unsolicited): +C5GREG: <stat>,<tac>,<ci>,<AcT>,<Allowed_NSSAI_length>,<Allowed_NSSAI>
*/
if (*out_cereg) {
istat = 3;
ilac = 4;
ici = 6;
iact = 7;
} else if (*out_c5greg) {
istat = 2;
ilac = 3;
ici = 4;
iact = 5;
}
} else if (n_matches == 9) {
/* C5GREG=2 (solicited): +C5GREG: <n>,<stat>,<tac>,<ci>,<AcT>,<Allowed_NSSAI_length>,<Allowed_NSSAI> */
istat = 3;
ilac = 4;
ici = 5;
iact = 6;
}
/* Status */ /* Status */
if (!mm_get_uint_from_match_info (info, istat, &stat)) { if (!mm_get_uint_from_match_info (info, istat, &stat)) {
g_set_error_literal (error, g_set_error_literal (error,
+7 -8
View File
@@ -141,14 +141,13 @@ MMFlowControl mm_flow_control_from_string (const gchar *str,
gboolean mm_modem_3gpp_registration_state_is_registered (MMModem3gppRegistrationState state); gboolean mm_modem_3gpp_registration_state_is_registered (MMModem3gppRegistrationState state);
/* Common Regex getters */ /* Common Regex getters */
GPtrArray *mm_3gpp_creg_regex_get (gboolean solicited); GRegex *mm_3gpp_creg_regex_get (gboolean solicited);
void mm_3gpp_creg_regex_destroy (GPtrArray *array); GRegex *mm_3gpp_ciev_regex_get (void);
GRegex *mm_3gpp_ciev_regex_get (void); GRegex *mm_3gpp_cgev_regex_get (void);
GRegex *mm_3gpp_cgev_regex_get (void); GRegex *mm_3gpp_cusd_regex_get (void);
GRegex *mm_3gpp_cusd_regex_get (void); GRegex *mm_3gpp_cmti_regex_get (void);
GRegex *mm_3gpp_cmti_regex_get (void); GRegex *mm_3gpp_cds_regex_get (void);
GRegex *mm_3gpp_cds_regex_get (void); GRegex *mm_3gpp_cbm_regex_get (void);
GRegex *mm_3gpp_cbm_regex_get (void);
/* AT+WS46=? response parser: returns array of MMModemMode values */ /* AT+WS46=? response parser: returns array of MMModemMode values */
GArray *mm_3gpp_parse_ws46_test_response (const gchar *response, GArray *mm_3gpp_parse_ws46_test_response (const gchar *response,
+43 -31
View File
@@ -1088,8 +1088,8 @@ test_normalize_operator (void)
/* Test CREG/CGREG responses and unsolicited messages */ /* Test CREG/CGREG responses and unsolicited messages */
typedef struct { typedef struct {
GPtrArray *solicited_creg; GRegex *solicited_creg;
GPtrArray *unsolicited_creg; GRegex *unsolicited_creg;
} RegTestData; } RegTestData;
static RegTestData * static RegTestData *
@@ -1106,8 +1106,8 @@ reg_test_data_new (void)
static void static void
reg_test_data_free (RegTestData *data) reg_test_data_free (RegTestData *data)
{ {
mm_3gpp_creg_regex_destroy (data->solicited_creg); g_regex_unref (data->solicited_creg);
mm_3gpp_creg_regex_destroy (data->unsolicited_creg); g_regex_unref (data->unsolicited_creg);
g_free (data); g_free (data);
} }
@@ -1131,52 +1131,42 @@ test_creg_match (const char *test,
const CregResult *result) const CregResult *result)
{ {
g_autoptr(GMatchInfo) info = NULL; g_autoptr(GMatchInfo) info = NULL;
guint i;
MMModem3gppRegistrationState state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; MMModem3gppRegistrationState state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
MMModemAccessTechnology access_tech = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; MMModemAccessTechnology access_tech = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
gulong lac = 0; gulong lac = 0;
gulong ci = 0; gulong ci = 0;
GError *error = NULL; GError *error = NULL;
gboolean success; gboolean success;
gboolean matched;
gboolean cgreg = FALSE; gboolean cgreg = FALSE;
gboolean cereg = FALSE; gboolean cereg = FALSE;
gboolean c5greg = FALSE; gboolean c5greg = FALSE;
guint regex_num = 0; GRegex *regex;
GPtrArray *array;
g_assert (reply); g_assert (reply);
g_assert (test); g_assert (test);
g_assert (data); g_assert (data);
g_assert (result); g_assert (result);
g_debug ("Testing '%s' +C%sREG %s response...", g_debug ("Testing '%s' +C%sREG %s response '%s'...",
test, test,
result->cgreg ? "G" : "", result->cgreg ? "G" : "",
solicited ? "solicited" : "unsolicited"); solicited ? "solicited" : "unsolicited",
reply);
array = solicited ? data->solicited_creg : data->unsolicited_creg; regex = solicited ? data->solicited_creg : data->unsolicited_creg;
for (i = 0; i < array->len; i++) { g_regex_match (regex, reply, 0, &info);
GRegex *r = g_ptr_array_index (array, i);
if (g_regex_match (r, reply, 0, &info)) { while (g_match_info_matches (info)) {
g_debug (" matched with %d", i); matched = TRUE;
regex_num = i; success = mm_3gpp_parse_creg_response (info, NULL, &state, &lac, &ci, &access_tech, &cgreg, &cereg, &c5greg, &error);
break;
} g_assert (success);
g_clear_pointer (&info, g_match_info_free); g_assert_no_error (error);
g_match_info_next (info, NULL);
} }
g_debug (" regex_num (%u) == result->regex_num (%u)", g_assert (matched);
regex_num,
result->regex_num);
g_assert (info != NULL);
g_assert_cmpuint (regex_num, ==, result->regex_num);
success = mm_3gpp_parse_creg_response (info, NULL, &state, &lac, &ci, &access_tech, &cgreg, &cereg, &c5greg, &error);
g_assert (success);
g_assert_no_error (error);
g_assert_cmpuint (state, ==, result->state); g_assert_cmpuint (state, ==, result->state);
g_assert_cmpuint (lac, ==, result->lac); g_assert_cmpuint (lac, ==, result->lac);
g_assert_cmpuint (ci, ==, result->ci); g_assert_cmpuint (ci, ==, result->ci);
@@ -1472,7 +1462,7 @@ test_creg_cgreg_multi_unsolicited (void *f, gpointer d)
{ {
RegTestData *data = (RegTestData *) d; RegTestData *data = (RegTestData *) d;
const char *reply = "\r\n+CREG: 5\r\n\r\n+CGREG: 0\r\n"; const char *reply = "\r\n+CREG: 5\r\n\r\n+CGREG: 0\r\n";
const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, FALSE, FALSE, FALSE }; const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_IDLE, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, TRUE, FALSE, FALSE };
test_creg_match ("Multi CREG/CGREG", FALSE, reply, data, &result); test_creg_match ("Multi CREG/CGREG", FALSE, reply, data, &result);
} }
@@ -1482,11 +1472,21 @@ test_creg_cgreg_multi2_unsolicited (void *f, gpointer d)
{ {
RegTestData *data = (RegTestData *) d; RegTestData *data = (RegTestData *) d;
const char *reply = "\r\n+CGREG: 0\r\n\r\n+CREG: 5\r\n"; const char *reply = "\r\n+CGREG: 0\r\n\r\n+CREG: 5\r\n";
const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_IDLE, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, TRUE, FALSE, FALSE }; const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING, 0, 0, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, FALSE, FALSE, FALSE };
test_creg_match ("Multi CREG/CGREG #2", FALSE, reply, data, &result); test_creg_match ("Multi CREG/CGREG #2", FALSE, reply, data, &result);
} }
static void
test_cereg_multi_unsolicited (void *f, gpointer d)
{
RegTestData *data = (RegTestData *) d;
const char *reply = "\r\n+CEREG: 2\r\n\r\n+CNSMOD: 8\r\n\r\n+CEREG: 1,AAAA,01234567,7\r\n";
const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_HOME, 0xAAAA, 0x1234567, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 5, FALSE, TRUE, FALSE };
test_creg_match ("Multi CEREG", FALSE, reply, data, &result);
}
static void static void
test_cgreg2_x220_unsolicited (void *f, gpointer d) test_cgreg2_x220_unsolicited (void *f, gpointer d)
{ {
@@ -1518,6 +1518,16 @@ test_creg2_s8500_wave_multidigit_stat_unsolicited (void *f, gpointer d)
test_creg_match ("Samsung Wave S8500 CREG=2 with multidigit \"stat\" value", FALSE, reply, data, &result); test_creg_match ("Samsung Wave S8500 CREG=2 with multidigit \"stat\" value", FALSE, reply, data, &result);
} }
static void
test_creg2_s8500_wave_act_unsolicited (void *f, gpointer d)
{
RegTestData *data = (RegTestData *) d;
const char *reply = "\r\n+CGREG: 2,11,003F,8FE3, 10, C2816\r\n";
const CregResult result = { MM_MODEM_3GPP_REGISTRATION_STATE_ATTACHED_RLOS, 0x003F, 0x8FE3, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 8, TRUE, FALSE, FALSE };
test_creg_match ("Samsung Wave S8500 CREG=2 with act value", FALSE, reply, data, &result);
}
static void static void
test_creg2_gobi_weird_solicited (void *f, gpointer d) test_creg2_gobi_weird_solicited (void *f, gpointer d)
{ {
@@ -5362,6 +5372,7 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_creg2_md400_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_md400_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_multidigit_stat_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_multidigit_stat_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_s8500_wave_act_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_gobi_weird_solicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_gobi_weird_solicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_iridium_solicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_iridium_solicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg2_no_leading_zeros_solicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg2_no_leading_zeros_solicited, reg_data));
@@ -5406,6 +5417,7 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, reg_data)); g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_cereg_multi_unsolicited, reg_data));
g_test_suite_add (suite, TESTCASE (test_cscs_icon225_support_response, NULL)); g_test_suite_add (suite, TESTCASE (test_cscs_icon225_support_response, NULL));
g_test_suite_add (suite, TESTCASE (test_cscs_sierra_mercury_support_response, NULL)); g_test_suite_add (suite, TESTCASE (test_cscs_sierra_mercury_support_response, NULL));