sim: Sim PIN1 cache upon modem reset/crash

Adding SIM PIN caching feature to oFono. oFono now caches the SIM PIN1
type against the ICCID throughout its lifetime in a link list and
enters implicitly upon modem reset/crash.

Note, that this behavior can violate 3GPP spec 21.111, section 5.3 -
User Data stored in ME if that section is interpreted very strictly.
However, our interpretation is that firmware resets are allowed, based
on historic precedent.  Helps in user experience by not barring out
cellular services unless pin is entered manually.

Handles cases of incorrect pin and sim pin changed externally.
Clear cached PIN incase modem disabled manually and selectively when
sim is removed.

Seperate 'pin_cache_enter_cb' added without dbus calls to handle
implict entering of cached pin.

For now this behavior is applicable to all modems by default.  In the
future it may be needed to make this behavior opt in or otherwise
configurable.
This commit is contained in:
Nandini Rebello 2019-01-16 12:07:17 +05:30 committed by Denis Kenzior
parent 08821bba5b
commit f36d6d05cc
2 changed files with 112 additions and 0 deletions

View File

@ -418,6 +418,7 @@ unsigned char *__ofono_sim_session_get_aid(
struct ofono_sim_aid_session *session);
const char *__ofono_sim_get_impi(struct ofono_sim *sim);
void __ofono_sim_clear_cached_pins(struct ofono_sim *sim);
#include <ofono/stk.h>

111
src/sim.c
View File

@ -143,6 +143,11 @@ struct ofono_sim {
bool wait_initialized : 1;
};
struct cached_pin {
char *id;
char *pin;
};
struct msisdn_set_request {
struct ofono_sim *sim;
int pending;
@ -178,6 +183,8 @@ static void sim_own_numbers_update(struct ofono_sim *sim);
static GSList *g_drivers = NULL;
static GSList *cached_pins = NULL;
static const char *sim_passwd_name(enum ofono_sim_password_type type)
{
return passwd_name[type];
@ -475,6 +482,68 @@ done:
return reply;
}
static struct cached_pin *pin_cache_lookup(const char *iccid)
{
struct cached_pin *c;
GSList *l;
if (cached_pins == NULL)
return NULL;
for (l = cached_pins; l; l = l->next) {
c = l->data;
if (g_strcmp0(iccid, c->id) == 0)
return c;
}
return NULL;
}
static void pin_cache_update(const char *iccid, const char *pin)
{
struct cached_pin *pin_cached = pin_cache_lookup(iccid);
struct cached_pin *cpins;
if (pin_cached != NULL) {
g_free(pin_cached->pin);
pin_cached->pin = g_strdup(pin);
return;
}
cpins = g_new0(struct cached_pin, 1);
cpins->id = g_strdup(iccid);
cpins->pin = g_strdup(pin);
cached_pins = g_slist_prepend(cached_pins, cpins);
}
static void pin_cache_remove(const char *iccid)
{
struct cached_pin *pin_cached = pin_cache_lookup(iccid);
if (pin_cached == NULL)
return;
cached_pins = g_slist_remove(cached_pins, pin_cached);
}
static void pin_cache_enter_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
pin_cache_remove(sim->iccid);
__ofono_sim_recheck_pin(sim);
return;
}
sim->wait_initialized = true;
DBG("Waiting for ofono_sim_initialized_notify");
}
static void sim_pin_retries_query_cb(const struct ofono_error *error,
int retries[OFONO_SIM_PASSWORD_INVALID],
void *data)
@ -683,6 +752,11 @@ static void sim_locked_cb(struct ofono_sim *sim, gboolean locked)
OFONO_SIM_MANAGER_INTERFACE,
"LockedPins", DBUS_TYPE_STRING,
&locked_pins);
/* Cache pin only for SIM PIN type */
if (g_strcmp0(typestr, "pin") == 0)
pin_cache_update(sim->iccid, pin);
g_strfreev(locked_pins);
sim_pin_retries_check(sim);
@ -778,6 +852,14 @@ static DBusMessage *sim_unlock_pin(DBusConnection *conn, DBusMessage *msg,
static void sim_change_pin_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
const char *typestr;
const char *old;
const char *new;
dbus_message_get_args(sim->pending, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
__ofono_dbus_pending_reply(&sim->pending,
@ -788,6 +870,10 @@ static void sim_change_pin_cb(const struct ofono_error *error, void *data)
return;
}
/* Cache pin only for SIM PIN type */
if (g_strcmp0(typestr, "pin") == 0)
pin_cache_update(sim->iccid, new);
__ofono_dbus_pending_reply(&sim->pending,
dbus_message_new_method_return(sim->pending));
@ -839,8 +925,14 @@ static DBusMessage *sim_change_pin(DBusConnection *conn, DBusMessage *msg,
static void sim_enter_pin_cb(const struct ofono_error *error, void *data)
{
struct ofono_sim *sim = data;
const char *typestr;
const char *pin;
DBusMessage *reply;
dbus_message_get_args(sim->pending, NULL, DBUS_TYPE_STRING, &typestr,
DBUS_TYPE_STRING, &pin,
DBUS_TYPE_INVALID);
if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
reply = __ofono_error_failed(sim->pending);
else
@ -852,6 +944,10 @@ static void sim_enter_pin_cb(const struct ofono_error *error, void *data)
if (sim->initialized || error->type != OFONO_ERROR_TYPE_NO_ERROR)
goto recheck;
/* Cache pin only for SIM PIN type */
if (g_strcmp0(typestr, "pin") == 0)
pin_cache_update(sim->iccid, pin);
if (sim->pin_type == OFONO_SIM_PASSWORD_SIM_PIN ||
sim->pin_type == OFONO_SIM_PASSWORD_SIM_PUK) {
sim->wait_initialized = true;
@ -2751,6 +2847,8 @@ void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted)
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PIN2] = -1;
sim->pin_retries[OFONO_SIM_PASSWORD_SIM_PUK2] = -1;
pin_cache_remove(sim->iccid);
sim_free_state(sim);
}
}
@ -3024,6 +3122,7 @@ static void sim_pin_query_cb(const struct ofono_error *error,
struct ofono_sim *sim = data;
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(sim->atom);
struct cached_pin *cpins = pin_cache_lookup(sim->iccid);
const char *pin_name;
char **locked_pins;
gboolean lock_changed;
@ -3068,6 +3167,10 @@ static void sim_pin_query_cb(const struct ofono_error *error,
&pin_name);
}
if (g_strcmp0(pin_name, "pin") == 0 && cpins != NULL)
sim->driver->send_passwd(sim, cpins->pin,
pin_cache_enter_cb, sim);
switch (pin_type) {
case OFONO_SIM_PASSWORD_NONE:
case OFONO_SIM_PASSWORD_SIM_PIN2:
@ -3301,6 +3404,14 @@ void ofono_sim_register(struct ofono_sim *sim)
__ofono_atom_register(sim->atom, sim_unregister);
}
void __ofono_sim_clear_cached_pins(struct ofono_sim *sim)
{
if (cached_pins == NULL)
return;
pin_cache_remove(sim->iccid);
}
void ofono_sim_remove(struct ofono_sim *sim)
{
__ofono_atom_free(sim->atom);