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();  | 
