Merge request !1355 from 'mtk-unlock-required'
mtk-legacy: read IMSI if CPIN response is an error https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1355 Closes #980
This commit is contained in:
@@ -1505,32 +1505,6 @@ modem_load_own_numbers (MMIfaceModem *self,
|
||||
/*****************************************************************************/
|
||||
/* Check if unlock required (Modem interface) */
|
||||
|
||||
typedef struct {
|
||||
const gchar *result;
|
||||
MMModemLock code;
|
||||
} CPinResult;
|
||||
|
||||
static CPinResult unlock_results[] = {
|
||||
/* Longer entries first so we catch the correct one with strcmp() */
|
||||
{ "READY", MM_MODEM_LOCK_NONE },
|
||||
{ "SIM PIN2", MM_MODEM_LOCK_SIM_PIN2 },
|
||||
{ "SIM PUK2", MM_MODEM_LOCK_SIM_PUK2 },
|
||||
{ "SIM PIN", MM_MODEM_LOCK_SIM_PIN },
|
||||
{ "SIM PUK", MM_MODEM_LOCK_SIM_PUK },
|
||||
{ "PH-NETSUB PIN", MM_MODEM_LOCK_PH_NETSUB_PIN },
|
||||
{ "PH-NETSUB PUK", MM_MODEM_LOCK_PH_NETSUB_PUK },
|
||||
{ "PH-FSIM PIN", MM_MODEM_LOCK_PH_FSIM_PIN },
|
||||
{ "PH-FSIM PUK", MM_MODEM_LOCK_PH_FSIM_PUK },
|
||||
{ "PH-CORP PIN", MM_MODEM_LOCK_PH_CORP_PIN },
|
||||
{ "PH-CORP PUK", MM_MODEM_LOCK_PH_CORP_PUK },
|
||||
{ "PH-SIM PIN", MM_MODEM_LOCK_PH_SIM_PIN },
|
||||
{ "PH-NET PIN", MM_MODEM_LOCK_PH_NET_PIN },
|
||||
{ "PH-NET PUK", MM_MODEM_LOCK_PH_NET_PUK },
|
||||
{ "PH-SP PIN", MM_MODEM_LOCK_PH_SP_PIN },
|
||||
{ "PH-SP PUK", MM_MODEM_LOCK_PH_SP_PUK },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static MMModemLock
|
||||
modem_load_unlock_required_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
@@ -1553,42 +1527,19 @@ cpin_query_ready (MMIfaceModem *self,
|
||||
GTask *task)
|
||||
{
|
||||
|
||||
MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
|
||||
MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
|
||||
const gchar *result;
|
||||
GError *error = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
} else {
|
||||
if (result)
|
||||
lock = mm_parse_cpin_response (result, TRUE);
|
||||
g_task_return_int (task, lock);
|
||||
}
|
||||
|
||||
if (result &&
|
||||
strstr (result, "+CPIN:")) {
|
||||
CPinResult *iter = &unlock_results[0];
|
||||
const gchar *str;
|
||||
|
||||
str = strstr (result, "+CPIN:") + 6;
|
||||
/* Skip possible whitespaces after '+CPIN:' and before the response */
|
||||
while (*str == ' ')
|
||||
str++;
|
||||
|
||||
/* Some phones (Motorola EZX models) seem to quote the response */
|
||||
if (str[0] == '"')
|
||||
str++;
|
||||
|
||||
/* Translate the reply */
|
||||
while (iter->result) {
|
||||
if (g_str_has_prefix (str, iter->result)) {
|
||||
lock = iter->code;
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
g_task_return_int (task, lock);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
|
||||
@@ -5807,3 +5807,67 @@ mm_string_uint_map_lookup (const MMStringUintMap *map,
|
||||
}
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
const gchar *result;
|
||||
const MMModemLock code;
|
||||
} CPinResult;
|
||||
|
||||
static const CPinResult unlock_results[] = {
|
||||
/* Longer entries first so we catch the correct one with strcmp() */
|
||||
{ "READY", MM_MODEM_LOCK_NONE },
|
||||
{ "SIM PIN2", MM_MODEM_LOCK_SIM_PIN2 },
|
||||
{ "SIM PUK2", MM_MODEM_LOCK_SIM_PUK2 },
|
||||
{ "SIM PIN", MM_MODEM_LOCK_SIM_PIN },
|
||||
{ "SIM PUK", MM_MODEM_LOCK_SIM_PUK },
|
||||
{ "PH-NETSUB PIN", MM_MODEM_LOCK_PH_NETSUB_PIN },
|
||||
{ "PH-NETSUB PUK", MM_MODEM_LOCK_PH_NETSUB_PUK },
|
||||
{ "PH-FSIM PIN", MM_MODEM_LOCK_PH_FSIM_PIN },
|
||||
{ "PH-FSIM PUK", MM_MODEM_LOCK_PH_FSIM_PUK },
|
||||
{ "PH-CORP PIN", MM_MODEM_LOCK_PH_CORP_PIN },
|
||||
{ "PH-CORP PUK", MM_MODEM_LOCK_PH_CORP_PUK },
|
||||
{ "PH-SIM PIN", MM_MODEM_LOCK_PH_SIM_PIN },
|
||||
{ "PH-NET PIN", MM_MODEM_LOCK_PH_NET_PIN },
|
||||
{ "PH-NET PUK", MM_MODEM_LOCK_PH_NET_PUK },
|
||||
{ "PH-SP PIN", MM_MODEM_LOCK_PH_SP_PIN },
|
||||
{ "PH-SP PUK", MM_MODEM_LOCK_PH_SP_PUK },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MMModemLock
|
||||
mm_parse_cpin_response (const gchar *response,
|
||||
gboolean expect_cpin_prefix)
|
||||
{
|
||||
const CPinResult *iter = &unlock_results[0];
|
||||
|
||||
if (expect_cpin_prefix) {
|
||||
const gchar *p;
|
||||
|
||||
p = strstr (response, "+CPIN:");
|
||||
if (!p)
|
||||
return MM_MODEM_LOCK_UNKNOWN;
|
||||
|
||||
/* Advance past the +CPIN: */
|
||||
response = p + 6;
|
||||
}
|
||||
|
||||
/* Skip possible whitespaces after '+CPIN:' and before the response */
|
||||
while (*response == ' ')
|
||||
response++;
|
||||
|
||||
/* Some phones (Motorola EZX models) seem to quote the response */
|
||||
if (response[0] == '"')
|
||||
response++;
|
||||
|
||||
/* Translate the reply */
|
||||
while (iter->result) {
|
||||
if (g_str_has_prefix (response, iter->result)) {
|
||||
return iter->code;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
return MM_MODEM_LOCK_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -638,4 +638,9 @@ guint mm_string_uint_map_lookup (const MMStringUintMap *map,
|
||||
const gchar *str,
|
||||
const guint default_value);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMModemLock mm_parse_cpin_response (const gchar *response,
|
||||
gboolean expect_cpin_prefix);
|
||||
|
||||
#endif /* MM_MODEM_HELPERS_H */
|
||||
|
||||
@@ -55,6 +55,101 @@ struct _MMBroadbandModemMtkLegacyPrivate {
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Check unlock required (Modem interface) */
|
||||
|
||||
static MMModemLock
|
||||
load_unlock_required_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GError *inner_error = NULL;
|
||||
gssize value;
|
||||
|
||||
value = g_task_propagate_int (G_TASK (res), &inner_error);
|
||||
if (inner_error) {
|
||||
g_propagate_error (error, inner_error);
|
||||
return MM_MODEM_LOCK_UNKNOWN;
|
||||
}
|
||||
return (MMModemLock)value;
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_required_cimi_query_ready (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else {
|
||||
/* Assume unlocked if we can successfully read the IMSI */
|
||||
g_task_return_int (task, MM_MODEM_LOCK_NONE);
|
||||
}
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
cpin_query_ready (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMModemLock lock = MM_MODEM_LOCK_UNKNOWN;
|
||||
const gchar *result;
|
||||
GError *error = NULL;
|
||||
|
||||
result = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
/* Some older MTK-based phones reply to +CPIN with CME ERROR 100,
|
||||
* but to even boot up they require the SIM PIN and so must be
|
||||
* unlocked. Double-check by reading the IMSI though.
|
||||
*/
|
||||
if (g_error_matches (error,
|
||||
MM_MOBILE_EQUIPMENT_ERROR,
|
||||
MM_MOBILE_EQUIPMENT_ERROR_UNKNOWN)) {
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CIMI",
|
||||
10,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)unlock_required_cimi_query_ready,
|
||||
task);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise just return the error */
|
||||
g_task_return_error (task, error);
|
||||
} else {
|
||||
if (result)
|
||||
lock = mm_parse_cpin_response (result, TRUE);
|
||||
g_task_return_int (task, lock);
|
||||
}
|
||||
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
load_unlock_required (MMIfaceModem *self,
|
||||
gboolean last_attempt,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, cancellable, callback, user_data);
|
||||
|
||||
mm_obj_dbg (self, "checking if unlock required...");
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
"+CPIN?",
|
||||
10,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)cpin_query_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
modem_after_sim_unlock_finish (MMIfaceModem *self,
|
||||
GAsyncResult *res,
|
||||
@@ -835,6 +930,8 @@ iface_modem_init (MMIfaceModemInterface *iface)
|
||||
{
|
||||
iface_modem_parent = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->load_unlock_required = load_unlock_required;
|
||||
iface->load_unlock_required_finish = load_unlock_required_finish;
|
||||
iface->modem_after_sim_unlock = modem_after_sim_unlock;
|
||||
iface->modem_after_sim_unlock_finish = modem_after_sim_unlock_finish;
|
||||
iface->load_supported_modes = load_supported_modes;
|
||||
|
||||
@@ -72,31 +72,6 @@ struct _MMBroadbandModemSimtechPrivate {
|
||||
MMModemLock sim_lock;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const gchar *result;
|
||||
MMModemLock code;
|
||||
} CPinResult;
|
||||
|
||||
static CPinResult unlock_results[] = {
|
||||
{ "READY", MM_MODEM_LOCK_NONE },
|
||||
{ "SIM PIN2", MM_MODEM_LOCK_SIM_PIN2 },
|
||||
{ "SIM PUK2", MM_MODEM_LOCK_SIM_PUK2 },
|
||||
{ "SIM PIN", MM_MODEM_LOCK_SIM_PIN },
|
||||
{ "SIM PUK", MM_MODEM_LOCK_SIM_PUK },
|
||||
{ "PH-NETSUB PIN", MM_MODEM_LOCK_PH_NETSUB_PIN },
|
||||
{ "PH-NETSUB PUK", MM_MODEM_LOCK_PH_NETSUB_PUK },
|
||||
{ "PH-FSIM PIN", MM_MODEM_LOCK_PH_FSIM_PIN },
|
||||
{ "PH-FSIM PUK", MM_MODEM_LOCK_PH_FSIM_PUK },
|
||||
{ "PH-CORP PIN", MM_MODEM_LOCK_PH_CORP_PIN },
|
||||
{ "PH-CORP PUK", MM_MODEM_LOCK_PH_CORP_PUK },
|
||||
{ "PH-SIM PIN", MM_MODEM_LOCK_PH_SIM_PIN },
|
||||
{ "PH-NET PIN", MM_MODEM_LOCK_PH_NET_PIN },
|
||||
{ "PH-NET PUK", MM_MODEM_LOCK_PH_NET_PUK },
|
||||
{ "PH-SP PIN", MM_MODEM_LOCK_PH_SP_PIN },
|
||||
{ "PH-SP PUK", MM_MODEM_LOCK_PH_SP_PUK },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Setup/Cleanup unsolicited events (3GPP interface) */
|
||||
|
||||
@@ -158,20 +133,10 @@ simtech_cpin_changed (MMPortSerialAt *port,
|
||||
MMBroadbandModemSimtech *self)
|
||||
{
|
||||
g_autofree gchar *str = NULL;
|
||||
CPinResult *iter;
|
||||
|
||||
str = mm_get_string_unquoted_from_match_info (match_info, 1);
|
||||
if (str) {
|
||||
iter = &unlock_results[0];
|
||||
/* Translate the reply */
|
||||
while (iter->result) {
|
||||
if (g_str_has_prefix (str, iter->result)) {
|
||||
self->priv->sim_lock = iter->code;
|
||||
return;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
if (str)
|
||||
self->priv->sim_lock = mm_parse_cpin_response (str, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -5089,6 +5089,37 @@ test_string_to_access_tech (void)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
const gchar *str;
|
||||
const gboolean expect_prefix;
|
||||
const MMModemLock expected_lock;
|
||||
} TestCpinResponse;
|
||||
|
||||
static const TestCpinResponse test_cpin_responses[] = {
|
||||
{ "+CME ERROR: 100", TRUE, MM_MODEM_LOCK_UNKNOWN },
|
||||
{ "+CPIN: SIM PIN", TRUE, MM_MODEM_LOCK_SIM_PIN },
|
||||
{ "+CPIN: SIM PUK2", TRUE, MM_MODEM_LOCK_SIM_PUK2 },
|
||||
{ " SIM PUK", FALSE, MM_MODEM_LOCK_SIM_PUK },
|
||||
{ " SIM PUK2", FALSE, MM_MODEM_LOCK_SIM_PUK2 },
|
||||
{ "+CPIN: \"SIM PIN\"", TRUE, MM_MODEM_LOCK_SIM_PIN },
|
||||
{ "+CPIN: PH-NET PIN", TRUE, MM_MODEM_LOCK_PH_NET_PIN },
|
||||
};
|
||||
|
||||
static void
|
||||
test_cpin_response (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (test_cpin_responses); i++) {
|
||||
MMModemLock lock;
|
||||
|
||||
lock = mm_parse_cpin_response (test_cpin_responses[i].str, test_cpin_responses[i].expect_prefix);
|
||||
g_assert_cmpint (lock, ==, test_cpin_responses[i].expected_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (GTestFixtureFunc) t, NULL)
|
||||
|
||||
int main (int argc, char **argv)
|
||||
@@ -5351,6 +5382,8 @@ int main (int argc, char **argv)
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_string_to_access_tech, NULL));
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_cpin_response, NULL));
|
||||
|
||||
result = g_test_run ();
|
||||
|
||||
reg_test_data_free (reg_data);
|
||||
|
||||
Reference in New Issue
Block a user