mm-iface-modem,mm-broadband-modem,mm-shared-qmi: support SIM IMSI switch
It is possible that SIM IMSI might change in roaming conditions for a sim. Register for UIM refresh indication always and reprobe if ICCID or IMSI changes for QMI modem.
This commit is contained in:
committed by
Aleksander Morgado
parent
115692dd91
commit
5c0db37432
@@ -11,6 +11,7 @@
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2018-2020 Aleksander Morgado <aleksander@aleksander.es>
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
@@ -397,6 +398,7 @@ quectel_qusim_unsolicited_handler (MMPortSerialAt *port,
|
||||
MM_IFACE_MODEM_GET_INTERFACE (self)->check_for_sim_swap (
|
||||
self,
|
||||
NULL,
|
||||
NULL,
|
||||
(GAsyncReadyCallback)quectel_qusim_check_for_sim_swap_ready,
|
||||
NULL);
|
||||
}
|
||||
|
||||
+147
-38
@@ -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,12 +4127,22 @@ modem_power_up (MMIfaceModem *self,
|
||||
/*****************************************************************************/
|
||||
/* Reprobing the modem if the SIM changed across a power-off or power-down */
|
||||
|
||||
typedef struct {
|
||||
MMBaseSim *sim;
|
||||
guint retries;
|
||||
} SimSwapContext;
|
||||
#define SIM_SWAP_CHECK_LOAD_RETRIES_MAX 3
|
||||
|
||||
static gboolean load_sim_identifier (GTask *task);
|
||||
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;
|
||||
gchar *iccid;
|
||||
gchar *imsi;
|
||||
SimSwapCheckStep step;
|
||||
} SimSwapContext;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+179
-90
@@ -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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user