[PATCH v3] telit-plugin: ignore QSS when SIM-ME interface is locked

Carlo Lobrano c.lobrano at gmail.com
Fri Jul 28 13:57:55 UTC 2017


With some modems, the lock/unlock of the SIM-ME interface with +CSIM=1/0
command is followed by #QSS unsolicited messages. With the current
implementation, this messages are mistaken for SIM swap events and so the
modem is first dropped and then re-probed.

With this patch, the plugin takes into account the SIM-ME lock state when
parsing #QSS unsolicited, so that the QSS handler can correctly
elaborate the messages that are not related to SIM swap events.
---

I spotted an error in version 2: csim_lock_task was saved in priv only if CSIM was locked

---
 plugins/telit/mm-broadband-modem-telit.c | 85 ++++++++++++++++++++++++++++----
 plugins/telit/mm-modem-helpers-telit.h   |  9 ++++
 2 files changed, 85 insertions(+), 9 deletions(-)

diff --git a/plugins/telit/mm-broadband-modem-telit.c b/plugins/telit/mm-broadband-modem-telit.c
index e7650c0..2c6f7a9 100644
--- a/plugins/telit/mm-broadband-modem-telit.c
+++ b/plugins/telit/mm-broadband-modem-telit.c
@@ -44,6 +44,8 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemTelit, mm_broadband_modem_telit, MM_TYPE
                         G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
                         G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init));
 
