shared-qmi: implement SIM/profile change detection

Implement eUICC change detection for QMI based modems using one of the
following mechanisms (in order of preference):

1. If the modem supports "get slot status" operation, we monitor
   physical slot status indications from the modem for the active
   slot to detect when ICCID changes.
2. Use "refresh register all" to subscribe refresh indications when
   the eUICC triggers REFRESH operation following the enablement of
   a new profile.
3. Use "refresh register" to subscribe refresh indications (file
   path of EF_ICCID is used) in a similar way. This is used with
   older modems that do not support "refresh register all".

If ICCID change is detected, the already existing SIM hot swap
mechanism in MM is triggered.
This commit is contained in:
Teijo Kinnunen
2020-09-28 09:29:09 +00:00
committed by Aleksander Morgado
parent 318b2b01e3
commit e91f2ef315
8 changed files with 626 additions and 56 deletions
@@ -27,6 +27,7 @@ static void iface_modem_location_init (MMIfaceModemLocation *iface);
static void iface_modem_time_init (MMIfaceModemTime *iface);
static void shared_quectel_init (MMSharedQuectel *iface);
static MMIfaceModem *iface_modem_parent;
static MMIfaceModemLocation *iface_modem_location_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiQuectel, mm_broadband_modem_qmi_quectel, MM_TYPE_BROADBAND_MODEM_QMI, 0,
@@ -62,10 +63,18 @@ mm_broadband_modem_qmi_quectel_init (MMBroadbandModemQmiQuectel *self)
static void
iface_modem_init (MMIfaceModem *iface)
{
iface_modem_parent = g_type_interface_peek_parent (iface);
iface->setup_sim_hot_swap = mm_shared_quectel_setup_sim_hot_swap;
iface->setup_sim_hot_swap_finish = mm_shared_quectel_setup_sim_hot_swap_finish;
}
static MMIfaceModem *
peek_parent_modem_interface (MMSharedQuectel *self)
{
return iface_modem_parent;
}
static void
iface_modem_firmware_init (MMIfaceModemFirmware *iface)
{
@@ -87,7 +96,7 @@ iface_modem_location_init (MMIfaceModemLocation *iface)
}
static MMIfaceModemLocation *
peek_parent_location_interface (MMSharedQuectel *self)
peek_parent_modem_location_interface (MMSharedQuectel *self)
{
return iface_modem_location_parent;
}
@@ -102,7 +111,8 @@ iface_modem_time_init (MMIfaceModemTime *iface)
static void
shared_quectel_init (MMSharedQuectel *iface)
{
iface->peek_parent_location_interface = peek_parent_location_interface;
iface->peek_parent_modem_interface = peek_parent_modem_interface;
iface->peek_parent_modem_location_interface = peek_parent_modem_location_interface;
}
static void
+12 -2
View File
@@ -27,6 +27,7 @@ static void iface_modem_location_init (MMIfaceModemLocation *iface);
static void iface_modem_time_init (MMIfaceModemTime *iface);
static void shared_quectel_init (MMSharedQuectel *iface);
static MMIfaceModem *iface_modem_parent;
static MMIfaceModemLocation *iface_modem_location_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQuectel, mm_broadband_modem_quectel, MM_TYPE_BROADBAND_MODEM, 0,
@@ -62,10 +63,18 @@ mm_broadband_modem_quectel_init (MMBroadbandModemQuectel *self)
static void
iface_modem_init (MMIfaceModem *iface)
{
iface_modem_parent = g_type_interface_peek_parent (iface);
iface->setup_sim_hot_swap = mm_shared_quectel_setup_sim_hot_swap;
iface->setup_sim_hot_swap_finish = mm_shared_quectel_setup_sim_hot_swap_finish;
}
static MMIfaceModem *
peek_parent_modem_interface (MMSharedQuectel *self)
{
return iface_modem_parent;
}
static void
iface_modem_firmware_init (MMIfaceModemFirmware *iface)
{
@@ -87,7 +96,7 @@ iface_modem_location_init (MMIfaceModemLocation *iface)
}
static MMIfaceModemLocation *
peek_parent_location_interface (MMSharedQuectel *self)
peek_parent_modem_location_interface (MMSharedQuectel *self)
{
return iface_modem_location_parent;
}
@@ -102,7 +111,8 @@ iface_modem_time_init (MMIfaceModemTime *iface)
static void
shared_quectel_init (MMSharedQuectel *iface)
{
iface->peek_parent_location_interface = peek_parent_location_interface;
iface->peek_parent_modem_interface = peek_parent_modem_interface;
iface->peek_parent_modem_location_interface = peek_parent_modem_location_interface;
}
static void
+38 -2
View File
@@ -43,6 +43,7 @@ typedef enum {
} FeatureSupport;
typedef struct {
MMIfaceModem *iface_modem_parent;
MMIfaceModemLocation *iface_modem_location_parent;
MMModemLocationSource provided_sources;
MMModemLocationSource enabled_sources;
@@ -65,8 +66,11 @@ get_private (MMSharedQuectel *self)
priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
priv->qgps_supported = FEATURE_SUPPORT_UNKNOWN;
g_assert (MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_location_interface);
priv->iface_modem_location_parent = MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_location_interface (self);
g_assert (MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_modem_location_interface);
priv->iface_modem_location_parent = MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_modem_location_interface (self);
g_assert (MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_modem_interface);
priv->iface_modem_parent = MM_SHARED_QUECTEL_GET_INTERFACE (self)->peek_parent_modem_interface (self);
g_object_set_qdata (G_OBJECT (self), private_quark, priv);
}
@@ -170,16 +174,37 @@ mm_shared_quectel_setup_sim_hot_swap_finish (MMIfaceModem *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
parent_setup_sim_hot_swap_ready (MMIfaceModem *self,
GAsyncResult *res,
GTask *task)
{
Private *priv;
g_autoptr(GError) error = NULL;
priv = get_private (MM_SHARED_QUECTEL (self));
if (!priv->iface_modem_parent->setup_sim_hot_swap_finish (self, res, &error))
mm_obj_dbg (self, "additional SIM hot swap detection setup failed: %s", error->message);
/* The +QUSIM based setup never fails, so we can safely return success here */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
void
mm_shared_quectel_setup_sim_hot_swap (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
Private *priv;
MMPortSerialAt *ports[2];
GTask *task;
GRegex *pattern;
guint i;
priv = get_private (MM_SHARED_QUECTEL (self));
task = g_task_new (self, NULL, callback, user_data);
ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self));
@@ -200,6 +225,17 @@ mm_shared_quectel_setup_sim_hot_swap (MMIfaceModem *self,
g_regex_unref (pattern);
mm_obj_dbg (self, "+QUSIM detection set up");
/* Now, if available, setup parent logic */
if (priv->iface_modem_parent->setup_sim_hot_swap &&
priv->iface_modem_parent->setup_sim_hot_swap_finish) {
priv->iface_modem_parent->setup_sim_hot_swap (self,
(GAsyncReadyCallback) parent_setup_sim_hot_swap_ready,
task);
return;
}
/* Otherwise, we're done */
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
+2 -1
View File
@@ -37,7 +37,8 @@ typedef struct _MMSharedQuectel MMSharedQuectel;
struct _MMSharedQuectel {
GTypeInterface g_iface;
MMIfaceModemLocation * (* peek_parent_location_interface) (MMSharedQuectel *self);
MMIfaceModem * (* peek_parent_modem_interface) (MMSharedQuectel *self);
MMIfaceModemLocation * (* peek_parent_modem_location_interface) (MMSharedQuectel *self);
};
GType mm_shared_quectel_get_type (void);