aboutsummaryrefslogtreecommitdiff
path: root/src/mm-modem-helpers-qmi.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-09-16 14:45:10 +0200
committerAleksander Morgado <aleksander@aleksander.es>2019-10-11 08:16:04 +0000
commit6977b41adb6adaad4a7fe00d34bd2a0eb82d46d1 (patch)
tree07e2389c04e6208f37c45f2662cdc415b46393ef /src/mm-modem-helpers-qmi.c
parenta55543d11e2eb4fa4114932573e6a84656bc99ea (diff)
broadband-modem-qmi: prefer ASCII unique IDs
If the manufacturer uses QMI unique IDs in ASCII, use the same format in our APIs, instead of blindly converting them to a 16-byte HEX string. This makes user operations much nicer, e.g. instead of: $ sudo mmcli -m 0 --firmware-list ---------------- Firmware | list: 02.20.03.00_GENERIC | current: yes | gobi pri unique id: 3030322E3031375F3030300000000000 | gobi modem unique id: 3F5F3F00000000000000000000000000 | 02.14.03.02_SPRINT | current: no | gobi pri unique id: 3030322E3031325F3030310000000000 | gobi modem unique id: 3F5F3F00000000000000000000000000 | 02.20.03.22_VERIZON | current: no | gobi pri unique id: 3030322E3032365F3030300000000000 | gobi modem unique id: 3F5F3F00000000000000000000000000 | 02.14.03.00_VODAFONE | current: no | gobi pri unique id: 3030302E3030385F3030300000000000 | gobi modem unique id: 3F5F3F00000000000000000000000000 We will have: $ sudo mmcli -m 1 --firmware-list ---------------- Firmware | list: 02.20.03.00_GENERIC | current: no | gobi pri unique id: 002.017_000 | gobi modem unique id: ?_? | 02.14.03.02_SPRINT | current: no | gobi pri unique id: 002.012_001 | gobi modem unique id: ?_? | 02.20.03.22_VERIZON | current: yes | gobi pri unique id: 002.026_000 | gobi modem unique id: ?_? | 02.14.03.00_VODAFONE | current: no | gobi pri unique id: 000.008_000 | gobi modem unique id: ?_?
Diffstat (limited to 'src/mm-modem-helpers-qmi.c')
-rw-r--r--src/mm-modem-helpers-qmi.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/mm-modem-helpers-qmi.c b/src/mm-modem-helpers-qmi.c
index ef6e0483..c8f5e0b2 100644
--- a/src/mm-modem-helpers-qmi.c
+++ b/src/mm-modem-helpers-qmi.c
@@ -20,6 +20,7 @@
#include <mm-errors-types.h>
#include "mm-modem-helpers-qmi.h"
+#include "mm-modem-helpers.h"
#include "mm-enums-types.h"
#include "mm-log.h"
@@ -1588,6 +1589,8 @@ mm_oma_session_state_failed_reason_from_qmi_oma_session_failed_reason (QmiOmaSes
}
}
+/*****************************************************************************/
+
gboolean
mm_error_from_qmi_loc_indication_status (QmiLocIndicationStatus status,
GError **error)
@@ -1618,3 +1621,121 @@ mm_error_from_qmi_loc_indication_status (QmiLocIndicationStatus status,
return FALSE;
}
}
+
+/*****************************************************************************/
+/* Convert between firmware unique ID (string) and QMI unique ID (16 bytes)
+ *
+ * The unique ID coming in the QMI message is a fixed-size 16 byte array, and its
+ * format really depends on the manufacturer. But, if the manufacturer is nice enough
+ * to use ASCII for this field, just use it ourselves as well, no need to obfuscate
+ * the information we expose in our interfaces.
+ *
+ * We also need to do the conversion in the other way around, because when
+ * selecting a new image to run we need to provide the QMI unique ID.
+ */
+
+#define EXPECTED_QMI_UNIQUE_ID_LENGTH 16
+
+gchar *
+mm_qmi_unique_id_to_firmware_unique_id (GArray *qmi_unique_id,
+ GError **error)
+{
+ gint i;
+ gboolean expect_nul_byte = FALSE;
+
+ if (qmi_unique_id->len != EXPECTED_QMI_UNIQUE_ID_LENGTH) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "unexpected QMI unique ID length: %u (expected: %u)",
+ qmi_unique_id->len, EXPECTED_QMI_UNIQUE_ID_LENGTH);
+ return NULL;
+ }
+
+ for (i = 0; i < qmi_unique_id->len; i++) {
+ guint8 val;
+
+ val = g_array_index (qmi_unique_id, guint8, i);
+
+ /* Check for ASCII chars */
+ if (g_ascii_isprint ((gchar) val)) {
+ /* Halt iteration if we found an ASCII char after a NUL byte */
+ if (expect_nul_byte)
+ break;
+
+ /* good char */
+ continue;
+ }
+
+ /* Allow NUL bytes at the end of the array */
+ if (val == '\0' && i > 0) {
+ if (!expect_nul_byte)
+ expect_nul_byte = TRUE;
+ continue;
+ }
+
+ /* Halt iteration, not something we can build as ASCII */
+ break;
+ }
+
+ if (i != qmi_unique_id->len)
+ return mm_utils_bin2hexstr ((const guint8 *)qmi_unique_id->data, qmi_unique_id->len);
+
+ return g_strndup ((const gchar *)qmi_unique_id->data, qmi_unique_id->len);
+}
+
+GArray *
+mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id,
+ GError **error)
+{
+ guint len;
+ GArray *qmi_unique_id;
+
+ len = strlen (unique_id);
+
+ /* The length will be exactly EXPECTED_QMI_UNIQUE_ID_LENGTH*2 if given in HEX */
+ if (len == (2 * EXPECTED_QMI_UNIQUE_ID_LENGTH)) {
+ guint8 *tmp;
+ gsize tmp_len;
+ guint i;
+
+ for (i = 0; i < len; i++) {
+ if (!g_ascii_isxdigit (unique_id[i])) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unexpected character found in unique id (not HEX): %c", unique_id[i]);
+ return NULL;
+ }
+ }
+
+ tmp_len = 0;
+ tmp = (guint8 *) mm_utils_hexstr2bin (unique_id, &tmp_len);
+ g_assert (tmp_len == EXPECTED_QMI_UNIQUE_ID_LENGTH);
+
+ qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len);
+ g_array_insert_vals (qmi_unique_id, 0, tmp, tmp_len);
+ g_free (tmp);
+ return qmi_unique_id;
+ }
+
+ /* The length will be EXPECTED_QMI_UNIQUE_ID_LENGTH or less if given in ASCII */
+ if (len > 0 && len <= EXPECTED_QMI_UNIQUE_ID_LENGTH) {
+ guint i;
+
+ for (i = 0; i < len; i++) {
+ if (!g_ascii_isprint (unique_id[i])) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unexpected character found in unique id (not ASCII): %c", unique_id[i]);
+ return NULL;
+ }
+ }
+
+ qmi_unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), EXPECTED_QMI_UNIQUE_ID_LENGTH);
+ g_array_set_size (qmi_unique_id, EXPECTED_QMI_UNIQUE_ID_LENGTH);
+ memcpy (&qmi_unique_id->data[0], unique_id, len);
+ if (len < EXPECTED_QMI_UNIQUE_ID_LENGTH)
+ memset (&qmi_unique_id->data[len], 0, EXPECTED_QMI_UNIQUE_ID_LENGTH - len);
+ return qmi_unique_id;
+ }
+
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unexpected unique id length: %u", len);
+ return NULL;
+}