diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-modem-helpers.c | 82 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 2 | ||||
-rw-r--r-- | src/mm-sim.c | 66 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 84 |
4 files changed, 170 insertions, 64 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, diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h index a1f12329..355453a5 100644 --- a/src/mm-modem-helpers.h +++ b/src/mm-modem-helpers.h @@ -204,6 +204,8 @@ gboolean mm_3gpp_parse_operator_id (const gchar *operator_id, const gchar *mm_3gpp_get_pdp_type_from_ip_family (MMBearerIpFamily family); MMBearerIpFamily 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); + /*****************************************************************************/ /* CDMA specific helpers and utilities */ /*****************************************************************************/ diff --git a/src/mm-sim.c b/src/mm-sim.c index 3e1ca46c..b2b011be 100644 --- a/src/mm-sim.c +++ b/src/mm-sim.c @@ -946,7 +946,6 @@ parse_iccid (const gchar *response, GError **error) { gchar buf[21]; - gchar swapped[21]; const gchar *str; gint sw1; gint sw2; @@ -974,69 +973,8 @@ parse_iccid (const gchar *response, (sw1 == 0x91) || (sw1 == 0x92) || (sw1 == 0x9f)) { - gsize len = 0; - gint f_pos = -1; - gint i; - - /* Make sure the buffer is only digits or 'F' */ - for (len = 0; len < sizeof (buf) && 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, - "CRSM ICCID response contained invalid character '%c'", - buf[len]); - return NULL; - } - - /* BCD encoded ICCIDs are 20 digits long */ - if (len != 20) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Invalid +CRSM ICCID response size (was %zd, expected 20)", - len); - return NULL; - } - - /* Ensure if there's an 'F' that it's second-to-last */ - if ((f_pos >= 0) && (f_pos != len - 2)) { - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Invalid +CRSM ICCID length (unexpected F)"); - return NULL; - } - - /* Swap digits in the EFiccid response to get the actual ICCID, each - * group of 2 digits is reversed in the +CRSM response. i.e.: - * - * 21436587 -> 12345678 - */ - memset (swapped, 0, sizeof (swapped)); - for (i = 0; i < 10; i++) { - swapped[i * 2] = buf[(i * 2) + 1]; - swapped[(i * 2) + 1] = buf[i * 2]; - } - - /* Zero out the F for 19 digit ICCIDs */ - if (swapped[len - 1] == 'F') - swapped[len - 1] = 0; - - - return g_strdup (swapped); + /* +CRSM response must be character-swapped */ + return mm_3gpp_parse_iccid (buf, TRUE, error); } else { g_set_error (error, MM_CORE_ERROR, diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c index b8cd2d44..28d9b12a 100644 --- a/src/tests/test-modem-helpers.c +++ b/src/tests/test-modem-helpers.c @@ -1523,6 +1523,83 @@ test_cind_response_moto_v3m (void *f, gpointer d) } /*****************************************************************************/ +/* Test ICCID parsing */ + +static void +test_iccid_parse_quoted_swap_19_digit (void *f, gpointer d) +{ + const char *raw_iccid = "\"984402003576012594F9\""; + const char *expected = "8944200053671052499"; + char *parsed; + GError *error = NULL; + + parsed = mm_3gpp_parse_iccid (raw_iccid, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (parsed, ==, expected); +} + +static void +test_iccid_parse_unquoted_swap_20_digit (void *f, gpointer d) +{ + const char *raw_iccid = "98231420326409614067"; + const char *expected = "89324102234690160476"; + char *parsed; + GError *error = NULL; + + parsed = mm_3gpp_parse_iccid (raw_iccid, TRUE, &error); + g_assert_no_error (error); + g_assert_cmpstr (parsed, ==, expected); +} + +static void +test_iccid_parse_unquoted_unswapped_19_digit (void *f, gpointer d) +{ + const char *raw_iccid = "8944200053671052499F"; + const char *expected = "8944200053671052499"; + char *parsed; + GError *error = NULL; + + parsed = mm_3gpp_parse_iccid (raw_iccid, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (parsed, ==, expected); +} + +static void +test_iccid_parse_quoted_unswapped_20_digit (void *f, gpointer d) +{ + const char *raw_iccid = "\"89324102234690160476\""; + const char *expected = "89324102234690160476"; + char *parsed; + GError *error = NULL; + + parsed = mm_3gpp_parse_iccid (raw_iccid, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (parsed, ==, expected); +} + +static void +test_iccid_parse_short (void *f, gpointer d) +{ + const char *raw_iccid = "982314203264096"; + char *parsed; + GError *error = NULL; + + parsed = mm_3gpp_parse_iccid (raw_iccid, TRUE, &error); + g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); +} + +static void +test_iccid_parse_invalid_chars (void *f, gpointer d) +{ + const char *raw_iccid = "98231420326ab9614067"; + char *parsed; + GError *error = NULL; + + parsed = mm_3gpp_parse_iccid (raw_iccid, TRUE, &error); + g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); +} + +/*****************************************************************************/ /* Test CGDCONT test responses */ static void @@ -2315,6 +2392,13 @@ int main (int argc, char **argv) g_test_suite_add (suite, TESTCASE (test_cind_response_linktop_lw273, NULL)); g_test_suite_add (suite, TESTCASE (test_cind_response_moto_v3m, NULL)); + g_test_suite_add (suite, TESTCASE (test_iccid_parse_quoted_swap_19_digit, NULL)); + g_test_suite_add (suite, TESTCASE (test_iccid_parse_unquoted_swap_20_digit, NULL)); + g_test_suite_add (suite, TESTCASE (test_iccid_parse_unquoted_unswapped_19_digit, NULL)); + g_test_suite_add (suite, TESTCASE (test_iccid_parse_quoted_unswapped_20_digit, NULL)); + g_test_suite_add (suite, TESTCASE (test_iccid_parse_short, NULL)); + g_test_suite_add (suite, TESTCASE (test_iccid_parse_invalid_chars, NULL)); + while (item->devid) { g_test_suite_add (suite, TESTCASE (test_devid_item, (gconstpointer) item)); item++; |