diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem-qmi.c | 101 | ||||
-rw-r--r-- | src/mm-modem-helpers-qmi.c | 121 | ||||
-rw-r--r-- | src/mm-modem-helpers-qmi.h | 8 |
3 files changed, 192 insertions, 38 deletions
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c index 723be393..cd612795 100644 --- a/src/mm-broadband-modem-qmi.c +++ b/src/mm-broadband-modem-qmi.c @@ -7178,20 +7178,30 @@ out: } static MMFirmwareProperties * -create_firmware_properties_from_pair (FirmwarePair *pair) +create_firmware_properties_from_pair (FirmwarePair *pair, + GError **error) { - gchar *unique_id_str; - MMFirmwareProperties *firmware; + gchar *pri_unique_id_str = NULL; + gchar *modem_unique_id_str = NULL; + MMFirmwareProperties *firmware = NULL; - firmware = mm_firmware_properties_new (MM_FIRMWARE_IMAGE_TYPE_GOBI, pair->build_id); + /* If the string is ASCII, use it without converting to HEX */ + + pri_unique_id_str = mm_qmi_unique_id_to_firmware_unique_id (pair->pri_unique_id, error); + if (!pri_unique_id_str) + goto out; - unique_id_str = mm_utils_bin2hexstr ((const guint8 *)pair->pri_unique_id->data, pair->pri_unique_id->len); - mm_firmware_properties_set_gobi_pri_unique_id (firmware, unique_id_str); - g_free (unique_id_str); + modem_unique_id_str = mm_qmi_unique_id_to_firmware_unique_id (pair->modem_unique_id, error); + if (!modem_unique_id_str) + goto out; + + firmware = mm_firmware_properties_new (MM_FIRMWARE_IMAGE_TYPE_GOBI, pair->build_id); + mm_firmware_properties_set_gobi_pri_unique_id (firmware, pri_unique_id_str); + mm_firmware_properties_set_gobi_modem_unique_id (firmware, modem_unique_id_str); - unique_id_str = mm_utils_bin2hexstr ((const guint8 *)pair->modem_unique_id->data, pair->modem_unique_id->len); - mm_firmware_properties_set_gobi_modem_unique_id (firmware, unique_id_str); - g_free (unique_id_str); +out: + g_free (pri_unique_id_str); + g_free (modem_unique_id_str); return firmware; } @@ -7201,6 +7211,7 @@ get_next_image_info (GTask *task) { MMBroadbandModemQmi *self; FirmwareListPreloadContext *ctx; + GError *error = NULL; self = g_task_get_source_object (task); ctx = g_task_get_task_data (task); @@ -7216,7 +7227,12 @@ get_next_image_info (GTask *task) ctx->pairs = g_list_delete_link (ctx->pairs, ctx->pairs); /* Build firmware properties */ - ctx->current_firmware = create_firmware_properties_from_pair (ctx->current_pair); + ctx->current_firmware = create_firmware_properties_from_pair (ctx->current_pair, &error); + if (!ctx->current_firmware) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } /* Now, load additional optional information for the PRI image */ if (!ctx->skip_image_info) { @@ -7667,21 +7683,21 @@ find_firmware_properties_by_gobi_pri_info_substring (MMBroadbandModemQmi *self, static void firmware_change_current (MMIfaceModemFirmware *_self, - const gchar *unique_id, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self); - QmiMessageDmsSetFirmwarePreferenceInput *input; - FirmwareChangeCurrentContext *ctx; - GTask *task; - QmiClient *client = NULL; - GArray *array; - QmiMessageDmsSetFirmwarePreferenceInputListImage modem_image_id; - QmiMessageDmsSetFirmwarePreferenceInputListImage pri_image_id; - guint8 *tmp; - gsize tmp_len; + const gchar *unique_id, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMBroadbandModemQmi *self; + GTask *task; + FirmwareChangeCurrentContext *ctx; + GError *error = NULL; + QmiClient *client = NULL; + GArray *array; + QmiMessageDmsSetFirmwarePreferenceInput *input = NULL; + QmiMessageDmsSetFirmwarePreferenceInputListImage modem_image_id = { 0 }; + QmiMessageDmsSetFirmwarePreferenceInputListImage pri_image_id = { 0 }; + self = MM_BROADBAND_MODEM_QMI (_self); if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), QMI_SERVICE_DMS, &client, callback, user_data)) @@ -7734,22 +7750,26 @@ firmware_change_current (MMIfaceModemFirmware *_self, } /* Modem image ID */ - tmp_len = 0; - tmp = (guint8 *)mm_utils_hexstr2bin (mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), &tmp_len); modem_image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_MODEM; modem_image_id.build_id = (gchar *)mm_firmware_properties_get_unique_id (ctx->firmware); - modem_image_id.unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len); - g_array_insert_vals (modem_image_id.unique_id, 0, tmp, tmp_len); - g_free (tmp); + modem_image_id.unique_id = mm_firmware_unique_id_to_qmi_unique_id (mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), &error); + if (!modem_image_id.unique_id) { + g_prefix_error (&error, "Couldn't build modem image unique id: "); + g_task_return_error (task, error); + g_object_unref (task); + goto out; + } /* PRI image ID */ - tmp_len = 0; - tmp = (guint8 *)mm_utils_hexstr2bin (mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), &tmp_len); pri_image_id.type = QMI_DMS_FIRMWARE_IMAGE_TYPE_PRI; pri_image_id.build_id = (gchar *)mm_firmware_properties_get_unique_id (ctx->firmware); - pri_image_id.unique_id = g_array_sized_new (FALSE, FALSE, sizeof (guint8), tmp_len); - g_array_insert_vals (pri_image_id.unique_id, 0, tmp, tmp_len); - g_free (tmp); + pri_image_id.unique_id = mm_firmware_unique_id_to_qmi_unique_id (mm_firmware_properties_get_gobi_pri_unique_id (ctx->firmware), &error); + if (!pri_image_id.unique_id) { + g_prefix_error (&error, "Couldn't build PRI image unique id: "); + g_task_return_error (task, error); + g_object_unref (task); + goto out; + } mm_dbg ("Changing Gobi firmware to MODEM '%s' and PRI '%s' with Build ID '%s'...", mm_firmware_properties_get_gobi_modem_unique_id (ctx->firmware), @@ -7770,9 +7790,14 @@ firmware_change_current (MMIfaceModemFirmware *_self, NULL, (GAsyncReadyCallback)firmware_select_stored_image_ready, task); - g_array_unref (modem_image_id.unique_id); - g_array_unref (pri_image_id.unique_id); - qmi_message_dms_set_firmware_preference_input_unref (input); + +out: + if (modem_image_id.unique_id) + g_array_unref (modem_image_id.unique_id); + if (pri_image_id.unique_id) + g_array_unref (pri_image_id.unique_id); + if (input) + qmi_message_dms_set_firmware_preference_input_unref (input); } /*****************************************************************************/ 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; +} diff --git a/src/mm-modem-helpers-qmi.h b/src/mm-modem-helpers-qmi.h index a51c4f66..5c0200e4 100644 --- a/src/mm-modem-helpers-qmi.h +++ b/src/mm-modem-helpers-qmi.h @@ -138,4 +138,12 @@ typedef struct { MMModemCapability mm_modem_capability_from_qmi_capabilities_context (MMQmiCapabilitiesContext *ctx); +/*****************************************************************************/ +/* QMI unique id manipulation */ + +gchar *mm_qmi_unique_id_to_firmware_unique_id (GArray *qmi_unique_id, + GError **error); +GArray *mm_firmware_unique_id_to_qmi_unique_id (const gchar *unique_id, + GError **error); + #endif /* MM_MODEM_HELPERS_QMI_H */ |