summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sim.h104
-rw-r--r--samsung-ril.c9
-rw-r--r--samsung-ril.h4
-rw-r--r--sec.c223
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);
diff --git a/sec.c b/sec.c
index dbad1fd..6e09812 100644
--- a/sec.c
+++ b/sec.c
@@ -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();