diff options
author | Dan Williams <dcbw@redhat.com> | 2013-09-09 13:00:43 -0500 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2013-09-10 09:42:36 +0200 |
commit | 11a7e3dfdf0642c451bfd7c214f4b52640ef661a (patch) | |
tree | 1d51d13aeb7ffc5383b65969dabfa7086a8e1269 /src/mm-modem-helpers.c | |
parent | ac343d390ba804ebd58c5477f45c69c1b8402edd (diff) |
core: add helper for parsing and validating the ICCID
Diffstat (limited to 'src/mm-modem-helpers.c')
-rw-r--r-- | src/mm-modem-helpers.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c index 95d74dc1..cf80f07b 100644 --- a/src/mm-modem-helpers.c +++ b/src/mm-modem-helpers.c @@ -1891,6 +1891,88 @@ mm_3gpp_get_ip_family_from_pdp_type (const gchar *pdp_type) /*************************************************************************/ +char * +mm_3gpp_parse_iccid (const char *raw_iccid, gboolean swap, GError **error) +{ + char *buf, *swapped = NULL; + gsize len = 0; + int f_pos = -1, i; + + g_return_val_if_fail (raw_iccid != NULL, NULL); + + /* Skip spaces and quotes */ + while (raw_iccid && *raw_iccid && (isspace (*raw_iccid) || *raw_iccid == '"')) + raw_iccid++; + + /* Make sure the buffer is only digits or 'F' */ + buf = g_strdup (raw_iccid); + for (len = 0; buf[len]; len++) { + if (isdigit (buf[len])) + continue; + if (buf[len] == 'F' || buf[len] == 'f') { + buf[len] = 'F'; /* canonicalize the F */ + f_pos = len; + continue; + } + if (buf[len] == '\"') { + buf[len] = 0; + break; + } + + /* Invalid character */ + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "ICCID response contained invalid character '%c'", + buf[len]); + goto error; + } + + /* BCD encoded ICCIDs are 20 digits long */ + if (len != 20) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "Invalid ICCID response size (was %zd, expected 20)", + len); + goto error; + } + + /* Ensure if there's an 'F' that it's second-to-last if swap = TRUE, + * otherwise last if swap = FALSE */ + if (f_pos >= 0) { + if ((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. + * + * 21436587 -> 12345678 + */ + swapped = g_malloc0 (25); + for (i = 0; i < 10; i++) { + swapped[i * 2] = buf[(i * 2) + 1]; + swapped[(i * 2) + 1] = buf[i * 2]; + } + } else + swapped = g_strdup (buf); + + /* Zero out the F for 19 digit ICCIDs */ + if (swapped[len - 1] == 'F') + swapped[len - 1] = 0; + + g_free (buf); + return swapped; + +error: + g_free (buf); + g_free (swapped); + return NULL; +} + +/*************************************************************************/ + gboolean mm_3gpp_parse_operator_id (const gchar *operator_id, guint16 *mcc, |