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.
This commit is contained in:
committed by
Dan Williams
parent
eb01914bd0
commit
099d54a4bc
+22
-19
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user