summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2018-08-21 16:31:35 +0200
committerDan Williams <dcbw@redhat.com>2018-09-12 17:17:36 +0000
commit099d54a4bcaf7d71ccda1d42424d5b73ec286911 (patch)
tree5bccced72ff142676f676b39b5cfe3bb45933a8e
parenteb01914bd0cada5d2ed144d5f3f45fd17722e97c (diff)
downloadModemManager-099d54a4bcaf7d71ccda1d42424d5b73ec286911.tar.gz
helpers: allow [A-F] range in operator-specific ICCID account number
There are operators (e.g. the Chinese CMCC operator) that abuse the fact that 4 bits are used to store the BCD encoded numbers, and also use the [A-F] range as valid characters for the ICCID in the operator specific account number part. Haven't seen any documentation where this format with [A-F] characters is explicitly allowed, but I have seen multiple real cases where it happens. E.g.: 898602F9091830030220 898602C0123456789012 This patch also removes the 'last F' validation, used when reading 19-digit ICCIDs with +CRSM, as it no longer applies.
-rw-r--r--src/mm-modem-helpers.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 70c6cc51c..5e3f5c0c0 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -3500,14 +3500,21 @@ mm_3gpp_get_ip_family_from_pdp_type (const gchar *pdp_type)
}
/*************************************************************************/
-
+/* ICCID validation */
+/*
+ * 89: telecom (2 digits)
+ * cc: country (2 digits)
+ * oo: operator (2 digits)
+ * aaaaaaaaaaaaa: operator-specific account number (13 digits)
+ * x: checksum (1 digit)
+ */
char *
mm_3gpp_parse_iccid (const char *raw_iccid, GError **error)
{
gboolean swap;
char *buf, *swapped = NULL;
gsize len = 0;
- int f_pos = -1, i;
+ int i;
g_return_val_if_fail (raw_iccid != NULL, NULL);
@@ -3518,13 +3525,20 @@ mm_3gpp_parse_iccid (const char *raw_iccid, GError **error)
/* Make sure the buffer is only digits or 'F' */
buf = g_strdup (raw_iccid);
for (len = 0; buf[len]; len++) {
- if (isdigit (buf[len]))
+ /* Digit values allowed anywhere */
+ if (g_ascii_isdigit (buf[len]))
continue;
- if (buf[len] == 'F' || buf[len] == 'f') {
- buf[len] = 'F'; /* canonicalize the F */
- f_pos = len;
+
+ /* There are operators (e.g. the Chinese CMCC operator) that abuse the
+ * fact that 4 bits are used to store the BCD encoded numbers, and also
+ * use the [A-F] range as valid characters for the ICCID. Explicitly
+ * allow this range in the operator-specific part. */
+ if (len >= 6 && g_ascii_isxdigit (buf[len])) {
+ /* canonicalize hex digit */
+ buf[len] = g_ascii_toupper (buf[len]);
continue;
}
+
if (buf[len] == '\"') {
buf[len] = 0;
break;
@@ -3532,8 +3546,8 @@ mm_3gpp_parse_iccid (const char *raw_iccid, GError **error)
/* Invalid character */
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
- "ICCID response contained invalid character '%c'",
- buf[len]);
+ "ICCID response contained invalid character '%c' at index '%zu'",
+ buf[len], len);
goto error;
}
@@ -3568,17 +3582,6 @@ mm_3gpp_parse_iccid (const char *raw_iccid, GError **error)
goto error;
}
- /* Ensure if there's an 'F' that it's second-to-last if swap = TRUE,
- * otherwise last if swap = FALSE. Also fail if an F is found within a
- * 19-digit reported ICCID. */
- if (f_pos >= 0) {
- if ((len != 20) || (swap && (f_pos != len - 2)) || (!swap && (f_pos != len - 1))) {
- g_set_error_literal (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
- "Invalid ICCID length (unexpected F position)");
- goto error;
- }
- }
-
if (swap) {
/* Swap digits in the ICCID response to get the actual ICCID, each
* group of 2 digits is reversed.