[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