aboutsummaryrefslogtreecommitdiff
path: root/src/mm-modem-helpers.c
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-03-25 13:20:13 -0500
committerDan Williams <dcbw@redhat.com>2013-03-27 08:23:52 -0500
commit3b3326bdf03a02822ac8d1e9e0ff08db2324c3ed (patch)
tree207615827c0f252c27a2f6c210283cb8edb88b6f /src/mm-modem-helpers.c
parentf299a05571f8d9b9f0bf996f20563ed9a13dab02 (diff)
broadband-modem: parse +GSN response for IMEI, MEID, and ESN (bgo #696596)
+GSN response differs widely between modems. Some prefix the MEID and/or ESN with 0x, some have leading zeros, some return the MEID and the ESN, and some append the serial number to the end of the IMEI. Handle that and make the ESN, MEID, IMEI, and EquipmentIdentifier parsing consistent.
Diffstat (limited to 'src/mm-modem-helpers.c')
-rw-r--r--src/mm-modem-helpers.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index cedd2b7f..b20ff1c6 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -2100,3 +2100,124 @@ mm_cdma_normalize_band (const gchar *long_band,
/* Unknown/not registered */
return 'Z';
}
+
+/*************************************************************************/
+
+/* Caller must strip any "+GSN:" or "+CGSN" from @gsn */
+gboolean
+mm_parse_gsn (const char *gsn,
+ gchar **out_imei,
+ gchar **out_meid,
+ gchar **out_esn)
+{
+ gchar **items, **iter;
+ gchar *meid = NULL, *esn = NULL, *imei = NULL, *p;
+ gboolean success = FALSE;
+
+ if (!gsn || !gsn[0])
+ return FALSE;
+
+ /* IMEI is 15 numeric digits */
+
+ /* ESNs take one of two formats:
+ * (1) 7 or 8 hexadecimal digits
+ * (2) 10 or 11 decimal digits
+ *
+ * In addition, leading zeros may be present or absent, and hexadecimal
+ * ESNs may or may not be prefixed with "0x".
+ */
+
+ /* MEIDs take one of two formats:
+ * (1) 14 hexadecimal digits, sometimes padded to 16 digits with leading zeros
+ * (2) 18 decimal digits
+ *
+ * As with ESNs, leading zeros may be present or absent, and hexadecimal
+ * MEIDs may or may not be prefixed with "0x".
+ */
+
+ items = g_strsplit_set (gsn, "\r\n\t: ,", 0);
+ for (iter = items; iter && *iter && (!esn || !meid); iter++) {
+ gboolean expect_hex = FALSE, is_hex, is_digit;
+ gchar *s = *iter;
+ guint len = 0;
+
+ if (!s[0])
+ continue;
+
+ if (g_str_has_prefix (s, "0x") || g_str_has_prefix (s, "0X")) {
+ expect_hex = TRUE;
+ s += 2;
+
+ /* Skip any leading zeros */
+ while (*s == '0')
+ s++;
+ }
+
+ /* Check whether all digits are hex or decimal */
+ is_hex = is_digit = TRUE;
+ p = s;
+ while (*p && (is_hex || is_digit)) {
+ if (!g_ascii_isxdigit (*p))
+ is_hex = FALSE;
+ if (!g_ascii_isdigit (*p))
+ is_digit = FALSE;
+ p++, len++;
+ }
+
+ /* Note that some hex strings are also valid digit strings */
+
+ if (is_hex) {
+ if (len == 7 || len == 8) {
+ /* ESN */
+ if (!esn) {
+ if (len == 7)
+ esn = g_strdup_printf ("0%s", s);
+ else
+ esn = g_strdup (s);
+ }
+ } else if (len == 14) {
+ /* MEID */
+ if (!meid)
+ meid = g_strdup (s);
+ }
+ }
+
+ if (is_digit) {
+ if (!is_hex)
+ g_warn_if_fail (expect_hex == FALSE);
+
+ if (len == 15) {
+ if (!imei)
+ imei = g_strdup (s);
+ }
+
+ /* Decimal ESN/MEID unhandled for now; conversion from decimal to
+ * hex isn't a straight dec->hex conversion, as the first 2 digits
+ * of the ESN and first 3 digits of the MEID are the manufacturer
+ * identifier and must be converted separately from serial number
+ * and then concatenated with it.
+ */
+ }
+ }
+ g_strfreev (items);
+
+ success = meid || esn || imei;
+
+ if (out_imei)
+ *out_imei = imei;
+ else
+ g_free (imei);
+
+ if (out_meid)
+ *out_meid = meid;
+ else
+ g_free (meid);
+
+ if (out_esn)
+ *out_esn = esn;
+ else
+ g_free (esn);
+
+ return success;
+}
+