/* * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram * Copyright (C) 2011-2013 Paul Kocialkowski * * 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 . */ #define LOG_TAG "RIL-SEC" #include #include "samsung-ril.h" #include "util.h" #include ril_sim_state ipc2ril_sim_state(struct ipc_sec_sim_status_response *pin_status) { if (pin_status == NULL) return -EINVAL; switch (pin_status->status) { case IPC_SEC_SIM_STATUS_LOCK_SC: switch (pin_status->facility_lock) { case IPC_SEC_FACILITY_LOCK_TYPE_SC_UNLOCKED: return SIM_STATE_READY; case IPC_SEC_FACILITY_LOCK_TYPE_SC_PIN1_REQ: return SIM_STATE_PIN; case IPC_SEC_FACILITY_LOCK_TYPE_SC_PUK_REQ: return SIM_STATE_PUK; case IPC_SEC_FACILITY_LOCK_TYPE_SC_CARD_BLOCKED: return SIM_STATE_BLOCKED; default: RIL_LOGE("Unknown SIM facility lock: 0x%x", pin_status->facility_lock); return SIM_STATE_ABSENT; } break; case IPC_SEC_SIM_STATUS_LOCK_FD: return SIM_STATE_ABSENT; case IPC_SEC_SIM_STATUS_LOCK_PN: return SIM_STATE_NETWORK_PERSO; case IPC_SEC_SIM_STATUS_LOCK_PU: return SIM_STATE_NETWORK_SUBSET_PERSO; case IPC_SEC_SIM_STATUS_LOCK_PP: return SIM_STATE_SERVICE_PROVIDER_PERSO; case IPC_SEC_SIM_STATUS_LOCK_PC: return SIM_STATE_CORPORATE_PERSO; case IPC_SEC_SIM_STATUS_READY: case IPC_SEC_SIM_STATUS_INIT_COMPLETE: case IPC_SEC_SIM_STATUS_PB_INIT_COMPLETE: return SIM_STATE_READY; case IPC_SEC_SIM_STATUS_SIM_LOCK_REQUIRED: case IPC_SEC_SIM_STATUS_INSIDE_PF_ERROR: case IPC_SEC_SIM_STATUS_CARD_NOT_PRESENT: case IPC_SEC_SIM_STATUS_CARD_ERROR: return SIM_STATE_ABSENT; default: RIL_LOGE("Unknown SIM status: 0x%x", pin_status->status); return SIM_STATE_ABSENT; } } void ril_state_update(ril_sim_state sim_state) { RIL_RadioState radio_state; ril_data.state.sim_state = sim_state; switch (sim_state) { case SIM_STATE_READY: #if RIL_VERSION >= 7 radio_state = RADIO_STATE_ON; #else radio_state = RADIO_STATE_SIM_READY; #endif break; case SIM_STATE_NOT_READY: radio_state = RADIO_STATE_SIM_NOT_READY; break; case SIM_STATE_ABSENT: case SIM_STATE_PIN: case SIM_STATE_PUK: case SIM_STATE_BLOCKED: case SIM_STATE_NETWORK_PERSO: case SIM_STATE_NETWORK_SUBSET_PERSO: case SIM_STATE_CORPORATE_PERSO: case SIM_STATE_SERVICE_PROVIDER_PERSO: radio_state = RADIO_STATE_SIM_LOCKED_OR_ABSENT; break; default: radio_state = RADIO_STATE_SIM_NOT_READY; break; } ril_radio_state_update(radio_state); } #if RIL_VERSION >= 6 void ipc2ril_card_status(struct ipc_sec_sim_status_response *pin_status, RIL_CardStatus_v6 *card_status) #else void ipc2ril_card_status(struct ipc_sec_sim_status_response *pin_status, RIL_CardStatus *card_status) #endif { ril_sim_state sim_state; int app_status_array_length; int app_index; int i; if (pin_status == NULL || card_status == NULL) return; static RIL_AppStatus app_status_array[] = { /* SIM_ABSENT = 0 */ { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, /* SIM_NOT_READY = 1 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, /* SIM_READY = 2 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN }, /* SIM_PIN = 3 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, /* SIM_PUK = 4 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN }, /* SIM_BLOCKED = 4 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN }, /* SIM_NETWORK_PERSO = 6 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, /* SIM_NETWORK_SUBSET_PERSO = 7 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK_SUBSET, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, /* SIM_CORPORATE_PERSO = 8 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_CORPORATE, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, /* SIM_SERVICE_PROVIDER_PERSO = 9 */ { RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN }, }; app_status_array_length = sizeof(app_status_array) / sizeof(RIL_AppStatus); if (app_status_array_length > RIL_CARD_MAX_APPS) app_status_array_length = RIL_CARD_MAX_APPS; sim_state = ipc2ril_sim_state(pin_status); /* Card is assumed to be present if not explicitly absent */ if (sim_state == SIM_STATE_ABSENT) { card_status->card_state = RIL_CARDSTATE_ABSENT; } else { card_status->card_state = RIL_CARDSTATE_PRESENT; } // FIXME: How do we know that? card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN; // Initialize the apps for (i = 0 ; i < app_status_array_length ; i++) { memcpy((void *) &(card_status->applications[i]), (void *) &(app_status_array[i]), sizeof(RIL_AppStatus)); } for (i = app_status_array_length ; i < RIL_CARD_MAX_APPS ; i++) { memset((void *) &(card_status->applications[i]), 0, sizeof(RIL_AppStatus)); } // sim_state corresponds to the app index on the table card_status->gsm_umts_subscription_app_index = (int) sim_state; card_status->cdma_subscription_app_index = (int) sim_state; card_status->num_applications = app_status_array_length; RIL_LOGD("Selecting application #%d on %d", (int) sim_state, app_status_array_length); } void ril_tokens_pin_status_dump(void) { RIL_LOGD("ril_tokens_pin_status_dump:\n\ \tril_data.tokens.pin_status = %p\n", ril_data.tokens.pin_status); } void ipc_sec_sim_status(struct ipc_message_info *info) { struct ipc_sec_sim_status_response *pin_status; RIL_Token t; #if RIL_VERSION >= 6 RIL_CardStatus_v6 card_status; #else RIL_CardStatus card_status; #endif ril_sim_state sim_state; if (info->data == NULL || info->length < sizeof(struct ipc_sec_sim_status_response)) goto error; pin_status = (struct ipc_sec_sim_status_response *) info->data; t = ril_request_get_token(info->aseq); switch (info->type) { case IPC_TYPE_NOTI: if (ril_radio_state_complete(RADIO_STATE_OFF, RIL_TOKEN_NULL)) return; RIL_LOGD("Got UNSOL PIN status message"); if (ril_data.tokens.pin_status != RIL_TOKEN_NULL && ril_data.tokens.pin_status != RIL_TOKEN_DATA_WAITING) { RIL_LOGE("Another PIN status Req is in progress, skipping"); return; } sim_state = ipc2ril_sim_state(pin_status); ril_state_update(sim_state); memcpy(&(ril_data.state.sim_pin_status), pin_status, sizeof(struct ipc_sec_sim_status_response)); ril_data.tokens.pin_status = RIL_TOKEN_DATA_WAITING; ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); break; case IPC_TYPE_RESP: RIL_LOGD("Got SOL PIN status message"); if (ril_data.tokens.pin_status != t) RIL_LOGE("PIN status tokens mismatch"); sim_state = ipc2ril_sim_state(pin_status); ril_state_update(sim_state); // Better keeping this up to date memcpy(&(ril_data.state.sim_pin_status), pin_status, sizeof(struct ipc_sec_sim_status_response)); ipc2ril_card_status(pin_status, &card_status); ril_request_complete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status)); if (ril_data.tokens.pin_status != RIL_TOKEN_DATA_WAITING) ril_data.tokens.pin_status = RIL_TOKEN_NULL; break; default: RIL_LOGE("%s: unhandled ipc method: %d", __func__, info->type); break; } ril_tokens_pin_status_dump(); return; error: if (info != NULL) ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); } void ril_request_get_sim_status(RIL_Token t) { struct ipc_sec_sim_status_response *pin_status; #if RIL_VERSION >= 6 RIL_CardStatus_v6 card_status; #else RIL_CardStatus card_status; #endif if (ril_radio_state_complete(RADIO_STATE_OFF, t)) return; if (ril_data.tokens.pin_status == RIL_TOKEN_DATA_WAITING) { RIL_LOGD("Got RILJ request for UNSOL data"); hex_dump(&(ril_data.state.sim_pin_status), sizeof(struct ipc_sec_sim_status_response)); pin_status = &(ril_data.state.sim_pin_status); ipc2ril_card_status(pin_status, &card_status); ril_request_complete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status)); ril_data.tokens.pin_status = RIL_TOKEN_NULL; } else if (ril_data.tokens.pin_status == RIL_TOKEN_NULL) { RIL_LOGD("Got RILJ request for SOL data"); /* Request data to the modem */ ril_data.tokens.pin_status = t; ipc_fmt_send_get(IPC_SEC_SIM_STATUS, ril_request_get_id(t)); } else { RIL_LOGE("Another request is going on, returning UNSOL data"); pin_status = &(ril_data.state.sim_pin_status); ipc2ril_card_status(pin_status, &card_status); ril_request_complete(t, RIL_E_SUCCESS, &card_status, sizeof(card_status)); } ril_tokens_pin_status_dump(); } void ipc_sec_sim_icc_type(struct ipc_message_info *info) { struct ipc_sec_sim_icc_type *sim_icc_type; if (info->data == NULL || info->length < sizeof(struct ipc_sec_sim_icc_type)) goto error; sim_icc_type = (struct ipc_sec_sim_icc_type *) info->data; memcpy(&ril_data.state.sim_icc_type, sim_icc_type, sizeof(struct ipc_sec_sim_icc_type)); return; error: if (info != NULL) ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); } /* * SIM I/O */ int ril_request_sim_io_register(RIL_Token t, unsigned char command, unsigned short fileid, unsigned char p1, unsigned char p2, unsigned char p3, void *data, int length, struct ril_request_sim_io_info **sim_io_p) { struct ril_request_sim_io_info *sim_io; struct list_head *list_end; struct list_head *list; sim_io = calloc(1, sizeof(struct ril_request_sim_io_info)); if (sim_io == NULL) return -1; sim_io->command = command; sim_io->fileid = fileid; sim_io->p1 = p1; sim_io->p2 = p2; sim_io->p3 = p3; sim_io->data = data; sim_io->length = length; sim_io->waiting = 1; sim_io->token = t; list_end = ril_data.sim_io; while (list_end != NULL && list_end->next != NULL) list_end = list_end->next; list = list_head_alloc((void *) sim_io, list_end, NULL); if (ril_data.sim_io == NULL) ril_data.sim_io = list; if (sim_io_p != NULL) *sim_io_p = sim_io; return 0; } void ril_request_sim_io_unregister(struct ril_request_sim_io_info *sim_io) { struct list_head *list; if (sim_io == NULL) return; list = ril_data.sim_io; while (list != NULL) { if (list->data == (void *) sim_io) { memset(sim_io, 0, sizeof(struct ril_request_sim_io_info)); free(sim_io); if (list == ril_data.sim_io) ril_data.sim_io = list->next; list_head_free(list); break; } list_continue: list = list->next; } } struct ril_request_sim_io_info *ril_request_sim_io_info_find(void) { struct ril_request_sim_io_info *sim_io; struct list_head *list; list = ril_data.sim_io; while (list != NULL) { sim_io = (struct ril_request_sim_io_info *) list->data; if (sim_io == NULL) goto list_continue; return sim_io; list_continue: list = list->next; } return NULL; } struct ril_request_sim_io_info *ril_request_sim_io_info_find_token(RIL_Token t) { struct ril_request_sim_io_info *sim_io; struct list_head *list; list = ril_data.sim_io; while (list != NULL) { sim_io = (struct ril_request_sim_io_info *) list->data; if (sim_io == NULL) goto list_continue; if (sim_io->token == t) return sim_io; list_continue: list = list->next; } return NULL; } void ril_request_sim_io_info_clear(struct ril_request_sim_io_info *sim_io) { if (sim_io == NULL) return; if (sim_io->data != NULL) free(sim_io->data); } void ril_request_sim_io_next(void) { struct ril_request_sim_io_info *sim_io; int rc; ril_data.tokens.sim_io = RIL_TOKEN_NULL; sim_io = ril_request_sim_io_info_find(); if (sim_io == NULL) return; sim_io->waiting = 0; ril_data.tokens.sim_io = sim_io->token; ril_request_sim_io_complete(sim_io->token, sim_io->command, sim_io->fileid, sim_io->p1, sim_io->p2, sim_io->p3, sim_io->data, sim_io->length); if (sim_io->data != NULL) free(sim_io->data); sim_io->data = NULL; sim_io->length = 0; } void ril_request_sim_io_complete(RIL_Token t, unsigned char command, unsigned short fileid, unsigned char p1, unsigned char p2, unsigned char p3, void *data, int length) { struct ipc_sec_rsim_access_get *rsim_access = NULL; void *rsim_access_data = NULL; int rsim_access_length = 0; rsim_access_length += sizeof(struct ipc_sec_rsim_access_get); if (data != NULL && length > 0) rsim_access_length += length; rsim_access_data = calloc(1, rsim_access_length); rsim_access = (struct ipc_sec_rsim_access_get *) rsim_access_data; rsim_access->command = command; rsim_access->fileid = fileid; rsim_access->p1 = p1; rsim_access->p2 = p2; rsim_access->p3 = p3; if (data != NULL && length > 0) memcpy((void *) ((int) rsim_access_data + sizeof(struct ipc_sec_rsim_access_get)), data, length); ipc_fmt_send(IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, rsim_access_data, rsim_access_length, ril_request_get_id(t)); free(rsim_access_data); } void ril_request_sim_io(RIL_Token t, void *data, int length) { struct ril_request_sim_io_info *sim_io_info = NULL; #if RIL_VERSION >= 6 RIL_SIM_IO_v6 *sim_io = NULL; #else RIL_SIM_IO *sim_io = NULL; #endif void *sim_io_data = NULL; int sim_io_data_length = 0; int rc; if (data == NULL || length < (int) sizeof(*sim_io)) goto error; if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) return; #if RIL_VERSION >= 6 sim_io = (RIL_SIM_IO_v6 *) data; #else sim_io = (RIL_SIM_IO *) data; #endif // SIM IO data should be a string if present if (sim_io->data != NULL) { sim_io_data_length = strlen(sim_io->data) / 2; if (sim_io_data_length > 0) { sim_io_data = calloc(1, sim_io_data_length); hex2bin(sim_io->data, sim_io_data_length * 2, sim_io_data); } } rc = ril_request_sim_io_register(t, sim_io->command, sim_io->fileid, sim_io->p1, sim_io->p2, sim_io->p3, sim_io_data, sim_io_data_length, &sim_io_info); if (rc < 0 || sim_io_info == NULL) { RIL_LOGE("Unable to add the request to the list"); ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); if (sim_io_data != NULL) free(sim_io_data); // Send the next SIM I/O in the list ril_request_sim_io_next(); } if (ril_data.tokens.sim_io != RIL_TOKEN_NULL) { RIL_LOGD("Another SIM I/O is being processed, adding to the list"); return; } sim_io_info->waiting = 0; ril_data.tokens.sim_io = t; ril_request_sim_io_complete(t, sim_io->command, sim_io->fileid, sim_io->p1, sim_io->p2, sim_io->p3, sim_io_data, sim_io_data_length); if (sim_io_data != NULL) free(sim_io_data); sim_io_info->data = NULL; sim_io_info->length = 0; return; error: ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } void ipc_sec_rsim_access(struct ipc_message_info *info) { struct ril_request_sim_io_info *sim_io_info; struct sim_file_response sim_file_response; RIL_SIM_IO_Response sim_io_response; struct ipc_sec_rsim_access_response *rsim_access = NULL; struct ipc_sec_rsim_access_response_data *rsim_data = NULL; void *rsim_access_data = NULL; char *sim_response = NULL; unsigned char *buf = NULL; int offset; int i; if (info->data == NULL || info->length < sizeof(struct ipc_sec_rsim_access_response)) goto error; sim_io_info = ril_request_sim_io_info_find_token(ril_request_get_token(info->aseq)); if (sim_io_info == NULL) { RIL_LOGE("Unable to find SIM I/O in the list!"); // Send the next SIM I/O in the list ril_request_sim_io_next(); return; } rsim_access = (struct ipc_sec_rsim_access_response *) info->data; rsim_access_data = (void *) ((int) info->data + sizeof(struct ipc_sec_rsim_access_response)); memset(&sim_io_response, 0, sizeof(sim_io_response)); sim_io_response.sw1 = rsim_access->sw1; sim_io_response.sw2 = rsim_access->sw2; switch (sim_io_info->command) { case SIM_COMMAND_READ_BINARY: case SIM_COMMAND_READ_RECORD: if (rsim_access->len <= 0) break; // Copy the data as-is sim_response = (char *) malloc(rsim_access->len * 2 + 1); bin2hex(rsim_access_data, rsim_access->len, sim_response); sim_io_response.simResponse = sim_response; break; case SIM_COMMAND_GET_RESPONSE: if (rsim_access->len < sizeof(struct ipc_sec_rsim_access_response_data)) break; // SIM ICC type 1 requires direct copy if (ril_data.state.sim_icc_type.type == 1) { sim_response = (char *) malloc(rsim_access->len * 2 + 1); bin2hex(rsim_access_data, rsim_access->len, sim_response); sim_io_response.simResponse = sim_response; break; } rsim_data = (struct ipc_sec_rsim_access_response_data *) rsim_access_data; memset(&sim_file_response, 0, sizeof(sim_file_response)); buf = (unsigned char *) rsim_data; buf += sizeof(struct ipc_sec_rsim_access_response_data); buf += rsim_data->offset - 2; if (((int) buf + 1 - (int) rsim_access_data) > rsim_access->len) break; sim_file_response.file_id[0] = buf[0]; sim_file_response.file_id[1] = buf[1]; buf = (unsigned char *) rsim_data; buf += rsim_access->len - 2; while ((int) buf > (int) rsim_data + 2) { if (buf[0] == 0x88) { buf -= 2; break; } buf--; } if ((int) buf <= (int) rsim_data + 2) break; sim_file_response.file_size[0] = buf[0]; sim_file_response.file_size[1] = buf[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_info->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 (rsim_data->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 = rsim_data->record_length; sim_response = (char *) malloc(sizeof(struct sim_file_response) * 2 + 1); bin2hex((void *) &sim_file_response, sizeof(struct sim_file_response), sim_response); sim_io_response.simResponse = sim_response; break; case SIM_COMMAND_UPDATE_BINARY: case SIM_COMMAND_UPDATE_RECORD: case SIM_COMMAND_SEEK: default: sim_io_response.simResponse = NULL; break; } ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &sim_io_response, sizeof(sim_io_response)); if (sim_io_response.simResponse != NULL) { RIL_LOGD("SIM response: %s", sim_io_response.simResponse); free(sim_io_response.simResponse); } ril_request_sim_io_unregister(sim_io_info); // Send the next SIM I/O in the list ril_request_sim_io_next(); return; error: ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); } void ipc_sec_sim_status_complete(struct ipc_message_info *info) { struct ipc_gen_phone_res *phone_res; int attempts = -1; int rc; phone_res = (struct ipc_gen_phone_res *) info->data; rc = ipc_gen_phone_res_check(phone_res); if (rc < 0) { if ((phone_res->code & 0x00ff) == 0x10) { RIL_LOGE("Wrong password!"); ril_request_complete(ril_request_get_token(info->aseq), RIL_E_PASSWORD_INCORRECT, &attempts, sizeof(attempts)); } else if ((phone_res->code & 0x00ff) == 0x0c) { RIL_LOGE("Wrong password and no attempts left!"); attempts = 0; ril_request_complete(ril_request_get_token(info->aseq), RIL_E_PASSWORD_INCORRECT, &attempts, sizeof(attempts)); ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0); } else { RIL_LOGE("There was an error during pin status complete!"); ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); } return; } ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &attempts, sizeof(attempts)); } void ipc_sec_lock_info(struct ipc_message_info *info) { struct ipc_sec_lock_info_response *lock_info; int attempts; if (info->data == NULL || info->length < sizeof(struct ipc_sec_lock_info_response)) return; lock_info = (struct ipc_sec_lock_info_response *) info->data; /* * FIXME: solid way of handling lockinfo and sim unlock response together * so we can return the number of attempts left in respondSecPinStatus */ if (lock_info->type == IPC_SEC_PIN_TYPE_PIN1) { attempts = lock_info->attempts; RIL_LOGD("%s: PIN1 %d attempts left", __func__, attempts); } else { RIL_LOGE("%s: unhandled lock type %d", __func__, lock_info->type); } } void ril_request_enter_sim_pin(RIL_Token t, void *data, size_t length) { struct ipc_sec_pin_status_set pin_status; char *pin = ((char **) data)[0]; unsigned char buf[9]; if (data == NULL || length < (int) sizeof(char *)) goto error; if (ril_radio_state_complete(RADIO_STATE_OFF, t)) return; // 1. Send PIN if (strlen(data) > 16) { RIL_LOGE("%s: pin exceeds maximum length", __func__); ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } ipc_sec_pin_status_set_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin, NULL); ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_SIM_STATUS, ipc_sec_sim_status_complete); ipc_fmt_send_set(IPC_SEC_SIM_STATUS, ril_request_get_id(t), (unsigned char *) &pin_status, sizeof(pin_status)); // 2. Get lock status // FIXME: This is not clean at all memset(buf, 0, sizeof(buf)); buf[0] = 1; buf[1] = IPC_SEC_PIN_TYPE_PIN1; ipc_fmt_send(IPC_SEC_LOCK_INFO, IPC_TYPE_GET, buf, sizeof(buf), ril_request_get_id(t)); return; error: ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } void ril_request_change_sim_pin(RIL_Token t, void *data, size_t length) { char *password_old; char *password_new; struct ipc_sec_change_locking_pw_set locking_pw; if (data == NULL || length < (int) (2 * sizeof(char *))) goto error; if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) return; password_old = ((char **) data)[0]; password_new = ((char **) data)[1]; memset(&locking_pw, 0, sizeof(locking_pw)); locking_pw.facility = IPC_SEC_SIM_STATUS_LOCK_SC; locking_pw.length_new = strlen(password_new) > sizeof(locking_pw.password_new) ? sizeof(locking_pw.password_new) : strlen(password_new); memcpy(locking_pw.password_new, password_new, locking_pw.length_new); locking_pw.length_old = strlen(password_old) > sizeof(locking_pw.password_old) ? sizeof(locking_pw.password_old) : strlen(password_old); memcpy(locking_pw.password_old, password_old, locking_pw.length_old); ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_sim_status_complete); ipc_fmt_send_set(IPC_SEC_CHANGE_LOCKING_PW, ril_request_get_id(t), (unsigned char *) &locking_pw, sizeof(locking_pw)); return; error: ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } void ril_request_enter_sim_puk(RIL_Token t, void *data, size_t length) { struct ipc_sec_pin_status_set pin_status; char *puk; char *pin; if (data == NULL || length < (int) (2 * sizeof(char *))) goto error; if (ril_radio_state_complete(RADIO_STATE_OFF, t)) return; puk = ((char **) data)[0]; pin = ((char **) data)[1]; ipc_sec_pin_status_set_setup(&pin_status, IPC_SEC_PIN_TYPE_PIN1, pin, puk); ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_SIM_STATUS, ipc_sec_sim_status_complete); ipc_fmt_send_set(IPC_SEC_SIM_STATUS, ril_request_get_id(t), (unsigned char *) &pin_status, sizeof(pin_status)); return; error: ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } void ipc_sec_phone_lock(struct ipc_message_info *info) { int status; struct ipc_sec_phone_lock_response *lock; if (info->data == NULL || info->length < sizeof(struct ipc_sec_phone_lock_response)) goto error; lock = (struct ipc_sec_phone_lock_response *) info->data; status = lock->status; ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, &status, sizeof(status)); return; error: ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); } void ril_request_query_facility_lock(RIL_Token t, void *data, size_t length) { struct ipc_sec_phone_lock_get lock_request; char *facility; if (data == NULL || length < sizeof(char *)) goto error; if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) return; facility = ((char **) data)[0]; if (!strcmp(facility, "SC")) { lock_request.facility = IPC_SEC_FACILITY_TYPE_SC; } else if (!strcmp(facility, "FD")) { lock_request.facility = IPC_SEC_FACILITY_TYPE_FD; } else if (!strcmp(facility, "PN")) { lock_request.facility = IPC_SEC_FACILITY_TYPE_PN; } else if (!strcmp(facility, "PU")) { lock_request.facility = IPC_SEC_FACILITY_TYPE_PU; } else if (!strcmp(facility, "PP")) { lock_request.facility = IPC_SEC_FACILITY_TYPE_PP; } else if (!strcmp(facility, "PC")) { lock_request.facility = IPC_SEC_FACILITY_TYPE_PC; } else { RIL_LOGE("%s: unsupported facility: %s", __func__, facility); ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } ipc_fmt_send(IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, (void *) &lock_request, sizeof(lock_request), ril_request_get_id(t)); return; error: ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } // Both functions were the same #define ipc_sec_phone_lock_complete \ ipc_sec_sim_status_complete void ril_request_set_facility_lock(RIL_Token t, void *data, size_t length) { struct ipc_sec_phone_lock_set lock_request; char *facility; char *lock; char *password; char *class; if (data == NULL || length < (int) (4 * sizeof(char *))) goto error; if (ril_radio_state_complete(RADIO_STATE_SIM_NOT_READY, t)) return; facility = ((char **) data)[0]; lock = ((char **) data)[1]; password = ((char **) data)[2]; class = ((char **) data)[3]; memset(&lock_request, 0, sizeof(lock_request)); if (!strcmp(facility, "SC")) { lock_request.type = IPC_SEC_SIM_STATUS_LOCK_SC; } else if (!strcmp(facility, "FD")) { lock_request.type = IPC_SEC_SIM_STATUS_LOCK_FD; } else if (!strcmp(facility, "PN")) { lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PN; } else if (!strcmp(facility, "PU")) { lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PU; } else if (!strcmp(facility, "PP")) { lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PP; } else if (!strcmp(facility, "PC")) { lock_request.type = IPC_SEC_SIM_STATUS_LOCK_PC; } else { RIL_LOGE("%s: unsupported facility: %s", __func__, facility); ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); } lock_request.lock = lock[0] == '1' ? 1 : 0; lock_request.length = strlen(password) > sizeof(lock_request.password) ? sizeof(lock_request.password) : strlen(password); memcpy(lock_request.password, password, lock_request.length); ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SEC_PHONE_LOCK, ipc_sec_phone_lock_complete); ipc_fmt_send(IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, (void *) &lock_request, sizeof(lock_request), ril_request_get_id(t)); return; error: ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); }