[PATCH 1/3] broadband-modem-qmi: implement unlock retries loading with UIM service
Aleksander Morgado
aleksander at aleksander.es
Sat Jan 30 20:14:23 PST 2016
Newer modems like the MC7455 don't implement the "DMS UIM" commands in the
DMS service, and therefore these modems need to use the UIM service directly.
---
src/mm-broadband-modem-qmi.c | 357 ++++++++++++++++++++++++++++---------------
1 file changed, 236 insertions(+), 121 deletions(-)
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c
index b5cf403..bd6e2a8 100644
--- a/src/mm-broadband-modem-qmi.c
+++ b/src/mm-broadband-modem-qmi.c
@@ -1467,13 +1467,16 @@ modem_load_unlock_required_finish (MMIfaceModem *self,
static void load_unlock_required_context_step (LoadUnlockRequiredContext *ctx);
-static void
-uim_get_card_status_ready (QmiClientUim *client,
- GAsyncResult *res,
- LoadUnlockRequiredContext *ctx)
+/* Used also when loading unlock retries left */
+static gboolean
+uim_get_card_status_output_parse (QmiMessageUimGetCardStatusOutput *output,
+ MMModemLock *o_lock,
+ guint *o_pin1_retries,
+ guint *o_puk1_retries,
+ guint *o_pin2_retries,
+ guint *o_puk2_retries,
+ GError **error)
{
- QmiMessageUimGetCardStatusOutput *output;
- GError *error = NULL;
GArray *cards;
QmiMessageUimGetCardStatusOutputCardStatusCardsElement *card;
QmiMessageUimGetCardStatusOutputCardStatusCardsElementApplicationsElement *app;
@@ -1489,20 +1492,9 @@ uim_get_card_status_ready (QmiClientUim *client,
* purposes, we're going to consider as the SIM to use the first card present
* with a SIM/USIM application. */
- output = qmi_client_uim_get_card_status_finish (client, res, &error);
- if (!output) {
- g_prefix_error (&error, "QMI operation failed: ");
- g_simple_async_result_take_error (ctx->result, error);
- load_unlock_required_context_complete_and_free (ctx);
- return;
- }
-
- if (!qmi_message_uim_get_card_status_output_get_result (output, &error)) {
- g_prefix_error (&error, "QMI operation failed: ");
- g_simple_async_result_take_error (ctx->result, error);
- qmi_message_uim_get_card_status_output_unref (output);
- load_unlock_required_context_complete_and_free (ctx);
- return;
+ if (!qmi_message_uim_get_card_status_output_get_result (output, error)) {
+ g_prefix_error (error, "QMI operation failed: ");
+ return FALSE;
}
qmi_message_uim_get_card_status_output_get_card_status (
@@ -1515,11 +1507,9 @@ uim_get_card_status_ready (QmiClientUim *client,
NULL);
if (cards->len == 0) {
- g_simple_async_result_set_error (ctx->result, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
- "No cards reported");
- qmi_message_uim_get_card_status_output_unref (output);
- load_unlock_required_context_complete_and_free (ctx);
- return;
+ g_set_error (error, QMI_CORE_ERROR, QMI_CORE_ERROR_FAILED,
+ "No cards reported");
+ return FALSE;
}
if (cards->len > 1)
@@ -1598,24 +1588,22 @@ uim_get_card_status_ready (QmiClientUim *client,
if (card_i < 0 || application_j < 0) {
/* If not a single card found, report SIM not inserted */
if (n_absent > 0 && !n_error && !n_invalid)
- g_simple_async_result_set_error (ctx->result,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED,
- "No card found");
+ g_set_error (error,
+ MM_MOBILE_EQUIPMENT_ERROR,
+ MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED,
+ "No card found");
else if (n_error > 0)
- g_simple_async_result_set_error (ctx->result,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG,
- "Card error");
+ g_set_error (error,
+ MM_MOBILE_EQUIPMENT_ERROR,
+ MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG,
+ "Card error");
else
- g_simple_async_result_set_error (ctx->result,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE,
- "Card failure: %u absent, %u errors, %u invalid",
- n_absent, n_error, n_invalid);
- qmi_message_uim_get_card_status_output_unref (output);
- load_unlock_required_context_complete_and_free (ctx);
- return;
+ g_set_error (error,
+ MM_MOBILE_EQUIPMENT_ERROR,
+ MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE,
+ "Card failure: %u absent, %u errors, %u invalid",
+ n_absent, n_error, n_invalid);
+ return FALSE;
}
/* Get card/app to use */
@@ -1630,27 +1618,36 @@ uim_get_card_status_ready (QmiClientUim *client,
app->state != QMI_UIM_CARD_APPLICATION_STATE_PUK1_OR_UPIN_PUK_REQUIRED &&
app->state != QMI_UIM_CARD_APPLICATION_STATE_PIN1_BLOCKED) {
g_debug ("Neither SIM nor USIM are ready");
- g_simple_async_result_set_error (ctx->result,
- MM_CORE_ERROR,
- MM_CORE_ERROR_RETRY,
- "SIM not ready yet (retry)");
- qmi_message_uim_get_card_status_output_unref (output);
- load_unlock_required_context_complete_and_free (ctx);
- return;
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY,
+ "SIM not ready yet (retry)");
+ return FALSE;
}
+ /* Report retries if requested to do so */
+ if (o_pin1_retries)
+ *o_pin1_retries = app->pin1_retries;
+ if (o_puk1_retries)
+ *o_puk1_retries = app->puk1_retries;
+ if (o_pin2_retries)
+ *o_pin2_retries = app->pin2_retries;
+ if (o_puk2_retries)
+ *o_puk2_retries = app->puk2_retries;
+
+ /* Early bail out if lock status isn't wanted at this point, so that we
+ * don't fail with an error the unlock retries check */
+ if (!o_lock)
+ return TRUE;
+
/* Card is ready, what's the lock status? */
/* PIN1 */
switch (app->pin1_state) {
case QMI_UIM_PIN_STATE_PERMANENTLY_BLOCKED:
- g_simple_async_result_set_error (ctx->result,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG,
- "SIM PIN/PUK permanently blocked");
- qmi_message_uim_get_card_status_output_unref (output);
- load_unlock_required_context_complete_and_free (ctx);
- return;
+ g_set_error (error,
+ MM_MOBILE_EQUIPMENT_ERROR,
+ MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG,
+ "SIM PIN/PUK permanently blocked");
+ return FALSE;
case QMI_UIM_PIN_STATE_ENABLED_NOT_VERIFIED:
lock = MM_MODEM_LOCK_SIM_PIN;
@@ -1666,13 +1663,11 @@ uim_get_card_status_ready (QmiClientUim *client,
break;
default:
- g_simple_async_result_set_error (ctx->result,
- MM_MOBILE_EQUIPMENT_ERROR,
- MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG,
- "Unknown SIM PIN/PUK status");
- qmi_message_uim_get_card_status_output_unref (output);
- load_unlock_required_context_complete_and_free (ctx);
- return;
+ g_set_error (error,
+ MM_MOBILE_EQUIPMENT_ERROR,
+ MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG,
+ "Unknown SIM PIN/PUK status");
+ return FALSE;
}
/* PIN2 */
@@ -1698,7 +1693,36 @@ uim_get_card_status_ready (QmiClientUim *client,
}
}
- g_simple_async_result_set_op_res_gpointer (ctx->result, GUINT_TO_POINTER (lock), NULL);
+ *o_lock = lock;
+ return TRUE;
+}
+
+static void
+unlock_required_uim_get_card_status_ready (QmiClientUim *client,
+ GAsyncResult *res,
+ LoadUnlockRequiredContext *ctx)
+{
+ QmiMessageUimGetCardStatusOutput *output;
+ GError *error = NULL;
+ MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
+
+ output = qmi_client_uim_get_card_status_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ load_unlock_required_context_complete_and_free (ctx);
+ return;
+ }
+
+ if (!uim_get_card_status_output_parse (output,
+ &lock,
+ NULL, NULL, NULL, NULL,
+ &error)) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_simple_async_result_take_error (ctx->result, error);
+ } else
+ g_simple_async_result_set_op_res_gpointer (ctx->result, GUINT_TO_POINTER (lock), NULL);
+
qmi_message_uim_get_card_status_output_unref (output);
load_unlock_required_context_complete_and_free (ctx);
}
@@ -1844,7 +1868,7 @@ load_unlock_required_context_step (LoadUnlockRequiredContext *ctx)
NULL,
5,
NULL,
- (GAsyncReadyCallback) uim_get_card_status_ready,
+ (GAsyncReadyCallback) unlock_required_uim_get_card_status_ready,
ctx);
return;
}
@@ -1872,93 +1896,184 @@ modem_load_unlock_required (MMIfaceModem *self,
/* Check if unlock retries (Modem interface) */
static MMUnlockRetries *
-modem_load_unlock_retries_finish (MMIfaceModem *self,
- GAsyncResult *res,
- GError **error)
+modem_load_unlock_retries_finish (MMIfaceModem *self,
+ GAsyncResult *res,
+ GError **error)
{
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
- return NULL;
-
- return MM_UNLOCK_RETRIES (g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))));
+ return MM_UNLOCK_RETRIES (g_task_propagate_pointer (G_TASK (res), error));
}
static void
-retry_count_dms_uim_get_pin_status_ready (QmiClientDms *client,
+unlock_retries_uim_get_card_status_ready (QmiClientUim *client,
GAsyncResult *res,
- GSimpleAsyncResult *simple)
+ GTask *task)
+{
+ QmiMessageUimGetCardStatusOutput *output;
+ GError *error = NULL;
+ guint pin1_retries = 0;
+ guint puk1_retries = 0;
+ guint pin2_retries = 0;
+ guint puk2_retries = 0;
+ MMUnlockRetries *retries;
+
+ output = qmi_client_uim_get_card_status_finish (client, res, &error);
+ if (!output) {
+ g_prefix_error (&error, "QMI operation failed: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (!uim_get_card_status_output_parse (output,
+ NULL,
+ &pin1_retries, &puk1_retries,
+ &pin2_retries, &puk2_retries,
+ &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ retries = mm_unlock_retries_new ();
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, pin1_retries);
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, puk1_retries);
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN2, pin2_retries);
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK2, puk2_retries);
+
+ qmi_message_uim_get_card_status_output_unref (output);
+
+ g_task_return_pointer (task, retries, g_object_unref);
+ g_object_unref (task);
+}
+
+static void
+uim_load_unlock_retries (MMBroadbandModemQmi *self,
+ GTask *task)
+{
+ QmiClient *client;
+ GError *error = NULL;
+
+ client = peek_qmi_client (self, QMI_SERVICE_UIM, &error);
+ if (!client) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ qmi_client_uim_get_card_status (QMI_CLIENT_UIM (client),
+ NULL,
+ 5,
+ NULL,
+ (GAsyncReadyCallback) unlock_retries_uim_get_card_status_ready,
+ task);
+}
+
+static void
+unlock_retries_dms_uim_get_pin_status_ready (QmiClientDms *client,
+ GAsyncResult *res,
+ GTask *task)
{
QmiMessageDmsUimGetPinStatusOutput *output;
GError *error = NULL;
+ MMBroadbandModemQmi *self;
+ MMUnlockRetries *retries;
+ guint8 verify_retries_left;
+ guint8 unblock_retries_left;
+
+ self = g_task_get_source_object (task);
output = qmi_client_dms_uim_get_pin_status_finish (client, res, &error);
if (!output) {
g_prefix_error (&error, "QMI operation failed: ");
- g_simple_async_result_take_error (simple, error);
- } else if (!qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) {
- g_prefix_error (&error, "Couldn't get unlock retries: ");
- g_simple_async_result_take_error (simple, error);
- } else {
- MMUnlockRetries *retries;
- guint8 verify_retries_left;
- guint8 unblock_retries_left;
-
- retries = mm_unlock_retries_new ();
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
- if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
- output,
- NULL, /* current_status */
- &verify_retries_left,
- &unblock_retries_left,
- NULL)) {
- mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, verify_retries_left);
- mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, unblock_retries_left);
+ if (!qmi_message_dms_uim_get_pin_status_output_get_result (output, &error)) {
+ qmi_message_dms_uim_get_pin_status_output_unref (output);
+ /* We get InvalidQmiCommand on newer devices which don't like the legacy way */
+ if (g_error_matches (error,
+ QMI_PROTOCOL_ERROR,
+ QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) {
+ g_error_free (error);
+ /* Flag that the command is unsupported, and try with the new way */
+ self->priv->dms_uim_get_pin_status_supported = FALSE;
+ uim_load_unlock_retries (self, task);
+ return;
}
+ g_prefix_error (&error, "Couldn't get unlock retries: ");
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
- if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status (
- output,
- NULL, /* current_status */
- &verify_retries_left,
- &unblock_retries_left,
- NULL)) {
- mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN2, verify_retries_left);
- mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK2, unblock_retries_left);
- }
+ retries = mm_unlock_retries_new ();
- g_simple_async_result_set_op_res_gpointer (simple, retries, g_object_unref);
+ if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
+ output,
+ NULL, /* current_status */
+ &verify_retries_left,
+ &unblock_retries_left,
+ NULL)) {
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN, verify_retries_left);
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK, unblock_retries_left);
}
- if (output)
- qmi_message_dms_uim_get_pin_status_output_unref (output);
+ if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status (
+ output,
+ NULL, /* current_status */
+ &verify_retries_left,
+ &unblock_retries_left,
+ NULL)) {
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PIN2, verify_retries_left);
+ mm_unlock_retries_set (retries, MM_MODEM_LOCK_SIM_PUK2, unblock_retries_left);
+ }
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ qmi_message_dms_uim_get_pin_status_output_unref (output);
+
+ g_task_return_pointer (task, retries, g_object_unref);
+ g_object_unref (task);
}
static void
-modem_load_unlock_retries (MMIfaceModem *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
+dms_uim_load_unlock_retries (MMBroadbandModemQmi *self,
+ GTask *task)
{
- GSimpleAsyncResult *result;
- QmiClient *client = NULL;
+ QmiClient *client;
- if (!ensure_qmi_client (MM_BROADBAND_MODEM_QMI (self),
- QMI_SERVICE_DMS, &client,
- callback, user_data))
+ client = peek_qmi_client (self, QMI_SERVICE_DMS, NULL);
+ if (!client) {
+ /* Very unlikely that this will ever happen, but anyway, try with
+ * UIM service instead */
+ uim_load_unlock_retries (self, task);
return;
+ }
- result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- modem_load_unlock_retries);
-
- mm_dbg ("loading unlock retries...");
qmi_client_dms_uim_get_pin_status (QMI_CLIENT_DMS (client),
NULL,
5,
NULL,
- (GAsyncReadyCallback)retry_count_dms_uim_get_pin_status_ready,
- result);
+ (GAsyncReadyCallback) unlock_retries_dms_uim_get_pin_status_ready,
+ task);
+}
+
+static void
+modem_load_unlock_retries (MMIfaceModem *_self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemQmi *self;
+ GTask *task;
+
+ self = MM_BROADBAND_MODEM_QMI (_self);
+ task = g_task_new (self, NULL, callback, user_data);
+
+ mm_dbg ("loading unlock retries...");
+ if (self->priv->dms_uim_get_pin_status_supported)
+ dms_uim_load_unlock_retries (MM_BROADBAND_MODEM_QMI (self), task);
+ else
+ uim_load_unlock_retries (MM_BROADBAND_MODEM_QMI (self), task);
}
/*****************************************************************************/
--
2.7.0
More information about the ModemManager-devel
mailing list