diff options
author | Ben Chan <benchan@chromium.org> | 2018-10-11 11:36:00 -0700 |
---|---|---|
committer | Ben Chan <benchan@chromium.org> | 2018-10-26 09:50:01 -0700 |
commit | 055177fdf0b9cc461920bf0c488fab461d1ced06 (patch) | |
tree | f893f068cb53ae2e5a3dea7821fe223fef852b8b /src | |
parent | 942bdeaec26eb587f39e9709dff0174bc4bfdd42 (diff) |
sim-qmi: use QMI UIM service to read ICCID if needed
If a QMI modem doesn't support the deprecated DMS_UIM_GET_ICCID command,
use the UIM_READ_TRANSPARENT command to read EFiccid on the SIM to
determine the ICCID.
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-sim-qmi.c | 166 |
1 files changed, 159 insertions, 7 deletions
diff --git a/src/mm-sim-qmi.c b/src/mm-sim-qmi.c index e8c0afef..e7b90d70 100644 --- a/src/mm-sim-qmi.c +++ b/src/mm-sim-qmi.c @@ -91,6 +91,106 @@ ensure_qmi_client (GTask *task, /*****************************************************************************/ /* Load SIM ID (ICCID) */ +static GArray * +uim_read_finish (QmiClientUim *client, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +uim_read_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + QmiMessageUimReadTransparentOutput *output; + GError *error = NULL; + + output = qmi_client_uim_read_transparent_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + } else if (!qmi_message_uim_read_transparent_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't read data from UIM: "); + g_task_return_error (task, error); + } else { + GArray *read_result = NULL; + + qmi_message_uim_read_transparent_output_get_read_result (output, &read_result, NULL); + if (read_result) + g_task_return_pointer (task, + g_array_ref (read_result), + (GDestroyNotify) g_array_unref); + else + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "Read malformed data from UIM"); + } + + if (output) + qmi_message_uim_read_transparent_output_unref (output); + + g_object_unref (task); +} + +static void +uim_read (MMSimQmi *self, + guint16 file_id, + const guint16 *file_path, + gsize file_path_len, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + QmiClient *client = NULL; + GArray *file_path_bytes; + gsize i; + QmiMessageUimReadTransparentInput *input; + + task = g_task_new (self, NULL, callback, user_data); + + if (!ensure_qmi_client (task, + self, + QMI_SERVICE_UIM, &client)) + return; + + file_path_bytes = g_array_sized_new (FALSE, FALSE, 1, file_path_len * 2); + for (i = 0; i < file_path_len; ++i) { + guint8 byte; + + byte = file_path[i] & 0xFF; + g_array_append_val (file_path_bytes, byte); + byte = (file_path[i] >> 8) & 0xFF; + g_array_append_val (file_path_bytes, byte); + } + + input = qmi_message_uim_read_transparent_input_new (); + qmi_message_uim_read_transparent_input_set_session_information ( + input, + QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING, + "", + NULL); + qmi_message_uim_read_transparent_input_set_file (input, + file_id, + file_path_bytes, + NULL); + qmi_message_uim_read_transparent_input_set_read_information (input, + 0, + 0, + NULL); + g_array_unref (file_path_bytes); + + qmi_client_uim_read_transparent (QMI_CLIENT_UIM (client), + input, + 10, + NULL, + (GAsyncReadyCallback)uim_read_ready, + task); + qmi_message_uim_read_transparent_input_unref (input); +} + static gchar * load_sim_identifier_finish (MMBaseSim *self, GAsyncResult *res, @@ -100,6 +200,44 @@ load_sim_identifier_finish (MMBaseSim *self, } static void +uim_get_iccid_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) +{ + GError *error = NULL; + GArray *read_result; + gchar *iccid; + + read_result = uim_read_finish (client, res, &error); + if (!read_result) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + iccid = mm_bcd_to_string ((const guint8 *) read_result->data, read_result->len); + g_assert (iccid); + g_task_return_pointer (task, iccid, g_free); + g_object_unref (task); + + g_array_unref (read_result); +} + +static void +uim_get_iccid (MMSimQmi *self, + GTask *task) +{ + static const guint16 file_path[] = { 0x3F00 }; + + uim_read (self, + 0x2FE2, + file_path, + G_N_ELEMENTS (file_path), + (GAsyncReadyCallback)uim_get_iccid_ready, + task); +} + +static void dms_uim_get_iccid_ready (QmiClientDms *client, GAsyncResult *res, GTask *task) @@ -128,20 +266,16 @@ dms_uim_get_iccid_ready (QmiClientDms *client, } static void -load_sim_identifier (MMBaseSim *self, - GAsyncReadyCallback callback, - gpointer user_data) +dms_uim_get_iccid (MMSimQmi *self, + GTask *task) { - GTask *task; QmiClient *client = NULL; - task = g_task_new (self, NULL, callback, user_data); if (!ensure_qmi_client (task, - MM_SIM_QMI (self), + self, QMI_SERVICE_DMS, &client)) return; - mm_dbg ("loading SIM identifier..."); qmi_client_dms_uim_get_iccid (QMI_CLIENT_DMS (client), NULL, 5, @@ -150,6 +284,24 @@ load_sim_identifier (MMBaseSim *self, task); } +static void +load_sim_identifier (MMBaseSim *_self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMSimQmi *self; + GTask *task; + + self = MM_SIM_QMI (_self); + task = g_task_new (self, NULL, callback, user_data); + + mm_dbg ("loading SIM identifier..."); + if (!self->priv->dms_uim_deprecated) + dms_uim_get_iccid (self, task); + else + uim_get_iccid (self, task); +} + /*****************************************************************************/ /* Load IMSI */ |