diff options
-rw-r--r-- | include/sim.h | 104 | ||||
-rw-r--r-- | samsung-ril.c | 9 | ||||
-rw-r--r-- | samsung-ril.h | 4 | ||||
-rw-r--r-- | sec.c | 223 |
4 files changed, 296 insertions, 44 deletions
diff --git a/include/sim.h b/include/sim.h new file mode 100644 index 0000000..f071bf1 --- /dev/null +++ b/include/sim.h @@ -0,0 +1,104 @@ +/** + * This file is part of samsung-ril. + * + * Copyright (C) 2013 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/>. + * + */ + +#ifndef _SIM_H_ +#define _SIM_H_ + +// Values from TS 11.11 +#define SIM_COMMAND_READ_BINARY 0xB0 +#define SIM_COMMAND_UPDATE_BINARY 0xD6 +#define SIM_COMMAND_READ_RECORD 0xB2 +#define SIM_COMMAND_UPDATE_RECORD 0xDC +#define SIM_COMMAND_SEEK 0xA2 +#define SIM_COMMAND_GET_RESPONSE 0xC0 + +#define SIM_FILE_STRUCTURE_TRANSPARENT 0x00 +#define SIM_FILE_STRUCTURE_LINEAR_FIXED 0x01 +#define SIM_FILE_STRUCTURE_CYCLIC 0x03 + +#define SIM_FILE_TYPE_RFU 0x00 +#define SIM_FILE_TYPE_MF 0x01 +#define SIM_FILE_TYPE_DF 0x02 +#define SIM_FILE_TYPE_EF 0x04 + +struct sim_file_id { + unsigned short file_id; + unsigned char type; +}; + +struct sim_file_id sim_file_ids[] = { + { 0x2F05, SIM_FILE_TYPE_EF }, + { 0x2FE2, SIM_FILE_TYPE_EF }, + { 0x3F00, SIM_FILE_TYPE_MF }, + { 0x4F20, SIM_FILE_TYPE_EF }, + { 0x5F3A, SIM_FILE_TYPE_DF }, + { 0x6F05, SIM_FILE_TYPE_EF }, + { 0x6F06, SIM_FILE_TYPE_EF }, + { 0x6F07, SIM_FILE_TYPE_EF }, + { 0x6F11, SIM_FILE_TYPE_EF }, + { 0x6F13, SIM_FILE_TYPE_EF }, + { 0x6F14, SIM_FILE_TYPE_EF }, + { 0x6F15, SIM_FILE_TYPE_EF }, + { 0x6F16, SIM_FILE_TYPE_EF }, + { 0x6F17, SIM_FILE_TYPE_EF }, + { 0x6F18, SIM_FILE_TYPE_EF }, + { 0x6F38, SIM_FILE_TYPE_EF }, + { 0x6F38, SIM_FILE_TYPE_EF }, + { 0x6F3A, SIM_FILE_TYPE_EF }, + { 0x6F40, SIM_FILE_TYPE_EF }, + { 0x6F42, SIM_FILE_TYPE_EF }, + { 0x6F45, SIM_FILE_TYPE_EF }, + { 0x6F46, SIM_FILE_TYPE_EF }, + { 0x6F48, SIM_FILE_TYPE_EF }, + { 0x6F49, SIM_FILE_TYPE_EF }, + { 0x6F4A, SIM_FILE_TYPE_EF }, + { 0x6F4D, SIM_FILE_TYPE_EF }, + { 0x6F50, SIM_FILE_TYPE_EF }, + { 0x6F56, SIM_FILE_TYPE_EF }, + { 0x6FAD, SIM_FILE_TYPE_EF }, + { 0x6FAE, SIM_FILE_TYPE_EF }, + { 0x6FB7, SIM_FILE_TYPE_EF }, + { 0x6FC5, SIM_FILE_TYPE_EF }, + { 0x6FC6, SIM_FILE_TYPE_EF }, + { 0x6FC7, SIM_FILE_TYPE_EF }, + { 0x6FC9, SIM_FILE_TYPE_EF }, + { 0x6FCA, SIM_FILE_TYPE_EF }, + { 0x6FCB, SIM_FILE_TYPE_EF }, + { 0x6FCD, SIM_FILE_TYPE_EF }, + { 0x7F10, SIM_FILE_TYPE_DF }, + { 0x7F20, SIM_FILE_TYPE_DF }, +}; + +int sim_file_ids_count = sizeof(sim_file_ids) / sizeof(sim_file_ids[0]); + +struct sim_file_response { + unsigned char rfu12[2]; + unsigned char file_size[2]; + unsigned char file_id[2]; + unsigned char file_type; + unsigned char rfu3; + unsigned char access_condition[3]; + unsigned char file_status; + unsigned char file_length; + unsigned char file_structure; + unsigned char record_length; +} __attribute__((__packed__)); + +#endif diff --git a/samsung-ril.c b/samsung-ril.c index 8abb9a0..b10a624 100644 --- a/samsung-ril.c +++ b/samsung-ril.c @@ -199,6 +199,12 @@ int ril_request_get_id(RIL_Token t) return request->id; id = ril_request_id_get(); + + // Unregister a previous request with the same id + request = ril_request_info_find_id(id); + if (request != NULL) + ril_request_unregister(request); + rc = ril_request_register(t, id); if (rc < 0) return -1; @@ -322,6 +328,9 @@ void ipc_fmt_dispatch(struct ipc_message_info *info) case IPC_SEC_SIM_STATUS: ipc_sec_sim_status(info); break; + case IPC_SEC_SIM_ICC_TYPE: + ipc_sec_sim_icc_type(info); + break; case IPC_SEC_LOCK_INFO: ipc_sec_lock_info(info); break; diff --git a/samsung-ril.h b/samsung-ril.h index 9071ba5..796c0ad 100644 --- a/samsung-ril.h +++ b/samsung-ril.h @@ -162,7 +162,7 @@ struct ril_state { int power_state; struct ipc_sec_sim_status_response sim_pin_status; - struct ipc_sec_sim_icc_type sim_type; + struct ipc_sec_sim_icc_type sim_icc_type; struct ipc_net_regist_response netinfo; struct ipc_net_regist_response gprs_netinfo; @@ -280,12 +280,14 @@ struct ril_request_sim_io_info { void *data; int length; + int waiting; RIL_Token token; }; void ril_state_update(ril_sim_state status); void ipc_sec_sim_status(struct ipc_message_info *info); void ril_request_get_sim_status(RIL_Token t); +void ipc_sec_sim_icc_type(struct ipc_message_info *info); void ril_request_sim_io_next(void); 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); @@ -25,6 +25,8 @@ #include "samsung-ril.h" #include "util.h" +#include <sim.h> + ril_sim_state ipc2ril_sim_state(struct ipc_sec_sim_status_response *pin_status) { switch(pin_status->status) { @@ -315,12 +317,25 @@ void ril_request_get_sim_status(RIL_Token t) 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 == NULL || info->length < sizeof(struct ipc_sec_sim_icc_type)) + return; + + 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)); +} + /* * 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) + 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; @@ -337,6 +352,7 @@ int ril_request_sim_io_register(RIL_Token t, unsigned char command, unsigned sho 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; @@ -348,6 +364,9 @@ int ril_request_sim_io_register(RIL_Token t, unsigned char command, unsigned sho if (ril_data.sim_io == NULL) ril_data.sim_io = list; + if (sim_io_p != NULL) + *sim_io_p = sim_io; + return 0; } @@ -396,6 +415,27 @@ list_continue: 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) @@ -408,14 +448,6 @@ void ril_request_sim_io_info_clear(struct ril_request_sim_io_info *sim_io) void ril_request_sim_io_next(void) { struct ril_request_sim_io_info *sim_io; - unsigned char command; - unsigned short fileid; - unsigned char p1; - unsigned char p2; - unsigned char p3; - void *data; - int length; - RIL_Token t; int rc; ril_data.tokens.sim_io = (RIL_Token) 0x00; @@ -424,22 +456,16 @@ void ril_request_sim_io_next(void) if (sim_io == NULL) return; - command = sim_io->command; - fileid = sim_io->fileid; - p1 = sim_io->p1; - p2 = sim_io->p2; - p3 = sim_io->p3; - data = sim_io->data; - length = sim_io->length; - t = sim_io->token; + sim_io->waiting = 0; + ril_data.tokens.sim_io = sim_io->token; - ril_request_sim_io_unregister(sim_io); + 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); - ril_data.tokens.sim_io = t; - - ril_request_sim_io_complete(t, command, fileid, p1, p2, p3, data, length); - if (data != NULL) - free(data); + 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, @@ -483,6 +509,7 @@ void ril_request_sim_io_complete(RIL_Token t, unsigned char command, unsigned sh */ 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 @@ -510,30 +537,35 @@ void ril_request_sim_io(RIL_Token t, void *data, int length) } } - if (ril_data.tokens.sim_io != (RIL_Token) 0x00) { - LOGD("Another SIM I/O is being processed, adding to the list"); + 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) { + LOGE("Unable to add the request to the list"); - 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); - if (rc < 0) { - 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); - 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(); - } + // Send the next SIM I/O in the list + ril_request_sim_io_next(); + } + if (ril_data.tokens.sim_io != (RIL_Token) 0x00) { + 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; } /** @@ -548,33 +580,138 @@ void ril_request_sim_io(RIL_Token t, void *data, int length) */ 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 == NULL || info->data == NULL || info->length < sizeof(struct ipc_sec_rsim_access_response)) return; - memset(&sim_io_response, 0, sizeof(sim_io_response)); + sim_io_info = ril_request_sim_io_info_find_token(ril_request_get_token(info->aseq)); + if (sim_io_info == NULL) { + 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; - if (rsim_access->len > 0) { - sim_response = (char *) malloc(rsim_access->len * 2 + 1); - bin2hex(rsim_access_data, rsim_access->len, sim_response); - sim_io_response.simResponse = sim_response; - } else { - sim_io_response.simResponse = strdup(""); + 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)); - free(sim_io_response.simResponse); + if (sim_io_response.simResponse != NULL) { + 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(); |