sec: Handle various SIM I/O message formats based on SIM ICC type
authorPaul Kocialkowski <contact@paulk.fr>
Sat, 9 Feb 2013 22:43:19 +0000 (23:43 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Sat, 9 Feb 2013 22:43:19 +0000 (23:43 +0100)
Also make request id registration override older requests.

Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
include/sim.h [new file with mode: 0644]
samsung-ril.c
samsung-ril.h
sec.c

diff --git a/include/sim.h b/include/sim.h
new file mode 100644 (file)
index 0000000..f071bf1
--- /dev/null
@@ -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
index 8abb9a0..b10a624 100644 (file)
@@ -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;
index 9071ba5..796c0ad 100644 (file)
@@ -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 (file)
--- 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();