aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-modem-helpers.c82
-rw-r--r--src/mm-modem-helpers.h2
-rw-r--r--src/mm-sim.c66
-rw-r--r--src/tests/test-modem-helpers.c84
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++;