diff options
author | Andrzej Zaborowski <andrew.zaborowski@intel.com> | 2009-09-17 22:43:22 +0200 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2009-09-22 00:07:06 -0500 |
commit | ee02b14836d7e30b45ee6fd62da6a8135c94c9dd (patch) | |
tree | ebe561c1cb248e4a11643fdc09e61246520cda97 /drivers | |
parent | b1c8b291f5c8d1802b889756c01cc2f7f5288641 (diff) | |
download | ofono-ee02b14836d7e30b45ee6fd62da6a8135c94c9dd.tar.bz2 |
Do PIN authentication
This adds checking whether PIN is required during SIM initialisation and
delaying the sim ready notifications until after correct PIN is given.
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/atmodem/sim.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c index c629ec1d..b6f34c20 100644 --- a/drivers/atmodem/sim.c +++ b/drivers/atmodem/sim.c @@ -398,6 +398,242 @@ error: CALLBACK_WITH_FAILURE(cb, NULL, data); } +static struct { + enum ofono_passwd_type type; + const char *name; +} const at_sim_name[] = { + { OFONO_PASSWD_SIM_PIN, "SIM PIN" }, + { OFONO_PASSWD_SIM_PUK, "SIM PUK" }, + { OFONO_PASSWD_PHSIM_PIN, "PH-SIM PIN" }, + { OFONO_PASSWD_PHFSIM_PIN, "PH-FSIM PIN" }, + { OFONO_PASSWD_PHFSIM_PUK, "PH-FSIM PUK" }, + { OFONO_PASSWD_SIM_PIN2, "SIM PIN2" }, + { OFONO_PASSWD_SIM_PUK2, "SIM PUK2" }, + { OFONO_PASSWD_PHNET_PIN, "PH-NET PIN" }, + { OFONO_PASSWD_PHNET_PUK, "PH-NET PUK" }, + { OFONO_PASSWD_PHNETSUB_PIN, "PH-NETSUB PIN" }, + { OFONO_PASSWD_PHNETSUB_PUK, "PH-NETSUB PUK" }, + { OFONO_PASSWD_PHSP_PIN, "PH-SP PIN" }, + { OFONO_PASSWD_PHSP_PUK, "PH-SP PUK" }, + { OFONO_PASSWD_PHCORP_PIN, "PH-CORP PIN" }, + { OFONO_PASSWD_PHCORP_PUK, "PH-CORP PUK" }, +}; + +static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct cb_data *cbd = user_data; + GAtResultIter iter; + ofono_sim_passwd_cb_t cb = cbd->cb; + struct ofono_error error; + const char *pin_required; + int pin_type; + int i; + int len = sizeof(at_sim_name) / sizeof(*at_sim_name); + + dump_response("at_cpin_cb", ok, result); + decode_at_error(&error, g_at_result_final_response(result)); + + if (!ok) { + cb(&error, -1, cbd->data); + return; + } + + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CPIN:")) { + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + return; + } + + g_at_result_iter_next_unquoted_string(&iter, &pin_required); + + pin_type = -1; + if (!strcmp(pin_required, "READY")) + pin_type = OFONO_PASSWD_NONE; + else + for (i = 0; i < len; i++) + if (!strcmp(pin_required, at_sim_name[i].name)) { + pin_type = at_sim_name[i].type; + break; + } + + if (pin_type == -1) { + CALLBACK_WITH_FAILURE(cb, -1, cbd->data); + return; + } + + ofono_debug("crsm_pin_cb: %s", pin_required); + + cb(&error, pin_type, cbd->data); +} + +static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb, + void *data) +{ + GAtChat *chat = ofono_sim_get_data(sim); + struct cb_data *cbd = cb_data_new(cb, data); + + if (!cbd) + goto error; + + if (g_at_chat_send(chat, "AT+CPIN?", NULL, + at_cpin_cb, cbd, g_free) > 0) + return; + +error: + if (cbd) + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, -1, data); +} + +static void at_lock_unlock_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + ofono_sim_lock_unlock_cb_t cb = cbd->cb; + struct ofono_error error; + + dump_response("at_lock_unlock_cb", ok, result); + decode_at_error(&error, g_at_result_final_response(result)); + + cb(&error, cbd->data); +} + +static void at_pin_send(struct ofono_sim *sim, const char *passwd, + ofono_sim_lock_unlock_cb_t cb, void *data) +{ + GAtChat *chat = ofono_sim_get_data(sim); + struct cb_data *cbd = cb_data_new(cb, data); + char buf[64]; + int ret; + + if (!cbd) + goto error; + + snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd); + + ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free); + + memset(buf, 0, sizeof(buf)); + + if (ret > 0) + return; + +error: + if (cbd) + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, data); +} + +static void at_pin_send_puk(struct ofono_sim *sim, const char *puk, + const char *passwd, + ofono_sim_lock_unlock_cb_t cb, void *data) +{ + GAtChat *chat = ofono_sim_get_data(sim); + struct cb_data *cbd = cb_data_new(cb, data); + char buf[64]; + int ret; + + if (!cbd) + goto error; + + snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd); + + ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free); + + memset(buf, 0, sizeof(buf)); + + if (ret > 0) + return; + +error: + if (cbd) + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, data); +} + +static const char *const at_clck_cpwd_fac[] = { + [OFONO_PASSWD_SIM_PIN] = "SC", + [OFONO_PASSWD_SIM_PIN2] = "P2", + [OFONO_PASSWD_PHSIM_PIN] = "PS", + [OFONO_PASSWD_PHFSIM_PIN] = "PF", + [OFONO_PASSWD_PHNET_PIN] = "PN", + [OFONO_PASSWD_PHNETSUB_PIN] = "PU", + [OFONO_PASSWD_PHSP_PIN] = "PP", + [OFONO_PASSWD_PHCORP_PIN] = "PC", +}; + +static void at_pin_enable(struct ofono_sim *sim, int passwd_type, int enable, + const char *passwd, + ofono_sim_lock_unlock_cb_t cb, void *data) +{ + GAtChat *chat = ofono_sim_get_data(sim); + struct cb_data *cbd = cb_data_new(cb, data); + char buf[64]; + int ret; + int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac); + + if (!cbd) + goto error; + + if (passwd_type < 0 || passwd_type >= len || + !at_clck_cpwd_fac[passwd_type]) + goto error; + + snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"", + at_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd); + + ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free); + + memset(buf, 0, sizeof(buf)); + + if (ret > 0) + return; + +error: + if (cbd) + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, data); +} + +static void at_change_passwd(struct ofono_sim *sim, int passwd_type, + const char *old, const char *new, + ofono_sim_lock_unlock_cb_t cb, void *data) +{ + GAtChat *chat = ofono_sim_get_data(sim); + struct cb_data *cbd = cb_data_new(cb, data); + char buf[64]; + int ret; + int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac); + + if (!cbd) + goto error; + + if (passwd_type < 0 || passwd_type >= len || + !at_clck_cpwd_fac[passwd_type]) + goto error; + + snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"", + at_clck_cpwd_fac[passwd_type], old, new); + + ret = g_at_chat_send(chat, buf, NULL, at_lock_unlock_cb, cbd, g_free); + + memset(buf, 0, sizeof(buf)); + + if (ret > 0) + return; + +error: + if (cbd) + g_free(cbd); + + CALLBACK_WITH_FAILURE(cb, data); +} + static gboolean at_sim_register(gpointer user) { struct ofono_sim *sim = user; @@ -434,6 +670,11 @@ static struct ofono_sim_driver driver = { .write_file_linear = at_sim_update_record, .write_file_cyclic = at_sim_update_cyclic, .read_imsi = at_read_imsi, + .query_passwd_state = at_pin_query, + .send_passwd = at_pin_send, + .reset_passwd = at_pin_send_puk, + .lock = at_pin_enable, + .change_passwd = at_change_passwd, }; void at_sim_init() |