diff --git a/src/ofono.h b/src/ofono.h index 9d136845..30143f39 100644 --- a/src/ofono.h +++ b/src/ofono.h @@ -323,6 +323,10 @@ ofono_bool_t __ofono_is_valid_sim_pin(const char *pin, ofono_bool_t __ofono_is_valid_net_pin(const char *pin); +void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list, + ofono_bool_t full_file_change, + ofono_bool_t naa_init); + #include typedef void (*__ofono_sms_sim_download_cb_t)(ofono_bool_t ok, diff --git a/src/sim.c b/src/sim.c index c2e86315..7c2e151a 100644 --- a/src/sim.c +++ b/src/sim.c @@ -26,6 +26,7 @@ #define _GNU_SOURCE #include #include +#include #include #include @@ -2078,13 +2079,27 @@ static void sim_inserted_update(struct ofono_sim *sim) DBUS_TYPE_BOOLEAN, &present); } -static void sim_free_state(struct ofono_sim *sim) +static void sim_free_early_state(struct ofono_sim *sim) { if (sim->iccid) { g_free(sim->iccid); sim->iccid = NULL; } + if (sim->efli) { + g_free(sim->efli); + sim->efli = NULL; + sim->efli_length = 0; + } + + if (sim->language_prefs) { + g_strfreev(sim->language_prefs); + sim->language_prefs = NULL; + } +} + +static void sim_free_main_state(struct ofono_sim *sim) +{ if (sim->imsi) { g_free(sim->imsi); sim->imsi = NULL; @@ -2106,17 +2121,6 @@ static void sim_free_state(struct ofono_sim *sim) sim->service_numbers = NULL; } - if (sim->efli) { - g_free(sim->efli); - sim->efli = NULL; - sim->efli_length = 0; - } - - if (sim->language_prefs) { - g_strfreev(sim->language_prefs); - sim->language_prefs = NULL; - } - if (sim->efust) { g_free(sim->efust); sim->efust = NULL; @@ -2150,6 +2154,12 @@ static void sim_free_state(struct ofono_sim *sim) sim->barred_dialing = FALSE; } +static void sim_free_state(struct ofono_sim *sim) +{ + sim_free_early_state(sim); + sim_free_main_state(sim); +} + void ofono_sim_inserted_notify(struct ofono_sim *sim, ofono_bool_t inserted) { ofono_sim_state_event_cb_t notify; @@ -2442,3 +2452,132 @@ ofono_bool_t __ofono_is_valid_net_pin(const char *pin) { return is_valid_pin(pin, 4, 4); } + +static void sim_file_changed_flush(struct ofono_sim *sim, int id) +{ + int i, imgid; + + if (id == SIM_EFIMG_FILEID) + /* All cached images become invalid */ + sim_fs_image_cache_flush(sim->simfs); + else if (sim->efimg) { + /* + * Data and CLUT for image instances stored in the changed + * file need to be re-read. + */ + for (i = sim->efimg_length / 9 - 1; i >= 0; i--) { + imgid = (sim->efimg[i * 9 + 3] << 8) | + sim->efimg[i * 9 + 4]; + + if (imgid == id) + sim_fs_image_cache_flush_file(sim->simfs, i); + } + } + + sim_fs_cache_flush_file(sim->simfs, id); +} + +void __ofono_sim_refresh(struct ofono_sim *sim, GSList *file_list, + ofono_bool_t full_file_change, ofono_bool_t naa_init) +{ + GSList *l; + ofono_sim_state_event_cb_t notify; + gboolean reinit_naa = naa_init || full_file_change; + + /* + * Check if any files used in SIM initialisation procedure + * are affected, except EFiccid, EFpl, EFli. + */ + for (l = file_list; l; l = l->next) { + struct stk_file *file = l->data; + uint32_t mf, df, ef; + + if (file->len != 6) + continue; + + mf = (file->file[0] << 8) | (file->file[1] << 0); + df = (file->file[2] << 8) | (file->file[3] << 0); + ef = (file->file[4] << 8) | (file->file[5] << 0); + + if (mf != 0x3f00) + continue; + + /* + * 8.18: "the path '3F007FFF' indicates the relevant + * NAA Application dedicated file;". + */ + if (df == 0x7fff) + df = 0x7f20; + +#define DFGSM (0x7f20 << 16) +#define DFTEL (0x7f10 << 16) + + switch ((df << 16) | ef) { + case DFGSM | SIM_EFEST_FILEID: + case DFGSM | SIM_EFUST_FILEID: /* aka. EFSST */ + case DFGSM | SIM_EFPHASE_FILEID: + case DFGSM | SIM_EFAD_FILEID: + case DFTEL | SIM_EFBDN_FILEID: + case DFTEL | SIM_EFADN_FILEID: + case DFGSM | SIM_EF_CPHS_INFORMATION_FILEID: + reinit_naa = TRUE; + break; + } + } + + /* Flush cached content for affected files */ + if (full_file_change) + sim_fs_cache_flush(sim->simfs); + else { + for (l = file_list; l; l = l->next) { + struct stk_file *file = l->data; + int id = (file->file[file->len - 2] << 8) | + (file->file[file->len - 1] << 0); + + sim_file_changed_flush(sim, id); + } + } + + if (reinit_naa) { + /* Force the sim state out of READY */ + + sim_free_main_state(sim); + + sim->state = OFONO_SIM_STATE_INSERTED; + for (l = sim->state_watches->items; l; l = l->next) { + struct ofono_watchlist_item *item = l->data; + notify = item->notify; + + notify(sim->state, item->notify_data); + } + } + + /* + * Notify the subscribers of files that have changed and who + * haven't unsubsribed during the SIM state change. + */ + if (full_file_change) + sim_fs_notify_file_watches(sim->simfs, -1); + else { + for (l = file_list; l; l = l->next) { + struct stk_file *file = l->data; + int id = (file->file[file->len - 2] << 8) | + (file->file[file->len - 1] << 0); + + sim_fs_notify_file_watches(sim->simfs, id); + } + } + + if (reinit_naa) { + /* + * REVISIT: There's some concern that on re-insertion the + * atoms will start to talk to the SIM before it becomes + * ready, on certain SIMs. + */ + /* + * Start initialization procedure from after EFiccid, + * EFli and EFpl are retrieved. + */ + sim_pin_check(sim); + } +}