diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem.c | 183 | ||||
-rw-r--r-- | src/mm-iface-modem.c | 7 | ||||
-rw-r--r-- | src/mm-iface-modem.h | 3 | ||||
-rw-r--r-- | src/mm-shared-qmi.c | 269 |
4 files changed, 334 insertions, 128 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index 5c309195..2157572f 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -15,6 +15,7 @@ * Copyright (C) 2015 Marco Bascetta <marco.bascetta@sadel.it> * Copyright (C) 2019 Purism SPC * Copyright (C) 2011 - 2021 Google, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. */ #include <config.h> @@ -4126,13 +4127,23 @@ modem_power_up (MMIfaceModem *self, /*****************************************************************************/ /* Reprobing the modem if the SIM changed across a power-off or power-down */ +#define SIM_SWAP_CHECK_LOAD_RETRIES_MAX 3 + +typedef enum { + SIM_SWAP_CHECK_STEP_FIRST, + SIM_SWAP_CHECK_STEP_ICCID_CHANGED, + SIM_SWAP_CHECK_STEP_IMSI_CHANGED, + SIM_SWAP_CHECK_STEP_LAST, +} SimSwapCheckStep; + typedef struct { - MMBaseSim *sim; - guint retries; + MMBaseSim *sim; + guint retries; + gchar *iccid; + gchar *imsi; + SimSwapCheckStep step; } SimSwapContext; -static gboolean load_sim_identifier (GTask *task); - static void sim_swap_context_free (SimSwapContext *ctx) { @@ -4148,46 +4159,82 @@ modem_check_for_sim_swap_finish (MMIfaceModem *self, return g_task_propagate_boolean (G_TASK (res), error); } +static gboolean load_sim_identifier (GTask *task); +static gboolean load_sim_imsi (GTask *task); +static void sim_swap_check_step (GTask *task); + static void complete_sim_swap_check (GTask *task, - const gchar *current_simid) + const gchar *current) { MMBroadbandModem *self; SimSwapContext *ctx; - const gchar *cached_simid; + const gchar *cached; + const gchar *str; - g_assert (current_simid); + g_assert (current); self = MM_BROADBAND_MODEM (g_task_get_source_object (task)); ctx = g_task_get_task_data (task); - cached_simid = mm_gdbus_sim_get_sim_identifier (MM_GDBUS_SIM (ctx->sim)); - if (g_strcmp0 (current_simid, cached_simid) != 0) { - mm_obj_info (self, "SIM identifier has changed: %s -> %s - possible SIM swap", - cached_simid ? cached_simid : "<none>", current_simid); + switch (ctx->step) { + case SIM_SWAP_CHECK_STEP_ICCID_CHANGED: + cached = mm_gdbus_sim_get_sim_identifier (MM_GDBUS_SIM (ctx->sim)); + str = "identifier"; + break; + case SIM_SWAP_CHECK_STEP_IMSI_CHANGED: + cached = mm_gdbus_sim_get_imsi (MM_GDBUS_SIM (ctx->sim)); + str = "imsi"; + break; + case SIM_SWAP_CHECK_STEP_FIRST: + case SIM_SWAP_CHECK_STEP_LAST: + default: + g_assert_not_reached(); + } + + if (g_strcmp0 (current, cached) != 0) { + mm_obj_info (self, "SIM %s has changed: %s -> %s", + str, cached ? cached : "<none>", current); mm_iface_modem_process_sim_event (MM_IFACE_MODEM (self)); - } else - mm_obj_dbg (self, "SIM identifier has not changed"); + ctx->step = SIM_SWAP_CHECK_STEP_LAST; + } else { + mm_obj_dbg (self, "SIM %s has not changed", str); + ctx->step++; + } - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} + sim_swap_check_step (task); + } static void -load_sim_identifier_ready (MMBaseSim *sim, - GAsyncResult *res, - GTask *task) +load_sim_step_ready (MMBaseSim *sim, + GAsyncResult *res, + GTask *task) { MMBroadbandModem *self; SimSwapContext *ctx; - g_autofree gchar *current_simid = NULL; + g_autofree gchar *current = NULL; GError *error = NULL; + const gchar *str; self = MM_BROADBAND_MODEM (g_task_get_source_object (task)); ctx = g_task_get_task_data (task); - current_simid = mm_base_sim_load_sim_identifier_finish (sim, res, &error); + switch (ctx->step) { + case SIM_SWAP_CHECK_STEP_ICCID_CHANGED: + current = mm_base_sim_load_sim_identifier_finish (sim, res, &error); + str = "identifier"; + break; + case SIM_SWAP_CHECK_STEP_IMSI_CHANGED: + current = MM_BASE_SIM_GET_CLASS (sim)->load_imsi_finish (sim, res, &error); + str = "imsi"; + break; + case SIM_SWAP_CHECK_STEP_FIRST: + case SIM_SWAP_CHECK_STEP_LAST: + default: + g_assert_not_reached(); + } + if (error) { if (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED)) { g_task_return_error (task, error); @@ -4196,22 +4243,25 @@ load_sim_identifier_ready (MMBaseSim *sim, } if (ctx->retries > 0) { - mm_obj_warn (self, "could not load SIM identifier: %s (%d retries left)", - error->message, ctx->retries); + mm_obj_warn (self, "could not load SIM %s: %s (%d retries left)", + str, error->message, ctx->retries); --ctx->retries; g_clear_error (&error); - g_timeout_add_seconds (1, (GSourceFunc) load_sim_identifier, task); + if (ctx->step == SIM_SWAP_CHECK_STEP_ICCID_CHANGED) + g_timeout_add_seconds (1, (GSourceFunc) load_sim_identifier, task); + else + g_timeout_add_seconds (1, (GSourceFunc) load_sim_imsi, task); return; } - mm_obj_warn (self, "could not load SIM identifier: %s", error->message); + mm_obj_warn (self, "could not load SIM %s: %s", str, error->message); g_task_return_error (task, error); g_object_unref (task); return; } - complete_sim_swap_check (task, current_simid); -} + complete_sim_swap_check (task, current); + } static gboolean load_sim_identifier (GTask *task) @@ -4219,15 +4269,79 @@ load_sim_identifier (GTask *task) SimSwapContext *ctx = g_task_get_task_data (task); mm_base_sim_load_sim_identifier (ctx->sim, - (GAsyncReadyCallback)load_sim_identifier_ready, + (GAsyncReadyCallback)load_sim_step_ready, task); return G_SOURCE_REMOVE; } +static gboolean +load_sim_imsi (GTask *task) +{ + SimSwapContext *ctx = g_task_get_task_data (task); + + if (!MM_BASE_SIM_GET_CLASS (ctx->sim)->load_imsi || + !MM_BASE_SIM_GET_CLASS (ctx->sim)->load_imsi_finish) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "sim imsi could not be loaded"); + g_object_unref (task); + return G_SOURCE_REMOVE; + } + + MM_BASE_SIM_GET_CLASS (ctx->sim)->load_imsi ( + ctx->sim, + (GAsyncReadyCallback)load_sim_step_ready, + task); + return G_SOURCE_REMOVE; +} + +static void +sim_swap_check_step (GTask *task) +{ + SimSwapContext *ctx; + + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case SIM_SWAP_CHECK_STEP_FIRST: + ctx->step++; + /* fall-through */ + + case SIM_SWAP_CHECK_STEP_ICCID_CHANGED: + ctx->retries = SIM_SWAP_CHECK_LOAD_RETRIES_MAX; + /* We may or may not get the new SIM identifier (iccid). In case + * we've got it, the load_sim_identifier phase can be skipped. */ + if (ctx->iccid) + complete_sim_swap_check (task, ctx->iccid); + else + load_sim_identifier (task); + return; + + case SIM_SWAP_CHECK_STEP_IMSI_CHANGED: + ctx->retries = SIM_SWAP_CHECK_LOAD_RETRIES_MAX; + + if (ctx->imsi) + complete_sim_swap_check (task, ctx->imsi); + else + load_sim_imsi (task); + return; + + case SIM_SWAP_CHECK_STEP_LAST: + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + + default: + g_assert_not_reached (); + } +} + static void modem_check_for_sim_swap (MMIfaceModem *self, const gchar *iccid, + const gchar *imsi, GAsyncReadyCallback callback, gpointer user_data) { @@ -4238,7 +4352,9 @@ modem_check_for_sim_swap (MMIfaceModem *self, task = g_task_new (self, NULL, callback, user_data); ctx = g_slice_new0 (SimSwapContext); - ctx->retries = 3; + ctx->step = SIM_SWAP_CHECK_STEP_FIRST; + ctx->iccid = g_strdup (iccid); + ctx->imsi = g_strdup (imsi); g_task_set_task_data (task, ctx, (GDestroyNotify)sim_swap_context_free); g_object_get (self, @@ -4264,14 +4380,7 @@ modem_check_for_sim_swap (MMIfaceModem *self, return; } - /* We may or may not get the new SIM identifier (iccid). In case - * we've got it, the load_sim_identifier phase can be skipped. */ - if (iccid) { - complete_sim_swap_check (task, iccid); - return; - } - - load_sim_identifier (task); + sim_swap_check_step (task); } /*****************************************************************************/ diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c index 69c1872b..8a38a283 100644 --- a/src/mm-iface-modem.c +++ b/src/mm-iface-modem.c @@ -11,6 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2011 Google, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. */ #include <ModemManager.h> @@ -157,6 +158,7 @@ void mm_iface_modem_check_for_sim_swap (MMIfaceModem *self, guint slot_index, const gchar *iccid, + const gchar *imsi, GAsyncReadyCallback callback, gpointer user_data) { @@ -185,7 +187,7 @@ mm_iface_modem_check_for_sim_swap (MMIfaceModem *self, primary_slot = mm_gdbus_modem_get_primary_sim_slot (MM_GDBUS_MODEM (skeleton)); g_object_unref (skeleton); - /* Check that it's really the primary slot whose iccid has changed */ + /* Check that it's really the primary slot whose iccid or imsi has changed */ if (primary_slot && primary_slot != slot_index) { mm_obj_dbg (self, "checking for SIM swap ignored: status changed in slot %u, but primary is %u", slot_index, primary_slot); g_task_return_boolean (task, TRUE); @@ -200,6 +202,7 @@ mm_iface_modem_check_for_sim_swap (MMIfaceModem *self, MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap ( self, iccid, + imsi, (GAsyncReadyCallback)explicit_check_for_sim_swap_ready, task); return; @@ -4407,6 +4410,7 @@ interface_enabling_step (GTask *task) MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap ( self, NULL, + NULL, (GAsyncReadyCallback)check_for_sim_swap_ready, task); return; @@ -4603,6 +4607,7 @@ interface_syncing_step (GTask *task) self, 0, NULL, + NULL, (GAsyncReadyCallback)sync_detect_sim_swap_ready, task); return; diff --git a/src/mm-iface-modem.h b/src/mm-iface-modem.h index cf4274be..11b2a03c 100644 --- a/src/mm-iface-modem.h +++ b/src/mm-iface-modem.h @@ -11,6 +11,7 @@ * GNU General Public License for more details: * * Copyright (C) 2011 Google, Inc. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. */ #ifndef MM_IFACE_MODEM_H @@ -291,6 +292,7 @@ struct _MMIfaceModem { * not get the relevant notifications from the modem. */ void (*check_for_sim_swap) (MMIfaceModem *self, const gchar *iccid, + const gchar *imsi, GAsyncReadyCallback callback, gpointer user_data); gboolean (*check_for_sim_swap_finish) (MMIfaceModem *self, @@ -599,6 +601,7 @@ void mm_iface_modem_bind_simple_status (MMIfaceModem *self, void mm_iface_modem_check_for_sim_swap (MMIfaceModem *self, guint slot_index, const gchar *iccid, + const gchar *imsi, GAsyncReadyCallback callback, gpointer user_data); gboolean mm_iface_modem_check_for_sim_swap_finish (MMIfaceModem *self, diff --git a/src/mm-shared-qmi.c b/src/mm-shared-qmi.c index 0141d939..43d4a380 100644 --- a/src/mm-shared-qmi.c +++ b/src/mm-shared-qmi.c @@ -3565,6 +3565,27 @@ mm_shared_qmi_set_primary_sim_slot (MMIfaceModem *self, #define REFRESH_START_TIMEOUT_SECS 3 +typedef enum { + SETUP_SIM_HOT_SWAP_STEP_FIRST, + SETUP_SIM_HOT_SWAP_STEP_UIM_REGISTER_SLOT_STATUS, + SETUP_SIM_HOT_SWAP_STEP_UIM_REFRESH_REGISTER_ALL, + SETUP_SIM_HOT_SWAP_STEP_UIM_REFRESH_REGISTER_ICCID, + SETUP_SIM_HOT_SWAP_STEP_UIM_REFRESH_REGISTER_IMSI, + SETUP_SIM_HOT_SWAP_STEP_LAST, +} SetupSimHotSwapStep; + +typedef struct { + SetupSimHotSwapStep step; +} SetupSimHotSwapContext; + +static void setup_sim_hot_swap_step (GTask *task); + +static void +setup_sim_hot_swap_context_free (SetupSimHotSwapContext *ctx) +{ + g_slice_free (SetupSimHotSwapContext, ctx); +} + gboolean mm_shared_qmi_setup_sim_hot_swap_finish (MMIfaceModem *self, GAsyncResult *res, @@ -3613,7 +3634,7 @@ uim_start_refresh_timeout (MMSharedQmi *self) mm_obj_dbg (self, "refresh start timed out; trigger SIM change check"); - mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), 0, NULL, NULL, NULL); + mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), 0, NULL, NULL, NULL, NULL); return G_SOURCE_REMOVE; } @@ -3654,8 +3675,9 @@ uim_refresh_indication_cb (QmiClientUim *client, return; } - /* Currently we handle only UICC Reset type refresh, which can be used - * in profile switch scenarios. In other cases we just trigger 'refresh + /* Currently we handle UICC Reset type refresh, which can be used + * in profile switch scenarios, and Init Full FCN type refresh for + * SIM IMSI switch scenarios. In other cases we just trigger 'refresh * complete' during start phase. Signal to notify about potential SIM * profile switch is triggered when the refresh is ending. If it were * triggered in start phase, reading SIM files seems to fail with @@ -3665,7 +3687,7 @@ uim_refresh_indication_cb (QmiClientUim *client, * we start a timer at 'start' stage and if it expires, the SIM change * check is triggered anyway. */ if (stage == QMI_UIM_REFRESH_STAGE_START) { - if (mode == QMI_UIM_REFRESH_MODE_RESET) { + if (mode == QMI_UIM_REFRESH_MODE_RESET || mode == QMI_UIM_REFRESH_MODE_INIT_FULL_FCN) { if (!priv->uim_refresh_start_timeout_id) priv->uim_refresh_start_timeout_id = g_timeout_add_seconds (REFRESH_START_TIMEOUT_SECS, (GSourceFunc)uim_start_refresh_timeout, @@ -3673,12 +3695,12 @@ uim_refresh_indication_cb (QmiClientUim *client, } else uim_refresh_complete (client, session_type); } else if (stage == QMI_UIM_REFRESH_STAGE_END_WITH_SUCCESS) { - if (mode == QMI_UIM_REFRESH_MODE_RESET) { + if (mode == QMI_UIM_REFRESH_MODE_RESET || mode == QMI_UIM_REFRESH_MODE_INIT_FULL_FCN) { if (priv->uim_refresh_start_timeout_id) { g_source_remove (priv->uim_refresh_start_timeout_id); priv->uim_refresh_start_timeout_id = 0; } - mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), 0, NULL, NULL, NULL); + mm_iface_modem_check_for_sim_swap (MM_IFACE_MODEM (self), 0, NULL, NULL, NULL, NULL); } } } @@ -3842,46 +3864,55 @@ uim_slot_status_indication_cb (QmiClientUim *client, } static void -uim_refresh_register_iccid_change_ready (QmiClientUim *client, - GAsyncResult *res, - GTask *task) +uim_refresh_register_file_ready (QmiClientUim *client, + GAsyncResult *res, + GTask *task) { MMSharedQmi *self; Private *priv; g_autoptr(QmiMessageUimRefreshRegisterOutput) output = NULL; g_autoptr(GError) error = NULL; + SetupSimHotSwapContext *ctx; self = g_task_get_source_object (task); priv = get_private (self); + ctx = g_task_get_task_data (task); output = qmi_client_uim_refresh_register_finish (client, res, &error); if (!output || !qmi_message_uim_refresh_register_output_get_result (output, &error)) { - mm_obj_dbg (self, "refresh registration using 'refresh register' failed: %s", error->message); + mm_obj_dbg (self, "file refresh registration using 'refresh register' failed: %s", error->message); g_clear_object (&priv->uim_client); g_task_return_new_error (task, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NOT_SUPPORTED, "SIM hot swap detection not supported by modem"); + g_object_unref (task); } else { - mm_obj_dbg (self, "registered for SIM refresh events using 'refresh register'"); - priv->uim_refresh_indication_id = - g_signal_connect (client, - "refresh", - G_CALLBACK (uim_refresh_indication_cb), - self); - g_task_return_boolean (task, TRUE); + mm_obj_dbg (self, "file refresh registered using 'refresh register'"); + if (!priv->uim_refresh_indication_id) + priv->uim_refresh_indication_id = + g_signal_connect (client, + "refresh", + G_CALLBACK (uim_refresh_indication_cb), + self); + /* Go on to next step */ + ctx->step++; + setup_sim_hot_swap_step (task); } - g_object_unref (task); } /* This is the last resort if 'refresh register all' does not work. It works * on some older modems. Those modems may not also support QMI_UIM_SESSION_TYPE_CARD_SLOT_1 * so we'll use QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING */ static void -uim_refresh_register_iccid_change (GTask *task) +uim_refresh_register_file (GTask *task, + guint16 file_id, + const guint16 *file_path, + gsize file_path_len) { MMSharedQmi *self; Private *priv; QmiMessageUimRefreshRegisterInputInfoFilesElement file_element; guint8 val; + gsize i; g_autoptr(QmiMessageUimRefreshRegisterInput) refresh_register_input = NULL; g_autoptr(GArray) placeholder_aid = NULL; g_autoptr(GArray) file = NULL; @@ -3896,15 +3927,17 @@ uim_refresh_register_iccid_change (GTask *task) file = g_array_sized_new (FALSE, FALSE, sizeof (QmiMessageUimRefreshRegisterInputInfoFilesElement), 1); - file_element_path = g_array_sized_new (FALSE, FALSE, sizeof (guint8), 2); - val = 0x00; - g_array_append_val (file_element_path, val); - val = 0x3F; - g_array_append_val (file_element_path, val); + file_element_path = g_array_sized_new (FALSE, FALSE, sizeof (guint8), file_path_len * 2); + for (i = 0; i < file_path_len; ++i) { + val = file_path[i] & 0xFF; + g_array_append_val (file_element_path, val); + val = (file_path[i] >> 8) & 0xFF; + g_array_append_val (file_element_path, val); + } memset (&file_element, 0, sizeof (file_element)); - file_element.file_id = 0x2FE2; /* ICCID */ + file_element.file_id = file_id; file_element.path = file_element_path; g_array_append_val (file, file_element); @@ -3923,17 +3956,12 @@ uim_refresh_register_iccid_change (GTask *task) refresh_register_input, 10, NULL, - (GAsyncReadyCallback) uim_refresh_register_iccid_change_ready, + (GAsyncReadyCallback) uim_refresh_register_file_ready, task); } /* Refresh registration and event handling. - * This is used only as fallback in case slot status indications do not work - * in the particular modem (determined by UIM Get Slot Status failing) for - * detecting ICCID changing due to a profile switch. - * - * We assume that devices not supporting UIM Get Slot Status only have a - * single slot, for which we register refresh events. + * This is used for detecting ICCID and IMSI change. */ static void @@ -3945,9 +3973,11 @@ uim_refresh_register_all_ready (QmiClientUim *client, g_autoptr(GError) error = NULL; MMIfaceModem *self; Private *priv; + SetupSimHotSwapContext *ctx; self = g_task_get_source_object (task); priv = get_private (MM_SHARED_QMI (self)); + ctx = g_task_get_task_data (task); output = qmi_client_uim_refresh_register_all_finish (client, res, &error); if (!output || !qmi_message_uim_refresh_register_all_output_get_result (output, &error)) { @@ -3955,13 +3985,15 @@ uim_refresh_register_all_ready (QmiClientUim *client, g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) { /* As last resort, if 'refresh register all' fails, try a plain 'refresh register'. * Some older modems may not support 'refresh register all'. */ - uim_refresh_register_iccid_change (task); + ctx->step++; + setup_sim_hot_swap_step (task); return; } mm_obj_dbg (self, "refresh register all operation failed: %s", error->message); g_clear_object (&priv->uim_client); g_task_return_error (task, g_steal_pointer (&error)); + g_object_unref (task); } else { mm_obj_dbg (self, "registered for all SIM refresh events"); priv->uim_refresh_indication_id = @@ -3969,43 +4001,10 @@ uim_refresh_register_all_ready (QmiClientUim *client, "refresh", G_CALLBACK (uim_refresh_indication_cb), self); - g_task_return_boolean (task, TRUE); + /* Go to last step */ + ctx->step = SETUP_SIM_HOT_SWAP_STEP_LAST; + setup_sim_hot_swap_step (task); } - g_object_unref (task); -} - -static void -uim_slot_status_not_supported (GTask *task) -{ - MMIfaceModem *self; - Private *priv; - g_autoptr(QmiMessageUimRefreshRegisterAllInput) refresh_register_all_input = NULL; - g_autoptr(GArray) placeholder_aid = NULL; - - self = g_task_get_source_object (task); - priv = get_private (MM_SHARED_QMI (self)); - - g_assert (!priv->uim_refresh_indication_id); - - mm_obj_dbg (self, "slot status not supported by modem: register for refresh indications"); - - placeholder_aid = g_array_new (FALSE, FALSE, sizeof (guint8)); - refresh_register_all_input = qmi_message_uim_refresh_register_all_input_new (); - - qmi_message_uim_refresh_register_all_input_set_info (refresh_register_all_input, - TRUE, - NULL); - qmi_message_uim_refresh_register_all_input_set_session (refresh_register_all_input, - QMI_UIM_SESSION_TYPE_CARD_SLOT_1, - placeholder_aid, - NULL); - - qmi_client_uim_refresh_register_all (QMI_CLIENT_UIM (priv->uim_client), - refresh_register_all_input, - 10, - NULL, - (GAsyncReadyCallback) uim_refresh_register_all_ready, - task); } static void @@ -4017,9 +4016,11 @@ uim_check_get_slot_status_ready (QmiClientUim *client, g_autoptr(GError) error = NULL; MMIfaceModem *self; Private *priv; + SetupSimHotSwapContext *ctx; self = g_task_get_source_object (task); priv = get_private (MM_SHARED_QMI (self)); + ctx = g_task_get_task_data (task); output = qmi_client_uim_get_slot_status_finish (client, res, &error); if (!output || !qmi_message_uim_get_slot_status_output_get_result (output, &error)) { @@ -4030,7 +4031,10 @@ uim_check_get_slot_status_ready (QmiClientUim *client, if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_NOT_SUPPORTED) || g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_QMI_COMMAND)) { - uim_slot_status_not_supported (task); + mm_obj_dbg (self, "slot status not supported by modem"); + /* Go on to next step */ + ctx->step++; + setup_sim_hot_swap_step (task); return; } @@ -4042,8 +4046,9 @@ uim_check_get_slot_status_ready (QmiClientUim *client, } mm_obj_dbg (self, "slot status retrieval succeeded: monitoring slot status indications"); - g_task_return_boolean (task, TRUE); - g_object_unref (task); + /* Go on to next step */ + ctx->step++; + setup_sim_hot_swap_step (task); } static void @@ -4055,9 +4060,11 @@ uim_register_events_ready (QmiClientUim *client, g_autoptr(GError) error = NULL; MMIfaceModem *self; Private *priv; + SetupSimHotSwapContext *ctx; self = g_task_get_source_object (task); priv = get_private (MM_SHARED_QMI (self)); + ctx = g_task_get_task_data (task); /* If event registration fails, go on with initialization. In that case * we cannot use slot status indications to detect eUICC profile switches. */ @@ -4083,7 +4090,96 @@ uim_register_events_ready (QmiClientUim *client, } mm_obj_dbg (self, "not registered for slot status indications: %s", error->message); - uim_slot_status_not_supported (task); + + /* Go on to next step */ + ctx->step++; + setup_sim_hot_swap_step (task); +} + +static void +setup_sim_hot_swap_step (GTask *task) +{ + MMSharedQmi *self; + Private *priv; + SetupSimHotSwapContext *ctx; + + self = g_task_get_source_object (task); + priv = get_private (MM_SHARED_QMI (self)); + ctx = g_task_get_task_data (task); + + switch (ctx->step) { + case SETUP_SIM_HOT_SWAP_STEP_FIRST: + ctx->step++; + /* fall-through */ + + case SETUP_SIM_HOT_SWAP_STEP_UIM_REGISTER_SLOT_STATUS: { + g_autoptr(QmiMessageUimRegisterEventsInput) register_events_input = NULL; + + g_assert (!priv->uim_slot_status_indication_id); + + register_events_input = qmi_message_uim_register_events_input_new (); + qmi_message_uim_register_events_input_set_event_registration_mask (register_events_input, + QMI_UIM_EVENT_REGISTRATION_FLAG_PHYSICAL_SLOT_STATUS, + NULL); + qmi_client_uim_register_events (QMI_CLIENT_UIM (priv->uim_client), + register_events_input, + 10, + NULL, + (GAsyncReadyCallback) uim_register_events_ready, + task); + return; + } + + case SETUP_SIM_HOT_SWAP_STEP_UIM_REFRESH_REGISTER_ALL: { + g_autoptr(QmiMessageUimRefreshRegisterAllInput) refresh_register_all_input = NULL; + g_autoptr(GArray) placeholder_aid = NULL; + + g_assert (!priv->uim_refresh_indication_id); + + placeholder_aid = g_array_new (FALSE, FALSE, sizeof (guint8)); + refresh_register_all_input = qmi_message_uim_refresh_register_all_input_new (); + + qmi_message_uim_refresh_register_all_input_set_info (refresh_register_all_input, + TRUE, + NULL); + qmi_message_uim_refresh_register_all_input_set_session (refresh_register_all_input, + QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING, + placeholder_aid, + NULL); + + qmi_client_uim_refresh_register_all (QMI_CLIENT_UIM (priv->uim_client), + refresh_register_all_input, + 10, + NULL, + (GAsyncReadyCallback) uim_refresh_register_all_ready, + task); + return; + } + + case SETUP_SIM_HOT_SWAP_STEP_UIM_REFRESH_REGISTER_ICCID: { + const guint16 file_path[] = { 0x3F00 }; + + mm_obj_dbg (self, "register for change in sim iccid"); + uim_refresh_register_file (task, 0x2FE2, file_path, G_N_ELEMENTS (file_path)); + return; + } + + case SETUP_SIM_HOT_SWAP_STEP_UIM_REFRESH_REGISTER_IMSI: { + const guint16 file_path[] = { 0x3F00, 0x7FFF }; + + mm_obj_dbg (self, "register for change in sim imsi"); + uim_refresh_register_file (task, 0x6F07, file_path, G_N_ELEMENTS (file_path)); + return; + } + + case SETUP_SIM_HOT_SWAP_STEP_LAST: + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + + default: + g_assert_not_reached (); + } } void @@ -4091,33 +4187,26 @@ mm_shared_qmi_setup_sim_hot_swap (MMIfaceModem *self, GAsyncReadyCallback callback, gpointer user_data) { - g_autoptr(QmiMessageUimRegisterEventsInput) register_events_input = NULL; - GTask *task; - QmiClient *client = NULL; - Private *priv; + GTask *task; + QmiClient *client = NULL; + Private *priv; + SetupSimHotSwapContext *ctx; if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), QMI_SERVICE_UIM, &client, callback, user_data)) return; - task = g_task_new (self, NULL, callback, user_data); priv = get_private (MM_SHARED_QMI (self)); - - g_assert (!priv->uim_slot_status_indication_id); g_assert (!priv->uim_client); priv->uim_client = g_object_ref (client); - register_events_input = qmi_message_uim_register_events_input_new (); - qmi_message_uim_register_events_input_set_event_registration_mask (register_events_input, - QMI_UIM_EVENT_REGISTRATION_FLAG_PHYSICAL_SLOT_STATUS, - NULL); - qmi_client_uim_register_events (QMI_CLIENT_UIM (priv->uim_client), - register_events_input, - 10, - NULL, - (GAsyncReadyCallback) uim_register_events_ready, - task); + task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (SetupSimHotSwapContext); + ctx->step = SETUP_SIM_HOT_SWAP_STEP_FIRST; + g_task_set_task_data (task, ctx, (GDestroyNotify)setup_sim_hot_swap_context_free); + + setup_sim_hot_swap_step (task); } /*****************************************************************************/ |