diff options
Diffstat (limited to 'sim.c')
-rw-r--r-- | sim.c | 1303 |
1 files changed, 1303 insertions, 0 deletions
@@ -0,0 +1,1303 @@ +/* + * This file is part of Samsung-RIL. + * + * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> + * + * Samsung-RIL is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Samsung-RIL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> + +#define LOG_TAG "RIL" +#include <utils/Log.h> + +#include <samsung-ril.h> +#include <utils.h> +#include <sim.h> + +#if RIL_VERSION >= 6 +RIL_RadioState ipc2ril_sec_pin_status_response(struct ipc_sec_pin_status_response_data *data, + RIL_CardStatus_v6 *card_status) +#else +RIL_RadioState ipc2ril_sec_pin_status_response(struct ipc_sec_pin_status_response_data *data, + RIL_CardStatus *card_status) +#endif +{ + RIL_AppStatus app_statuses[] = { + // Absent + { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, + // Not ready + { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, + // Ready + { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, + // PIN lock + { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // PUK lock + { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN }, + // PUK locked + { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN }, + // Perso network + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // Perso network subset + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // Perso corporate + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_CORPORATE, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + // Perso service provider + { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, + }; + RIL_RadioState radio_state; + unsigned int index; + unsigned int count; + unsigned int i; + + if (data == NULL || card_status == NULL) + return 0; + + count = sizeof(app_statuses) / sizeof(RIL_AppStatus); + + switch (data->status) { + case IPC_SEC_PIN_STATUS_LOCK_SC: + switch (data->facility_lock) { + case IPC_SEC_FACILITY_LOCK_TYPE_SC_UNLOCKED: + index = 2; + break; + case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ: + index = 3; + break; + case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ: + index = 4; + break; + case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED: + index = 5; + break; + default: + index = 0; + break; + } + break; + case IPC_SEC_PIN_STATUS_LOCK_FD: + index = 0; + break; + case IPC_SEC_PIN_STATUS_LOCK_PN: + index = 6; + break; + case IPC_SEC_PIN_STATUS_LOCK_PU: + index = 7; + break; + case IPC_SEC_PIN_STATUS_LOCK_PP: + index = 9; + break; + case IPC_SEC_PIN_STATUS_LOCK_PC: + index = 8; + break; + case IPC_SEC_PIN_STATUS_READY: + case IPC_SEC_PIN_STATUS_INIT_COMPLETE: + case IPC_SEC_PIN_STATUS_PB_INIT_COMPLETE: + index = 2; + break; + case IPC_SEC_PIN_STATUS_SIM_LOCK_REQUIRED: + case IPC_SEC_PIN_STATUS_INSIDE_PF_ERROR: + case IPC_SEC_PIN_STATUS_CARD_NOT_PRESENT: + case IPC_SEC_PIN_STATUS_CARD_ERROR: + default: + index = 0; + break; + } + + switch (index) { + case 1: + radio_state = RADIO_STATE_SIM_NOT_READY; + break; + case 2: + radio_state = RADIO_STATE_SIM_READY; + break; + default: + radio_state = RADIO_STATE_SIM_LOCKED_OR_ABSENT; + } + +#if RIL_VERSION >= 6 + memset(card_status, 0, sizeof(RIL_CardStatus_v6)); +#else + memset(card_status, 0, sizeof(RIL_CardStatus)); +#endif + + if (index == 0) + card_status->card_state = RIL_CARDSTATE_ABSENT; + else + card_status->card_state = RIL_CARDSTATE_PRESENT; + + card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN; + + card_status->cdma_subscription_app_index = -1; +#if RIL_VERSION >= 7 + card_status->ims_subscription_app_index = -1; +#endif + + memcpy((void *) &card_status->applications[0], (void *) &app_statuses[index], sizeof(RIL_AppStatus)); + + card_status->gsm_umts_subscription_app_index = 0; + card_status->num_applications = 1; + + RIL_LOGD("%s: Selecting status application %d on %d", __func__, index, count); + + return radio_state; +} + +unsigned char ril2ipc_sec_facility_type(char *facility) +{ + if (facility == NULL) + return 0; + + if (!strcmp(facility, "SC")) + return IPC_SEC_FACILITY_TYPE_SC; + else if (!strcmp(facility, "FD")) + return IPC_SEC_FACILITY_TYPE_FD; + else if (!strcmp(facility, "PN")) + return IPC_SEC_FACILITY_TYPE_PN; + else if (!strcmp(facility, "PU")) + return IPC_SEC_FACILITY_TYPE_PU; + else if (!strcmp(facility, "PP")) + return IPC_SEC_FACILITY_TYPE_PP; + else if (!strcmp(facility, "PC")) + return IPC_SEC_FACILITY_TYPE_PC; + else + return 0; +} + +int ipc_sec_pin_status_callback(struct ipc_message *message) +{ + struct ipc_gen_phone_res_data *data; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + // Return the original SIM status + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); + } else { + // Destroy the original SIM status + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + } + + return 0; +} + +int ipc_sec_pin_status(struct ipc_message *message) +{ + struct ipc_sec_pin_status_response_data *data; + struct ipc_sec_pin_status_request_data request_data; +#if RIL_VERSION >= 6 + RIL_CardStatus_v6 card_status; +#else + RIL_CardStatus card_status; +#endif + RIL_RadioState radio_state; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_pin_status_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + data = (struct ipc_sec_pin_status_response_data *) message->data; + + radio_state = ipc2ril_sec_pin_status_response(data, &card_status); + if (radio_state == 0) + return 0; + + if (card_status.applications[0].app_type == RIL_APPTYPE_SIM && card_status.applications[0].app_state == RIL_APPSTATE_PIN && ril_data->sim_pin != NULL) { + ril_request_data_set_uniq(RIL_REQUEST_GET_SIM_STATUS, (void *) &card_status, sizeof(card_status)); + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, ril_data->sim_pin, NULL); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + return 0; + } + + rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_SEC_PIN_STATUS, ipc_sec_pin_status_callback); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + return 0; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS); + return 0; + } + + return 0; + } + + ril_radio_state_update(radio_state); + + if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &card_status, sizeof(card_status)); + } else { + ril_request_data_set_uniq(RIL_REQUEST_GET_SIM_STATUS, (void *) &card_status, sizeof(card_status)); + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); + } + + return 0; +} + +int ril_request_get_sim_status(void *data, size_t size, RIL_Token token) +{ + void *card_status_data; + size_t card_status_size; +#if RIL_VERSION >= 6 + RIL_CardStatus_v6 *card_status; +#else + RIL_CardStatus *card_status; +#endif + struct ril_request *request; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_GET_SIM_STATUS, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + card_status_size = ril_request_data_size_get(RIL_REQUEST_GET_SIM_STATUS); + card_status_data = ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS); + +#if RIL_VERSION >= 6 + if (card_status_data != NULL && card_status_size >= sizeof(RIL_CardStatus_v6)) { + card_status = (RIL_CardStatus_v6 *) ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS); +#else + if (card_status_data != NULL && card_status_size >= sizeof(RIL_CardStatus)) { + card_status = (RIL_CardStatus *) ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS); +#endif + ril_request_complete(token, RIL_E_SUCCESS, card_status_data, card_status_size); + + free(card_status_data); + + return RIL_REQUEST_COMPLETED; + } else { + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + return RIL_REQUEST_HANDLED; + } +} + +int ipc_sec_phone_lock(struct ipc_message *message) +{ + struct ipc_sec_phone_lock_response_data *data; + int active; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_phone_lock_response_data)) + return -1; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_sec_phone_lock_response_data *) message->data; + + active = !!data->active; + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &active, sizeof(active)); + + return 0; +} + +int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_phone_lock_request_get_data request_data; + char **values = NULL; + int rc; + + if (data == NULL || size < 4 * sizeof(char *)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + request_data.facility_type = ril2ipc_sec_facility_type(values[0]); + if (request_data.facility_type == 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_sec_callback(struct ipc_message *message) +{ + struct ipc_sec_lock_infomation_request_data request_data; + struct ipc_gen_phone_res_data *data; + struct ril_request *request = NULL; + void *request_complete_data; + size_t request_complete_size; + unsigned char facility_type; + char **values; + int retry_count; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; + + data = (struct ipc_gen_phone_res_data *) message->data; + + request = ril_request_find_token(ipc_fmt_request_token(message->aseq)); + if (request == NULL) + goto error; + + if (request->request == RIL_REQUEST_ENTER_SIM_PIN || request->request == RIL_REQUEST_CHANGE_SIM_PIN) { + // Grab the count of remaining tries before completing the request + + ril_request_data_set_uniq(request->request, (void *) data, sizeof(struct ipc_gen_phone_res_data)); + + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } else if (request->request == RIL_REQUEST_ENTER_SIM_PIN2 || request->request == RIL_REQUEST_CHANGE_SIM_PIN2) { + // Grab the count of remaining tries before completing the request + + ril_request_data_set_uniq(request->request, (void *) data, sizeof(struct ipc_gen_phone_res_data)); + + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } else if (request->request == RIL_REQUEST_SET_FACILITY_LOCK) { + values = (char **) request->data; + + request_complete_size = ril_request_data_size_get(RIL_REQUEST_SET_FACILITY_LOCK); + request_complete_data = ril_request_data_get(RIL_REQUEST_SET_FACILITY_LOCK); + + rc = ipc_gen_phone_res_check(data); + + if (request_complete_data != NULL && request_complete_size > 0 && rc >= 0) { + rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_SEC_PHONE_LOCK, ipc_sec_callback); + if (rc < 0) { + strings_array_free(values, request->size); + goto error; + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, request_complete_data, request_complete_size); + if (rc < 0) { + strings_array_free(values, request->size); + goto error; + } + } else { + // When FD facility PIN2 unlock failed, ask the count of remaining tries directly + + facility_type = ril2ipc_sec_facility_type(values[0]); + + strings_array_free(values, request->size); + + // Grab the count of remaining tries before completing the request + + ril_request_data_set_uniq(RIL_REQUEST_SET_FACILITY_LOCK, (void *) data, sizeof(struct ipc_gen_phone_res_data)); + + if (facility_type == IPC_SEC_FACILITY_TYPE_FD) { + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } else { + rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } + + rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) { + ril_request_data_free(request->request); + goto error; + } + } + } else if (request->request == RIL_REQUEST_SIM_IO) { + request_complete_size = ril_request_data_size_get(RIL_REQUEST_SIM_IO); + request_complete_data = ril_request_data_get(RIL_REQUEST_SIM_IO); + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + ril_request_complete(request->token, RIL_E_SIM_PIN2, NULL, 0); + goto complete; + } + + if (request_complete_data != NULL && request_complete_size > 0) { + rc = ipc_fmt_send(message->aseq, IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, request_complete_data, request_complete_size); + if (rc < 0) + goto error; + } else { + goto error; + } + } else { + retry_count = -1; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) { + if ((data->code & 0xff) == 0x10) { + RIL_LOGE("%s: Wrong password", __func__); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else if ((data->code & 0xff) == 0x0c) { + RIL_LOGE("%s: Wrong password and no attempts left", __func__); + retry_count = 0; + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, &retry_count, sizeof(retry_count)); + } + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &retry_count, sizeof(retry_count)); + } + } + + if (request->request == RIL_REQUEST_ENTER_SIM_PUK || request->request == RIL_REQUEST_ENTER_SIM_PUK2) + ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); + + goto complete; + +error: + if (request != NULL) + ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; +} + +int ril_request_set_facility_lock(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_phone_lock_request_set_data request_data; + struct ipc_sec_pin_status_request_data pin_request_data; + struct ril_request *request; + unsigned char facility_type; + unsigned char active; + char **values = NULL; + int rc; + + if (data == NULL || size < 4 * sizeof(char *)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_SET_FACILITY_LOCK, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + facility_type = ril2ipc_sec_facility_type(values[0]); + if (facility_type == 0) + goto error; + + active = values[1][0] == '1'; + + rc = ipc_sec_phone_lock_request_set_setup(&request_data, facility_type, active, values[2]); + if (rc < 0) + goto error; + + if (facility_type == IPC_SEC_FACILITY_TYPE_FD) { + // FD facility requires PIN2 unlock first + + rc = ipc_sec_pin_status_setup(&pin_request_data, IPC_SEC_PIN_TYPE_PIN2, values[2], NULL); + if (rc < 0) + goto error; + + ril_request_data_set_uniq(RIL_REQUEST_SET_FACILITY_LOCK, &request_data, sizeof(request_data)); + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SET_FACILITY_LOCK); + goto error; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_request_data, sizeof(pin_request_data)); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SET_FACILITY_LOCK); + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + } + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_pin(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *) || ril_data == NULL) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PIN, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + if (values[0] == NULL) + goto error; + + if (ril_data->sim_pin != NULL) + free(ril_data->sim_pin); + + ril_data->sim_pin = strdup(values[0]); + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, values[0], NULL); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_puk(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PUK, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, values[1], values[0]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_pin2(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PIN2, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2, values[0], NULL); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_enter_sim_puk2(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_pin_status_request_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 2 * sizeof(char *)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PUK2, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2, values[1], values[0]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_change_sim_pin(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_change_locking_pw_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 3 * sizeof(char *)) + goto error; + + request = ril_request_find_request_status(RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_change_locking_pw_setup(&request_data, IPC_SEC_FACILITY_TYPE_SC, values[0], values[1]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_change_sim_pin2(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_change_locking_pw_data request_data; + struct ril_request *request; + char **values = NULL; + int rc; + + if (data == NULL || size < 3 * sizeof(char *)) + goto error; + + request = ril_request_find_request_status(RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + values = (char **) data; + + rc = ipc_sec_change_locking_pw_setup(&request_data, IPC_SEC_FACILITY_TYPE_FD, values[0], values[1]); + if (rc < 0) + goto error; + + strings_array_free(values, size); + values = NULL; + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_callback); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (values != NULL) + strings_array_free(values, size); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_sec_rsim_access(struct ipc_message *message) +{ + struct ipc_sec_rsim_access_response_header *header; + struct ipc_sec_rsim_access_usim_response_header *usim_header; + struct sim_file_response sim_file_response; + struct ril_request *request; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + RIL_SIM_IO_Response response; +#if RIL_VERSION >= 6 + RIL_SIM_IO_v6 *sim_io; +#else + RIL_SIM_IO *sim_io; +#endif + unsigned char *p; + unsigned int offset; + unsigned int i; + void *data; + size_t size; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_rsim_access_response_header)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + header = (struct ipc_sec_rsim_access_response_header *) message->data; + + size = ipc_sec_rsim_access_size_extract(message->data, message->size); + data = ipc_sec_rsim_access_extract(message->data, message->size); + + request = ril_request_find_token(ipc_fmt_request_token(message->aseq)); +#if RIL_VERSION >= 6 + if (request == NULL || request->data == NULL || request->size < sizeof(RIL_SIM_IO_v6)) +#else + if (request == NULL || request->data == NULL || request->size < sizeof(RIL_SIM_IO)) +#endif + return 0; + +#if RIL_VERSION >= 6 + sim_io = (RIL_SIM_IO_v6 *) request->data; +#else + sim_io = (RIL_SIM_IO *) request->data; +#endif + + memset(&response, 0, sizeof(response)); + response.sw1 = header->sw1; + response.sw2 = header->sw2; + + switch (sim_io->command) { + case SIM_COMMAND_READ_BINARY: + case SIM_COMMAND_READ_RECORD: + if (header->length == 0) + break; + + response.simResponse = data2string(data, header->length); + break; + case SIM_COMMAND_GET_RESPONSE: + if (header->length == 0) + break; + + if (ipc_fmt_data->sim_icc_type_data.type == 0x01) { + response.simResponse = data2string(data, header->length); + break; + } + + if (header->length < sizeof(struct ipc_sec_rsim_access_usim_response_header)) + break; + + usim_header = (struct ipc_sec_rsim_access_usim_response_header *) data; + + memset(&sim_file_response, 0, sizeof(sim_file_response)); + + offset = sizeof(struct ipc_sec_rsim_access_usim_response_header) + usim_header->offset; + if (offset > header->length) + break; + + offset = usim_header->offset - 2; + p = (unsigned char *) usim_header + offset; + + sim_file_response.file_id[0] = p[0]; + sim_file_response.file_id[1] = p[1]; + + offset = header->length - 2; + p = (unsigned char *) usim_header; + + while (offset > 2) { + if (p[offset] == 0x88) { + offset -= 2; + break; + } + + offset--; + } + + if (offset <= 2) + break; + + p = (unsigned char *) usim_header + offset; + + sim_file_response.file_size[0] = p[0]; + sim_file_response.file_size[1] = p[1]; + + // Fallback to EF + sim_file_response.file_type = SIM_FILE_TYPE_EF; + for (i = 0; i < sim_file_ids_count; i++) { + if (sim_io->fileid == sim_file_ids[i].file_id) { + sim_file_response.file_type = sim_file_ids[i].type; + break; + } + } + + sim_file_response.access_condition[0] = 0x00; + sim_file_response.access_condition[1] = 0xff; + sim_file_response.access_condition[2] = 0xff; + + sim_file_response.file_status = 0x01; + sim_file_response.file_length = 0x02; + + switch (usim_header->file_structure) { + case IPC_SEC_RSIM_FILE_STRUCTURE_TRANSPARENT: + sim_file_response.file_structure = SIM_FILE_STRUCTURE_TRANSPARENT; + break; + case IPC_SEC_RSIM_FILE_STRUCTURE_LINEAR_FIXED: + default: + sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED; + break; + } + + sim_file_response.record_length = usim_header->length; + + response.simResponse = data2string((void *) &sim_file_response, sizeof(sim_file_response)); + break; + case SIM_COMMAND_UPDATE_BINARY: + case SIM_COMMAND_UPDATE_RECORD: + case SIM_COMMAND_SEEK: + default: + response.simResponse = NULL; + break; + } + + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &response, sizeof(response)); + + if (response.simResponse != NULL) + free(response.simResponse); + + return 0; +} + +int ril_request_sim_io(void *data, size_t size, RIL_Token token) +{ + struct ipc_sec_rsim_access_request_header request_header; + struct ipc_sec_pin_status_request_data pin_request_data; + struct ril_request *request; +#if RIL_VERSION >= 6 + RIL_SIM_IO_v6 *sim_io = NULL; +#else + RIL_SIM_IO *sim_io = NULL; +#endif + void *sim_io_data = NULL; + size_t sim_io_size = 0; + void *request_data = NULL; + size_t request_size = 0; + int pin_request = 0; + int rc; + +#if RIL_VERSION >= 6 + if (data == NULL || size < sizeof(RIL_SIM_IO_v6)) +#else + if (data == NULL || size < sizeof(RIL_SIM_IO)) +#endif + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_SIM_IO, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + +#if RIL_VERSION >= 6 + sim_io = (RIL_SIM_IO_v6 *) data; +#else + sim_io = (RIL_SIM_IO *) data; +#endif + + if (sim_io->data != NULL) { + sim_io_size = string2data_size(sim_io->data); + if (sim_io_size == 0) + goto error; + + sim_io_data = string2data(sim_io->data); + if (sim_io_data == NULL) + goto error; + } + + if (sim_io->pin2 != NULL) { + // PIN2 unlock first + + pin_request = 1; + + rc = ipc_sec_pin_status_setup(&pin_request_data, IPC_SEC_PIN_TYPE_PIN2, sim_io->pin2, NULL); + if (rc < 0) + goto error; + } + + if (sim_io->path != NULL) + free(sim_io->path); + + if (sim_io->data != NULL) + free(sim_io->data); + + if (sim_io->pin2 != NULL) + free(sim_io->pin2); + +#if RIL_VERSION >= 6 + if (sim_io->aidPtr != NULL) + free(sim_io->aidPtr); +#endif + + memset(&request_header, 0, sizeof(request_header)); + request_header.command = sim_io->command; + request_header.file_id = sim_io->fileid; + request_header.p1 = sim_io->p1; + request_header.p2 = sim_io->p2; + request_header.p3 = sim_io->p3; + + sim_io = NULL; + + request_size = ipc_sec_rsim_access_size_setup(&request_header, sim_io_data, sim_io_size); + if (request_size == 0) + goto error; + + request_data = ipc_sec_rsim_access_setup(&request_header, sim_io_data, sim_io_size); + if (request_data == NULL) + goto error; + + if (pin_request) { + // PIN2 unlock first + + ril_request_data_set_uniq(RIL_REQUEST_SIM_IO, request_data, request_size); + + rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SIM_IO); + goto error; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_request_data, sizeof(pin_request_data)); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_SIM_IO); + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + } + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, request_data, request_size); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (sim_io != NULL) { + if (sim_io->path != NULL) + free(sim_io->path); + + if (sim_io->data != NULL) + free(sim_io->data); + + if (sim_io->pin2 != NULL) + free(sim_io->pin2); + +#if RIL_VERSION >= 6 + if (sim_io->aidPtr != NULL) + free(sim_io->aidPtr); +#endif + } + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + if (sim_io_data != NULL && sim_io_size > 0) + free(sim_io_data); + + if (request_data != NULL && request_size > 0) + free(request_data); + + return rc; +} + +int ipc_sec_sim_icc_type(struct ipc_message *message) +{ + struct ipc_sec_sim_icc_type_data *data; + struct ril_client *client; + struct ipc_fmt_data *ipc_fmt_data; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_sim_icc_type_data)) + return -1; + + client = ril_client_find_id(RIL_CLIENT_IPC_FMT); + if (client == NULL || client->data == NULL) + return 0; + + ipc_fmt_data = (struct ipc_fmt_data *) client->data; + + data = (struct ipc_sec_sim_icc_type_data *) message->data; + + if (ipc_fmt_data->sim_icc_type_data.type != data->type) + ipc_fmt_data->sim_icc_type_data.type = data->type; + + return 0; +} + +int ipc_sec_lock_infomation(struct ipc_message *message) +{ + struct ipc_sec_lock_infomation_response_data *data; + struct ipc_gen_phone_res_data *gen_phone_res; + int requests[] = { RIL_REQUEST_ENTER_SIM_PIN, RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_ENTER_SIM_PIN2, RIL_REQUEST_CHANGE_SIM_PIN2, RIL_REQUEST_SET_FACILITY_LOCK }; + void *gen_phone_res_data = NULL; + size_t gen_phone_res_size = 0; + int retry_count; + unsigned int count; + unsigned int i; + int rc; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_lock_infomation_response_data)) + return -1; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return 0; + + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; + + data = (struct ipc_sec_lock_infomation_response_data *) message->data; + if (data->type != IPC_SEC_PIN_TYPE_PIN1 && data->type != IPC_SEC_PIN_TYPE_PIN2) + return 0; + + count = sizeof(requests) / sizeof(int); + + for (i = 0; i < count; i++) { + gen_phone_res_size = ril_request_data_size_get(requests[i]); + if (gen_phone_res_size < sizeof(struct ipc_gen_phone_res_data)) + continue; + + gen_phone_res_data = ril_request_data_get(requests[i]); + if (gen_phone_res_data == NULL) + continue; + + break; + } + + if (gen_phone_res_data == NULL || gen_phone_res_size < sizeof(struct ipc_gen_phone_res_data)) + return 0; + + gen_phone_res = (struct ipc_gen_phone_res_data *) gen_phone_res_data; + + retry_count = data->retry_count; + + rc = ipc_gen_phone_res_check(gen_phone_res); + if (rc < 0) { + if ((gen_phone_res->code & 0xff) == 0x10) { + RIL_LOGE("%s: Wrong password and %d attempts left", __func__, retry_count); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else if ((gen_phone_res->code & 0xff) == 0x0c) { + RIL_LOGE("%s: Wrong password and no attempts left", __func__); + retry_count = 0; + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count)); + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, &retry_count, sizeof(retry_count)); + } + } else { + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &retry_count, sizeof(retry_count)); + } + + free(gen_phone_res_data); + + return 0; +} |