core: add helper for parsing and validating the ICCID
This commit is contained in:
committed by
Aleksander Morgado
parent
ac343d390b
commit
11a7e3dfdf
@@ -59,8 +59,8 @@ iccid_read_ready (MMBaseModem *modem,
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
const gchar *p;
|
||||
gchar buf[21];
|
||||
gint i;
|
||||
char *parsed;
|
||||
GError *local = NULL;
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (!response) {
|
||||
@@ -82,34 +82,13 @@ iccid_read_ready (MMBaseModem *modem,
|
||||
return;
|
||||
}
|
||||
|
||||
memset (buf, 0, sizeof (buf));
|
||||
for (i = 0; i < 20; i++) {
|
||||
if (!isdigit (p[i]) && (p[i] != 'F') && (p[i] == 'f')) {
|
||||
g_simple_async_result_set_error (simple,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"CRSM ICCID response contained invalid character '%c'",
|
||||
p[i]);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p[i] == 'F' || p[i] == 'f') {
|
||||
buf[i] = 0;
|
||||
break;
|
||||
}
|
||||
buf[i] = p[i];
|
||||
}
|
||||
|
||||
if (i != 19 && i != 20)
|
||||
g_simple_async_result_set_error (simple,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Invalid +CRSM ICCID response size (was %d, expected 19 or 20)",
|
||||
i);
|
||||
/* Sierra !ICCID response is already character swapped */
|
||||
parsed = mm_3gpp_parse_iccid (p, FALSE, &local);
|
||||
if (parsed)
|
||||
g_simple_async_result_set_op_res_gpointer (simple, parsed, g_free);
|
||||
else
|
||||
g_simple_async_result_set_op_res_gpointer (simple, buf, NULL);
|
||||
g_simple_async_result_take_error (simple, local);
|
||||
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
/*****************************************************************************/
|
||||
|
||||
+2
-64
@@ -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,
|
||||
|
||||
@@ -1522,6 +1522,83 @@ test_cind_response_moto_v3m (void *f, gpointer d)
|
||||
test_cind_results ("Motorola V3m", reply, &expected[0], G_N_ELEMENTS (expected));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* 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 */
|
||||
|
||||
@@ -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++;
|
||||
|
||||
Reference in New Issue
Block a user