modem-helpers: improve and fix COPS=? numeric fields parsing

The numeric fields in the +COPS=? response were relying on a very weak
parsing logic, assuming that they were single-digit numeric values and
not using the common string to integer conversion utilities.

This commit improves the conversion from the 3GPP/ETSI defined network
availability and access technology values to the MM defined ones,
providing enum-based matches even if the numeric values are the same.

The commit also fixes the parsing of access technology values > 10,
required to report 5G related values.
This commit is contained in:
Aleksander Morgado
2022-03-16 11:57:53 +01:00
parent 5ba67aff82
commit 2c8cfb4768
5 changed files with 54 additions and 48 deletions

View File

@@ -1018,6 +1018,7 @@ modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *self,
NULL, /* format */ NULL, /* format */
&operator_code, &operator_code,
NULL, /* act */ NULL, /* act */
self,
error)) error))
return NULL; return NULL;
@@ -1064,6 +1065,7 @@ modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *self,
NULL, /* format */ NULL, /* format */
&operator_name, &operator_name,
NULL, /* act */ NULL, /* act */
self,
error)) error))
return NULL; return NULL;

View File

@@ -4496,6 +4496,7 @@ modem_3gpp_load_operator_code_finish (MMIfaceModem3gpp *self,
NULL, /* format */ NULL, /* format */
&operator_code, &operator_code,
NULL, /* act */ NULL, /* act */
self,
error)) error))
return NULL; return NULL;
@@ -4535,6 +4536,7 @@ modem_3gpp_load_operator_name_finish (MMIfaceModem3gpp *self,
NULL, /* format */ NULL, /* format */
&operator_name, &operator_name,
NULL, /* act */ NULL, /* act */
self,
error)) error))
return NULL; return NULL;

View File