+#define CSIM_UNLOCK_MAX_TIMEOUT 3
+
 typedef enum {
     FEATURE_SUPPORT_UNKNOWN,
     FEATURE_NOT_SUPPORTED,
@@ -53,6 +55,9 @@ typedef enum {
 struct _MMBroadbandModemTelitPrivate {
     FeatureSupport csim_lock_support;
     MMTelitQssStatus qss_status;
+    MMTelitCsimLockState csim_lock_state;
+    GTask *csim_lock_task;
+    guint csim_lock_timeout_id;
 };
 
 /*****************************************************************************/
@@ -107,6 +112,7 @@ typedef struct {
 } QssSetupContext;
 
 static void qss_setup_step (GTask *task);
+static void pending_csim_unlock_complete (MMBroadbandModemTelit *self);
 
 static void
 telit_qss_unsolicited_handler (MMPortSerialAt *port,
@@ -122,14 +128,36 @@ telit_qss_unsolicited_handler (MMPortSerialAt *port,
     prev_qss_status = self->priv->qss_status;
     self->priv->qss_status = cur_qss_status;
 
+    if (self->priv->csim_lock_state >= CSIM_LOCK_STATE_LOCK_REQUESTED) {
+
+        if (prev_qss_status > QSS_STATUS_SIM_REMOVED && cur_qss_status == QSS_STATUS_SIM_REMOVED) {
+            mm_dbg ("QSS handler: #QSS=0 after +CSIM=1 -> CSIM locked!");
+            self->priv->csim_lock_state = CSIM_LOCK_STATE_LOCKED;
+        }
+
+        if (prev_qss_status == QSS_STATUS_SIM_REMOVED && cur_qss_status != QSS_STATUS_SIM_REMOVED) {
+            mm_dbg ("QSS handler: #QSS>=1 after +CSIM=0 -> CSIM unlocked!");
+            self->priv->csim_lock_state = CSIM_LOCK_STATE_UNLOCKED;
+
+            if (self->priv->csim_lock_timeout_id) {
+                g_source_remove (self->priv->csim_lock_timeout_id);
+                self->priv->csim_lock_timeout_id = 0;
+            }
+
+            pending_csim_unlock_complete (self);
+        }
+
+        return;
+    }
+
     if (cur_qss_status != prev_qss_status)
-        mm_dbg ("QSS: status changed '%s -> %s",
+        mm_dbg ("QSS handler: status changed '%s -> %s",
                 mm_telit_qss_status_get_string (prev_qss_status),
                 mm_telit_qss_status_get_string (cur_qss_status));
 
     if ((prev_qss_status == QSS_STATUS_SIM_REMOVED && cur_qss_status != QSS_STATUS_SIM_REMOVED) ||
         (prev_qss_status > QSS_STATUS_SIM_REMOVED && cur_qss_status == QSS_STATUS_SIM_REMOVED)) {
-        mm_info ("QSS: SIM swap detected");
+        mm_info ("QSS handler: SIM swap detected");
         mm_broadband_modem_update_sim_hot_swap_detected (MM_BROADBAND_MODEM (self));
     }
 }
@@ -610,8 +638,9 @@ csim_unlock_ready (MMBaseModem  *_self,
     if (!response) {
         if (g_error_matches (error,
                              MM_MOBILE_EQUIPMENT_ERROR,
-                             MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED))
+                             MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED)) {
             self->priv->csim_lock_support = FEATURE_NOT_SUPPORTED;
+        }
         mm_warn ("Couldn't unlock SIM card: %s", error->message);
         g_error_free (error);
     }
@@ -703,6 +732,8 @@ csim_lock_ready (MMBaseModem  *_self,
             g_object_unref (task);
             return;
         }
+    } else {
+        self->priv->csim_lock_state = CSIM_LOCK_STATE_LOCK_REQUESTED;
     }
 
     if (self->priv->csim_lock_support != FEATURE_NOT_SUPPORTED) {
@@ -755,6 +786,37 @@ handle_csim_locking (GTask    *task,
 }
 
 static void
+pending_csim_unlock_complete (MMBroadbandModemTelit *self)
+{
+    LoadUnlockRetriesContext *ctx;
+
+    ctx = g_task_get_task_data (self->priv->csim_lock_task);
+
+    if (ctx->succeded_requests == 0) {
+        g_task_return_new_error (self->priv->csim_lock_task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+                                 "Could not get any of the SIM unlock retries values");
+    } else {
+        g_task_return_pointer (self->priv->csim_lock_task, g_object_ref (ctx->retries), g_object_unref);
+    }
+
+    g_clear_object (&self->priv->csim_lock_task);
+}
+
+static gboolean
+csim_unlock_periodic_check (MMBroadbandModemTelit *self)
+{
+    if (self->priv->csim_lock_state != CSIM_LOCK_STATE_UNLOCKED) {
+        mm_warn ("CSIM is still locked after %d seconds. Trying to continue anyway", CSIM_UNLOCK_MAX_TIMEOUT);
+    }
+
+    self->priv->csim_lock_timeout_id = 0;
+    pending_csim_unlock_complete (self);
+    g_object_unref (self);
+
+    return G_SOURCE_REMOVE;
+}
+
+static void
 load_unlock_retries_step (GTask *task)
 {
     MMBroadbandModemTelit *self;
@@ -805,12 +867,16 @@ load_unlock_retries_step (GTask *task)
             handle_csim_locking (task, FALSE);
             break;
         case LOAD_UNLOCK_RETRIES_STEP_LAST:
-            if (ctx->succeded_requests == 0)
-                g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
-                                         "Could not get any of the SIM unlock retries values");
-            else
-                g_task_return_pointer (task, g_object_ref (ctx->retries), g_object_unref);
-            g_object_unref (task);
+            self->priv->csim_lock_task = task;
+            if (self->priv->csim_lock_state == CSIM_LOCK_STATE_LOCKED) {
+                mm_dbg ("CSIM is locked. Waiting for #QSS=1");
+                self->priv->csim_lock_timeout_id = g_timeout_add_seconds (CSIM_UNLOCK_MAX_TIMEOUT,
+                                                                          (GSourceFunc) csim_unlock_periodic_check,
+                                                                          g_object_ref(self));
+            } else {
+                self->priv->csim_lock_state = CSIM_LOCK_STATE_UNLOCKED;
+                pending_csim_unlock_complete (self);
+            }
             break;
         default:
             break;
@@ -1388,6 +1454,7 @@ mm_broadband_modem_telit_init (MMBroadbandModemTelit *self)
                                               MMBroadbandModemTelitPrivate);
 
     self->priv->csim_lock_support = FEATURE_SUPPORT_UNKNOWN;
+    self->priv->csim_lock_state = CSIM_LOCK_STATE_UNKNOWN;
     self->priv->qss_status = QSS_STATUS_UNKNOWN;
 }
 
diff --git a/plugins/telit/mm-modem-helpers-telit.h b/plugins/telit/mm-modem-helpers-telit.h
index 24c39e0..1cf76f0 100644
--- a/plugins/telit/mm-modem-helpers-telit.h
+++ b/plugins/telit/mm-modem-helpers-telit.h
@@ -110,4 +110,13 @@ typedef enum { /*< underscore_name=mm_telit_qss_status >*/
 
 MMTelitQssStatus mm_telit_parse_qss_query (const gchar *response, GError **error);
 
+/* CSIM lock state */
+typedef enum { /*< underscore_name=mm_telit_csim_lock_state >*/
+    CSIM_LOCK_STATE_UNKNOWN,
+    CSIM_LOCK_STATE_UNLOCKED,
+    CSIM_LOCK_STATE_LOCK_REQUESTED,
+    CSIM_LOCK_STATE_LOCKED,
+} MMTelitCsimLockState;
+
+
 #endif  /* MM_MODEM_HELPERS_TELIT_H */
-- 
2.9.3



More information about the ModemManager-devel mailing list