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: ?_?
This commit is contained in:
@@ -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;
|
||||
|
||||
/* 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;
|
||||
|
||||
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->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);
|
||||
|
||||
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)
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user