@@ -1124,11 +1124,34 @@ mm_3gpp_network_info_list_free (GList *info_list)
g_list_free_full (info_list, (GDestroyNotify) mm_3gpp_network_info_free); g_list_free_full (info_list, (GDestroyNotify) mm_3gpp_network_info_free);
} }
static MMModem3gppNetworkAvailability
get_mm_network_availability_from_3gpp_network_availability (guint val,
gpointer log_object)
{
/* The network availability status in the MM API and in the 3GPP specs take the
* same numeric values, but we map them with an enum as it's much safer if new
* values are defined by 3GPP in the future. */
switch (val) {
case 1:
return MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE;
case 2:
return MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT;
case 3:
return MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN;
default:
break;
}
mm_obj_warn (log_object, "unknown network availability value: %u", val);
return MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN;
}
static MMModemAccessTechnology static MMModemAccessTechnology
get_mm_access_tech_from_etsi_access_tech (guint act) get_mm_access_tech_from_etsi_access_tech (guint val,
gpointer log_object)
{ {
/* See ETSI TS 27.007 */ /* See ETSI TS 27.007 */
switch (act) { switch (val) {
case 0: /* GSM */ case 0: /* GSM */
case 8: /* EC-GSM-IoT (A/Gb mode) */ case 8: /* EC-GSM-IoT (A/Gb mode) */
return MM_MODEM_ACCESS_TECHNOLOGY_GSM; return MM_MODEM_ACCESS_TECHNOLOGY_GSM;
@@ -1154,40 +1177,11 @@ get_mm_access_tech_from_etsi_access_tech (guint act)
case 13: /* E-UTRA-NR dual connectivity */ case 13: /* E-UTRA-NR dual connectivity */
return (MM_MODEM_ACCESS_TECHNOLOGY_5GNR | MM_MODEM_ACCESS_TECHNOLOGY_LTE); return (MM_MODEM_ACCESS_TECHNOLOGY_5GNR | MM_MODEM_ACCESS_TECHNOLOGY_LTE);
default: default:
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; break;
}
}
static MMModem3gppNetworkAvailability
parse_network_status (const gchar *str,
gpointer log_object)
{
/* Expecting a value between '0' and '3' inclusive */
if (!str ||
strlen (str) != 1 ||
str[0] < '0' ||
str[0] > '3') {
mm_obj_warn (log_object, "cannot parse network status value '%s'", str);
return MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN;
} }
return (MMModem3gppNetworkAvailability) (str[0] - '0'); mm_obj_warn (log_object, "unknown access technology value: %u", val);
} return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
static MMModemAccessTechnology
parse_access_tech (const gchar *str,
gpointer log_object)
{
/* Recognized access technologies are between '0' and '7' inclusive... */
if (!str ||
strlen (str) != 1 ||
str[0] < '0' ||
str[0] > '7') {
mm_obj_warn (log_object, "cannot parse access technology value '%s'", str);
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
}
return get_mm_access_tech_from_etsi_access_tech (str[0] - '0');
} }
GList * GList *
@@ -1260,14 +1254,14 @@ mm_3gpp_parse_cops_test_response (const gchar *reply,
/* Parse the results */ /* Parse the results */
while (g_match_info_matches (match_info)) { while (g_match_info_matches (match_info)) {
MM3gppNetworkInfo *info; MM3gppNetworkInfo *info;
gchar *tmp; guint net_value = 0;
gboolean valid = FALSE; gboolean valid = FALSE;
info = g_new0 (MM3gppNetworkInfo, 1); info = g_new0 (MM3gppNetworkInfo, 1);
tmp = mm_get_string_unquoted_from_match_info (match_info, 1); /* the regex makes sure this is a number, it won't fail */
info->status = parse_network_status (tmp, log_object); mm_get_uint_from_match_info (match_info, 1, &net_value);
g_free (tmp); info->status = get_mm_network_availability_from_3gpp_network_availability (net_value, log_object);
info->operator_long = mm_get_string_unquoted_from_match_info (match_info, 2); info->operator_long = mm_get_string_unquoted_from_match_info (match_info, 2);
info->operator_short = mm_get_string_unquoted_from_match_info (match_info, 3); info->operator_short = mm_get_string_unquoted_from_match_info (match_info, 3);
@@ -1280,13 +1274,14 @@ mm_3gpp_parse_cops_test_response (const gchar *reply,
/* Only try for access technology with UMTS-format matches. /* Only try for access technology with UMTS-format matches.
* If none give, assume GSM */ * If none give, assume GSM */
tmp = (umts_format ? if (umts_format) {
mm_get_string_unquoted_from_match_info (match_info, 5) : guint act_value = 0;
NULL);
info->access_tech = (tmp ? /* the regex makes sure this is a number, it won't fail */
parse_access_tech (tmp, log_object) : mm_get_uint_from_match_info (match_info, 5, &act_value);
MM_MODEM_ACCESS_TECHNOLOGY_GSM); info->access_tech = get_mm_access_tech_from_etsi_access_tech (act_value, log_object);
g_free (tmp); } else
info->access_tech = MM_MODEM_ACCESS_TECHNOLOGY_GSM;
/* If the operator number isn't valid (ie, at least 5 digits), /* If the operator number isn't valid (ie, at least 5 digits),
* ignore the scan result; it's probably the parameter stuff at the * ignore the scan result; it's probably the parameter stuff at the
@@ -1294,6 +1289,8 @@ mm_3gpp_parse_cops_test_response (const gchar *reply,
* but there's no good way to ignore it. * but there's no good way to ignore it.
*/ */
if (info->operator_code && (strlen (info->operator_code) >= 5)) { if (info->operator_code && (strlen (info->operator_code) >= 5)) {
gchar *tmp;
valid = TRUE; valid = TRUE;
tmp = info->operator_code; tmp = info->operator_code;
while (*tmp) { while (*tmp) {
@@ -1337,6 +1334,7 @@ mm_3gpp_parse_cops_read_response (const gchar *response,
guint *out_format, guint *out_format,
gchar **out_operator, gchar **out_operator,
MMModemAccessTechnology *out_act, MMModemAccessTechnology *out_act,
gpointer log_object,
GError **error) GError **error)
{ {
GRegex *r; GRegex *r;
@@ -1388,7 +1386,7 @@ mm_3gpp_parse_cops_read_response (const gchar *response,
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing AcT"); inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing AcT");
goto out; goto out;
} }
act = get_mm_access_tech_from_etsi_access_tech (actval); act = get_mm_access_tech_from_etsi_access_tech (actval, log_object);
} }
out: out:
@@ -2127,7 +2125,9 @@ mm_3gpp_parse_creg_response (GMatchInfo *info,
/* Don't fill in lac/ci/act if the device's state is unknown */ /* Don't fill in lac/ci/act if the device's state is unknown */
*out_lac = (gulong)lac; *out_lac = (gulong)lac;
*out_ci = (gulong)ci; *out_ci = (gulong)ci;
*out_act = (act >= 0 ? get_mm_access_tech_from_etsi_access_tech (act) : MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); *out_act = (act >= 0 ?
get_mm_access_tech_from_etsi_access_tech (act, log_object) :
MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
} }
return TRUE; return TRUE;
} }

View File

@@ -160,6 +160,7 @@ gboolean mm_3gpp_parse_cops_read_response (const gchar *response,
guint *out_format, guint *out_format,
gchar **out_operator, gchar **out_operator,
MMModemAccessTechnology *out_act, MMModemAccessTechnology *out_act,
gpointer log_object,
GError **error); GError **error);
/* Logic to compare two APN names */ /* Logic to compare two APN names */

View File

@@ -961,6 +961,7 @@ test_cops_query_data (const CopsQueryData *item)
&format, &format,
&operator, &operator,
&act, &act,
NULL,
&error); &error);
g_assert_no_error (error); g_assert_no_error (error);
g_assert (result); g_assert (result);