diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2018-08-21 16:31:35 +0200 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2018-09-12 17:17:36 +0000 |
commit | 099d54a4bcaf7d71ccda1d42424d5b73ec286911 (patch) | |
tree | 5bccced72ff142676f676b39b5cfe3bb45933a8e | |
parent | eb01914bd0cada5d2ed144d5f3f45fd17722e97c (diff) | |
download | ModemManager-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.c | 41 |
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. |