From d8135be6e2c132e59d3fbe9d231afa88b1e5e2b2 Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Sat, 22 Feb 2025 17:17:32 +0100 Subject: modem-helpers: Add helpers to parse channel lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `CSCB` has the form ``` CSCB: [0|1],"","" ``` If the first parameter is `0` this specifies the accepted types if `1` it specifies rejected. So far seen in the wild were CSCB strings with accepted types only and a coding scheme of "" so this is what we handle for the moment. Signed-off-by: Guido Günther --- src/mm-modem-helpers.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) (limited to 'src/mm-modem-helpers.c') diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 772a2de8..4f0c6248 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -2936,6 +2936,110 @@ out: return TRUE; } +/*************************************************************************/ + +#define CBS_MAX_CHANNEL G_MAXUINT16 + +GArray * +mm_3gpp_parse_cscb_response (const char *response, GError **error) +{ + g_autoptr(GRegex) r = NULL; + g_autoptr(GMatchInfo) match_info = NULL; + GError *inner_error = NULL; + gsize len; + g_autoptr (GArray) array = g_array_new (FALSE, FALSE, sizeof (MMCellBroadcastChannels)); + g_autofree char *str = NULL; + g_auto (GStrv) intervals = NULL; + int i; + + len = strlen (response); + if (!len) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "empty channel list"); + goto out; + } + + /* + * AT+CSCB=[0|1],"","" + */ + r = g_regex_new ("\\+CSCB:\\s*" + "(\\d),\\s*" /* [0|1] */ + "\"([\\d,\\-]*)\"," /* channel list */ + "\"\"", /* encodings */ + G_REGEX_NEWLINE_CRLF, + 0, + NULL); + g_assert (r != NULL); + + g_regex_match_full (r, response, -1, 0, 0, &match_info, &inner_error); + if (inner_error) + goto out; + + if (!g_match_info_matches (match_info)) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't match CSCB response"); + goto out; + } + + str = g_match_info_fetch (match_info, 1); + if (!g_str_equal (str, "0")) { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't match type of CSCB response: '%s'", str); + goto out; + } + + str = g_match_info_fetch (match_info, 2); + intervals = g_strsplit (str, ",", -1); + for (i = 0; intervals[i]; i++) { + gchar *interval_separator; + + g_strstrip (intervals[i]); + interval_separator = strstr (intervals[i], "-"); + if (interval_separator) { + /* Add an interval */ + gchar *end; + g_autofree gchar *start = NULL; + MMCellBroadcastChannels channels; + + start = g_strdup (intervals[i]); + interval_separator = strstr (start, "-"); + *(interval_separator++) = '\0'; + end = interval_separator; + + if (mm_get_uint_from_str (start, &channels.start) && + mm_get_uint_from_str (end, &channels.end) && + channels.start <= channels.end && + channels.end <= CBS_MAX_CHANNEL) + g_array_append_val (array, channels); + else { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't parse CSCB interval '%s'", intervals[i]); + goto out; + } + } else { + guint channel; + + /* Add single value */ + if (mm_get_uint_from_str (intervals[i], &channel)) { + MMCellBroadcastChannels channels = { + .start = channel, + .end = channel + }; + g_array_append_val (array, channels); + } else { + inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Couldn't parse CSCB value '%s'", intervals[i]); + goto out; + } + } + } + + return g_steal_pointer (&array); + + out: + g_assert (inner_error); + g_propagate_error (error, inner_error); + return NULL; +} + /*************************************************************************/ /* CGATT helpers */ @@ -5200,6 +5304,38 @@ out: /*****************************************************************************/ +gboolean +mm_validate_cbs_channels (GArray *channels, GError **error) +{ + guint i; + + for (i = 0; i < channels->len; i++) { + MMCellBroadcastChannels ch = g_array_index (channels, MMCellBroadcastChannels, i); + + if (ch.end < ch.start) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Invalid channels: End channel smaller than start channel"); + return FALSE; + } + + if (ch.start > CBS_MAX_CHANNEL) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Invalid channels: Start channel %u too large", ch.start); + return FALSE; + } + + if (ch.end > CBS_MAX_CHANNEL) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, + "Invalid channels: End channel %u too large", ch.end); + return FALSE; + } + } + + return TRUE; +} + +/*****************************************************************************/ + gboolean mm_sim_parse_cpol_query_response (const gchar *response, guint *out_index, -- cgit v1.2.3-70-g09d2