Exemplo n.º 1
0
void ril_request_setup_data_call(RIL_Token t, void *data, int length)
{
	struct ril_gprs_connection *gprs_connection = NULL;
	struct ipc_client_gprs_capabilities gprs_capabilities;
	struct ipc_gprs_port_list port_list;
	struct ipc_client *ipc_client;

	char *username = NULL;
	char *password = NULL;
	char *apn = NULL;

	ipc_client = ((struct ipc_client_object *) ipc_fmt_client->object)->ipc_client;

	apn = ((char **) data)[2];
	username = ((char **) data)[3];
	password = ((char **) data)[4];

	LOGD("Requesting data connection to APN '%s'\n", apn);

	gprs_connection = ril_gprs_connection_add();

	if(!gprs_connection) {
		LOGE("Unable to create GPRS connection, aborting");

		RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
		return;
	}

	gprs_connection->token = t;

	// Create the structs with the apn
	ipc_gprs_define_pdp_context_setup(&(gprs_connection->define_context),
		gprs_connection->cid, 1, apn);

	// Create the structs with the username/password tuple
	ipc_gprs_pdp_context_setup(&(gprs_connection->context),
		gprs_connection->cid, 1, username, password);

	ipc_client_gprs_get_capabilities(ipc_client, &gprs_capabilities);

	// If the device has the capability, deal with port list
	if(gprs_capabilities.port_list) {
		ipc_gprs_port_list_setup(&port_list);

		ipc_gen_phone_res_expect_to_func(reqGetId(t), IPC_GPRS_PORT_LIST,
			ipc_gprs_port_list_complete);

		ipc_fmt_send(IPC_GPRS_PORT_LIST, IPC_TYPE_SET,
			(void *) &port_list, sizeof(struct ipc_gprs_port_list), reqGetId(t));
	} else {
		ipc_gen_phone_res_expect_to_func(reqGetId(t), IPC_GPRS_DEFINE_PDP_CONTEXT,
			ipc_gprs_define_pdp_context_complete);

		ipc_fmt_send(IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
			(void *) &(gprs_connection->define_context),
				sizeof(struct ipc_gprs_define_pdp_context), reqGetId(t));
	}
}
int ipc_sec_pin_status(struct ipc_message *message)
{
	struct ipc_sec_pin_status_response_data *data;
	struct ipc_sec_pin_status_request_data request_data;
#if RIL_VERSION >= 6
	RIL_CardStatus_v6 card_status;
#else
	RIL_CardStatus card_status;
#endif
	RIL_RadioState radio_state;
	int rc;

	if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_pin_status_response_data))
		return -1;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return 0;

	data = (struct ipc_sec_pin_status_response_data *) message->data;

	radio_state = ipc2ril_sec_pin_status_response(data, &card_status);
	if (radio_state == 0)
		return 0;

	if (card_status.applications[0].app_type == RIL_APPTYPE_SIM && card_status.applications[0].app_state == RIL_APPSTATE_PIN && ril_data->sim_pin != NULL) {
		ril_request_data_set_uniq(RIL_REQUEST_GET_SIM_STATUS, (void *) &card_status, sizeof(card_status));

		rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, ril_data->sim_pin, NULL);
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS);
			return 0;
		}

		rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_SEC_PIN_STATUS, ipc_sec_pin_status_callback);
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS);
			return 0;
		}

		rc = ipc_fmt_send(message->aseq, IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_GET_SIM_STATUS);
			return 0;
		}

		return 0;
	}

	ril_radio_state_update(radio_state);

	if (message->type == IPC_TYPE_RESP && ipc_seq_valid(message->aseq)) {
		ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &card_status, sizeof(card_status));
	} else {
		ril_request_data_set_uniq(RIL_REQUEST_GET_SIM_STATUS, (void *) &card_status, sizeof(card_status));
		ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
	}

	return 0;
}
Exemplo n.º 3
0
void srs_snd_set_call_clock_sync(struct srs_message *message)
{
	unsigned char data = *((unsigned char *) message->data);
	LOGD("Clock sync data is 0x%x\n", data);

	ipc_fmt_send(IPC_SND_CLOCK_CTRL, IPC_TYPE_EXEC, &data, sizeof(data), reqIdNew());
}
int ril_request_answer(void *data, size_t size, RIL_Token token)
{
	int rc;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_ANSWER);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL, 0);
	if (rc < 0)
		goto error;

	ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}
int ril_request_hangup(void *data, size_t size, RIL_Token token)
{
	int hangup;
	int rc;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	hangup = 1;
	ril_request_data_set_uniq(RIL_REQUEST_HANGUP, &hangup, sizeof(hangup));

	rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_RELEASE);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_RELEASE, IPC_TYPE_EXEC, NULL, 0);
	if (rc < 0)
		goto error;

	ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	ril_request_data_free(RIL_REQUEST_HANGUP);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}
Exemplo n.º 6
0
void ril_request_stk_send_terminal_response(RIL_Token t, void *data, size_t length)
{
	unsigned char buffer[264];
	int size;

	if (data == NULL || length < sizeof(char *))
		goto error;

	size = strlen(data) / 2;
	if (size > 255) {
		RIL_LOGE("%s: data exceeds maximum length", __func__);
		goto error;
	}

	memset(buffer, 0, sizeof(buffer));

	buffer[0] = (unsigned char) size;
	hex2bin(data, strlen(data), &buffer[1]);

	ipc_fmt_send(IPC_SAT_PROACTIVE_CMD, IPC_TYPE_GET, buffer, sizeof(buffer), ril_request_get_id(t));

	ril_request_complete(t, RIL_E_SUCCESS, buffer, sizeof(char *));

	return;

error:
	ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
Exemplo n.º 7
0
void ril_request_delete_sms_on_sim(RIL_Token token, void *data, size_t size)
{
	struct ipc_sms_del_msg_request_data sms_del_msg_request_data;
	int index = 0;

	if (data == NULL || size < sizeof(index))
		goto error;

	if (ril_radio_state_complete(RADIO_STATE_OFF, token))
		return;

	index = *((int *) data);

	if (index <= 0 || index > 0xffff)
		goto error;

	memset(&sms_del_msg_request_data, 0, sizeof(sms_del_msg_request_data));
	sms_del_msg_request_data.unknown = 0x02;
	sms_del_msg_request_data.index = (short) index - 1;

	ipc_gen_phone_res_expect_to_abort(ril_request_get_id(token), IPC_SMS_DEL_MSG);

	ipc_fmt_send(IPC_SMS_DEL_MSG, IPC_TYPE_EXEC, (unsigned char *) &sms_del_msg_request_data, sizeof(sms_del_msg_request_data), ril_request_get_id(token));

	return;

error:
	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
}
Exemplo n.º 8
0
void ril_request_deactivate_data_call(RIL_Token t, void *data, int length)
{
	struct ril_gprs_connection *gprs_connection;
	struct ipc_gprs_pdp_context_set context;

	char *cid = ((char **) data)[0];
	int rc;

	gprs_connection = ril_gprs_connection_get_cid(atoi(cid));

	if(!gprs_connection) {
		LOGE("Unable to find GPRS connection, aborting");

		RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
		return;
	}

	gprs_connection->token = t;

	ipc_gprs_pdp_context_setup(&context, gprs_connection->cid, 0, NULL, NULL);

	ipc_gen_phone_res_expect_to_func(reqGetId(t), IPC_GPRS_PDP_CONTEXT,
		ipc_gprs_pdp_context_disable_complete);

	ipc_fmt_send(IPC_GPRS_PDP_CONTEXT, IPC_TYPE_SET,
		(void *) &context, sizeof(struct ipc_gprs_pdp_context_set), reqGetId(t));
}
Exemplo n.º 9
0
void srs_snd_set_call_audio_path(struct srs_message *message)
{
	int audio_path = ((int *) message->data)[0];
	unsigned char path = srs2ipc_audio_path(audio_path);

	LOGD("Audio path to: 0x%x\n", path);

	ipc_fmt_send(IPC_SND_AUDIO_PATH_CTRL, IPC_TYPE_SET, (void *) &path, sizeof(path), reqIdNew());
}
Exemplo n.º 10
0
void ril_request_set_mute(RIL_Token t, void *data, size_t datalen)
{
	unsigned char mute_data = ((int *)data)[0] > 0 ? 1 : 0;

	LOGD("Mute data is %d\n", mute_data);

	ipc_gen_phone_res_expect_to_complete(reqGetId(t), IPC_SND_MIC_MUTE_CTRL);

	ipc_fmt_send(IPC_SND_MIC_MUTE_CTRL, IPC_TYPE_SET, (void *) &mute_data, sizeof(mute_data), reqGetId(t));
}
Exemplo n.º 11
0
void srs_snd_set_call_volume(struct srs_message *message)
{
	struct srs_snd_call_volume *call_volume = (struct srs_snd_call_volume *) message->data;
	struct ipc_snd_spkr_volume_ctrl volume_ctrl;

	LOGD("Call volume for: 0x%x vol = 0x%x\n", call_volume->type, call_volume->volume);

	volume_ctrl.type = srs2ipc_call_type(call_volume->type);
	volume_ctrl.volume = call_volume->volume;

	ipc_fmt_send(IPC_SND_SPKR_VOLUME_CTRL, IPC_TYPE_SET, (void *) &volume_ctrl, sizeof(volume_ctrl), reqIdNew());
}
Exemplo n.º 12
0
void ipc_sms_device_ready(struct ipc_message_info *info)
{
#if RIL_VERSION >= 7
	if (ril_data.state.radio_state == RADIO_STATE_ON) {
#else
	if (ril_data.state.radio_state == RADIO_STATE_SIM_READY) {
#endif
		ipc_fmt_send(IPC_SMS_DEVICE_READY, IPC_TYPE_SET, NULL, 0, info->aseq);
	}

	ril_tokens_check();
}
int ril_request_dial(void *data, size_t size, RIL_Token token)
{
	struct ipc_call_outgoing_data request_data;
	RIL_Dial *dial = NULL;
	unsigned char identity;
	unsigned char prefix;
	int rc;

	if (data == NULL || size < sizeof(RIL_Dial))
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	dial = (RIL_Dial *) data;

	if (dial->address == NULL)
		goto error;

	identity = ril2ipc_call_identity(dial->clir);
	prefix = dial->address[0] == '+' ? IPC_CALL_PREFIX_INTL : IPC_CALL_PREFIX_NONE;

	rc = ipc_call_outgoing_setup(&request_data, IPC_CALL_TYPE_VOICE, identity, prefix, dial->address);
	if (rc < 0)
		goto error;

	free(dial->address);
	dial = NULL;

	rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_OUTGOING);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (dial != NULL && dial->address != NULL)
		free(dial->address);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}
Exemplo n.º 14
0
void ril_request_sms_acknowledge(RIL_Token t, void *data, size_t length)
{
	struct ipc_sms_deliver_report_request report_msg;
	int success, fail_cause;

	if (data == NULL || length < 2 * sizeof(int))
		goto error;

	if (ril_data.state.sms_incoming_msg_tpid == ril_data.state.ril_sms_tpid) {
		ril_data.state.ril_sms_tpid = 0;

		ril_request_complete(t, RIL_E_SUCCESS, NULL, 0);

		ipc_sms_incoming_msg_next();

		return;
	}

	if (ril_radio_state_complete(RADIO_STATE_OFF, t))
		return;

	success = ((int *) data)[0];
	fail_cause = ((int *) data)[1];

	if (ril_data.state.sms_incoming_msg_tpid == 0) {
		RIL_LOGE("There is no SMS message to ACK!");
		goto error;
	}

	report_msg.type = IPC_SMS_TYPE_STATUS_REPORT;
	report_msg.error = ril2ipc_sms_ack_error(success, fail_cause);
	report_msg.msg_tpid = ril_data.state.sms_incoming_msg_tpid;
	report_msg.unk = 0;

	ipc_gen_phone_res_expect_to_abort(ril_request_get_id(t), IPC_SMS_DELIVER_REPORT);

	ipc_fmt_send(IPC_SMS_DELIVER_REPORT, IPC_TYPE_EXEC, (void *) &report_msg, sizeof(report_msg), ril_request_get_id(t));

	ipc_sms_incoming_msg_next();

	return;

error:
	ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);

	ipc_sms_incoming_msg_next();
}
int ril_request_radio_power(void *data, size_t size, RIL_Token token)
{
	struct ipc_pwr_phone_state_request_data request_data;
	struct ril_request *request;
	int power_state;
	int rc;

	if (data == NULL || size < sizeof(power_state))
		goto error;

	request = ril_request_find_request_status(RIL_REQUEST_RADIO_POWER, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	power_state = *((int *)data);

	memset(&request_data, 0, sizeof(request_data));

	if (power_state > 0) {
		RIL_LOGD("Requesting normal power state");
		request_data.state = IPC_PWR_PHONE_STATE_REQUEST_NORMAL;
	 } else {
		RIL_LOGD("Requesting low power mode power state");
		request_data.state = IPC_PWR_PHONE_STATE_REQUEST_LPM;
	}

	rc = ipc_gen_phone_res_expect_abort(ipc_fmt_request_seq(token), IPC_PWR_PHONE_STATE);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_PWR_PHONE_STATE, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}
int ril_request_get_current_calls(void *data, size_t size, RIL_Token token)
{
	int rc;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0) {
		ril_request_complete(token, RIL_E_SUCCESS, NULL, 0);
		return RIL_REQUEST_COMPLETED;
	}

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_LIST, IPC_TYPE_GET, NULL, 0);
	if (rc < 0) {
		ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
		return RIL_REQUEST_COMPLETED;
	}

	return RIL_REQUEST_HANDLED;
}
int ril_request_dtmf_start_complete(unsigned char aseq, char tone)
{
	struct ipc_call_cont_dtmf_data request_data;
	int rc;

	memset(&request_data, 0, sizeof(request_data));
	request_data.status = IPC_CALL_DTMF_STATUS_START;
	request_data.tone = tone;

	rc = ipc_gen_phone_res_expect_complete(aseq, IPC_CALL_CONT_DTMF);
	if (rc < 0)
		return -1;

	rc = ipc_fmt_send(aseq, IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		return -1;

	return 0;
}
Exemplo n.º 18
0
void ipc_gprs_port_list_complete(struct ipc_message_info *info)
{
	struct ipc_gen_phone_res *phone_res = (struct ipc_gen_phone_res *) info->data;
	struct ril_gprs_connection *gprs_connection;
	int rc;
	int aseq;

	gprs_connection = ril_gprs_connection_get_token(reqGetToken(info->aseq));

	if(!gprs_connection) {
		LOGE("Unable to find GPRS connection, aborting");

		RIL_onRequestComplete(reqGetToken(info->aseq),
			RIL_E_GENERIC_FAILURE, NULL, 0);
		return;
	}

	rc = ipc_gen_phone_res_check(phone_res);
	if(rc < 0) {
		LOGE("There was an error, aborting port list complete");

		gprs_connection->fail_cause = PDP_FAIL_ERROR_UNSPECIFIED;
		gprs_connection->token = (RIL_Token) 0x00;
		ril_state.gprs_last_failed_cid = gprs_connection->cid;

		RIL_onRequestComplete(reqGetToken(info->aseq),
			RIL_E_GENERIC_FAILURE, NULL, 0);
		return;
	}

	// We need to get a clean new aseq here
	aseq = ril_request_reg_id(reqGetToken(info->aseq));

	ipc_gen_phone_res_expect_to_func(aseq, IPC_GPRS_DEFINE_PDP_CONTEXT,
		ipc_gprs_define_pdp_context_complete);

	ipc_fmt_send(IPC_GPRS_DEFINE_PDP_CONTEXT, IPC_TYPE_SET,
		(void *) &(gprs_connection->define_context),
		sizeof(struct ipc_gprs_define_pdp_context),
		aseq);
}
int ril_request_dtmf_complete(unsigned char aseq, char tone)
{
	struct ipc_call_burst_dtmf_request_entry entry;
	void *request_data = NULL;
	size_t request_size = 0;
	int rc;

	memset(&entry, 0, sizeof(entry));
	entry.status = IPC_CALL_DTMF_STATUS_START;
	entry.tone = tone;

	request_size = ipc_call_burst_dtmf_size_setup(&entry, 1);
	if (request_size == 0)
		goto error;

	request_data = ipc_call_burst_dtmf_setup(&entry, 1);
	if (request_data == NULL)
		goto error;

	rc = ipc_gen_phone_res_expect_abort(aseq, IPC_CALL_BURST_DTMF);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(aseq, IPC_CALL_BURST_DTMF, IPC_TYPE_EXEC, request_data, request_size);
	if (rc < 0)
		goto error;

	rc = 0;
	goto complete;

error:
	rc = -1;

complete:
	if (request_data != NULL && request_size > 0)
		free(request_data);

	return rc;
}
Exemplo n.º 20
0
void ril_request_write_sms_to_sim(RIL_Token token, void *data, size_t size)
{
	struct ipc_sms_save_msg_request_data *sms_save_msg_request_data;
	RIL_SMS_WriteArgs *args;
	void *buffer = NULL;
	size_t length;
	size_t data_length;
	size_t pdu_length = 0;
	size_t pdu_hex_length = 0;
	size_t smsc_length = 0;
	size_t smsc_hex_length = 0;
	unsigned char *p;

	if (data == NULL || size < sizeof(RIL_SMS_WriteArgs))
		goto error;

	if (ril_radio_state_complete(RADIO_STATE_OFF, token))
		return;

	args = (RIL_SMS_WriteArgs *) data;

	if (args->pdu != NULL) {
		pdu_length = strlen(args->pdu);
		pdu_hex_length = pdu_length % 2 == 0 ? pdu_length / 2 : (pdu_length ^ 1) / 2;
	}

	if (args->smsc != NULL) {
		smsc_length = strlen(args->smsc);
		smsc_hex_length = smsc_length % 2 == 0 ? smsc_length / 2 : (smsc_length ^ 1) / 2;
	}

	data_length = pdu_hex_length + smsc_hex_length;
	if (data_length == 0 || data_length > 0xff)
		goto error;

	length = sizeof(struct ipc_sms_save_msg_request_data) + data_length;
	buffer = malloc(length);

	sms_save_msg_request_data = (struct ipc_sms_save_msg_request_data *) buffer;

	memset(sms_save_msg_request_data, 0, sizeof(struct ipc_sms_save_msg_request_data));
	sms_save_msg_request_data->unknown = 0x02;
	sms_save_msg_request_data->index = 12 - 1;
	sms_save_msg_request_data->status = ril2ipc_sms_save_msg_status(args->status);
	sms_save_msg_request_data->length = (unsigned char) (data_length & 0xff);

	p = (unsigned char *) buffer + sizeof(struct ipc_sms_save_msg_request_data);

	if (args->smsc != NULL && smsc_length > 0) {
		hex2bin(args->smsc, smsc_length, p);
		p += smsc_hex_length;
	}

	if (args->pdu != NULL && pdu_length > 0) {
		hex2bin(args->pdu, pdu_length, p);
		p += pdu_hex_length;
	}

	ipc_gen_phone_res_expect_to_abort(ril_request_get_id(token), IPC_SMS_SAVE_MSG);

	ipc_fmt_send(IPC_SMS_SAVE_MSG, IPC_TYPE_EXEC, buffer, length, ril_request_get_id(token));

	goto complete;

error:
	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

complete:
	if (buffer != NULL)
		free(buffer);
}
Exemplo n.º 21
0
void ril_request_send_sms_complete(RIL_Token t, char *pdu, int pdu_length, unsigned char *smsc, int smsc_length)
{
	struct ipc_sms_send_msg_request send_msg;
	unsigned char send_msg_type;

	unsigned char *pdu_hex;
	int pdu_hex_length;

	void *data;
	int length;

	unsigned char *p;

	if (pdu == NULL || pdu_length <= 0 || smsc == NULL || smsc_length <= 0)
		goto error;

	if ((pdu_length / 2 + smsc_length) > 0xfe) {
		RIL_LOGE("PDU or SMSC too large, aborting");
		goto error;
	}

	pdu_hex_length = pdu_length % 2 == 0 ? pdu_length / 2 :
		(pdu_length ^ 1) / 2;

	// Length of the final message
	length = sizeof(send_msg) + pdu_hex_length + smsc_length;

	RIL_LOGD("Sending SMS message (length: 0x%x)!", length);

	pdu_hex = calloc(1, pdu_hex_length);
	hex2bin(pdu, pdu_length, pdu_hex);
	send_msg_type = IPC_SMS_MSG_SINGLE;

	/* PDU operations */
	int pdu_tp_da_index = 2;
	unsigned char pdu_tp_da_len = pdu_hex[pdu_tp_da_index];

	if (pdu_tp_da_len > 0xff / 2) {
		RIL_LOGE("PDU TP-DA Len failed (0x%x)\n", pdu_tp_da_len);
		goto pdu_end;
	}

	RIL_LOGD("PDU TP-DA Len is 0x%x\n", pdu_tp_da_len);

	int pdu_tp_udh_index = pdu_tp_da_index + pdu_tp_da_len;
	unsigned char pdu_tp_udh_len = pdu_hex[pdu_tp_udh_index];

	if (pdu_tp_udh_len > 0xff / 2 || pdu_tp_udh_len < 5) {
		RIL_LOGE("PDU TP-UDH Len failed (0x%x)\n", pdu_tp_udh_len);
		goto pdu_end;
	}

	RIL_LOGD("PDU TP-UDH Len is 0x%x\n", pdu_tp_udh_len);

	int pdu_tp_udh_num_index = pdu_tp_udh_index + 4;
	unsigned char pdu_tp_udh_num = pdu_hex[pdu_tp_udh_num_index];

	if (pdu_tp_udh_num > 0xf) {
		RIL_LOGE("PDU TP-UDH Num failed (0x%x)\n", pdu_tp_udh_num);
		goto pdu_end;
	}

	int pdu_tp_udh_seq_index = pdu_tp_udh_index + 5;
	unsigned char pdu_tp_udh_seq = pdu_hex[pdu_tp_udh_seq_index];

	if (pdu_tp_udh_seq > 0xf || pdu_tp_udh_seq > pdu_tp_udh_num) {
		RIL_LOGE("PDU TP-UDH Seq failed (0x%x)\n", pdu_tp_udh_seq);
		goto pdu_end;
	}

	RIL_LOGD("We are sending message %d on %d\n", pdu_tp_udh_seq, pdu_tp_udh_num);

	if (pdu_tp_udh_num > 1) {
		RIL_LOGD("We are sending a multi-part message!");
		send_msg_type = IPC_SMS_MSG_MULTIPLE;
	}

pdu_end:
	// Alloc memory for the final message
	data = calloc(1, length);

	// Clear and fill the IPC structure part of the message
	memset(&send_msg, 0, sizeof(struct ipc_sms_send_msg_request));
	send_msg.type = IPC_SMS_TYPE_OUTGOING;
	send_msg.msg_type = send_msg_type;
	send_msg.length = (unsigned char) (pdu_hex_length + smsc_length + 1);
	send_msg.smsc_len = smsc_length;

	// Copy the parts of the message
	p = data;
	memcpy(p, &send_msg, sizeof(send_msg));
	p += sizeof(send_msg);
	memcpy(p, smsc, smsc_length);
	p += smsc_length;
	memcpy(p, pdu_hex, pdu_hex_length);

	ipc_gen_phone_res_expect_to_func(ril_request_get_id(t), IPC_SMS_SEND_MSG, ipc_sms_send_msg_complete);

	ipc_fmt_send(IPC_SMS_SEND_MSG, IPC_TYPE_EXEC, data, length, ril_request_get_id(t));

	free(pdu_hex);
	free(data);

	return;

error:
	ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
	// Send the next SMS in the list
	ril_request_send_sms_next();
}
int ril_request_get_sim_status(void *data, size_t size, RIL_Token token)
{
	void *card_status_data;
	size_t card_status_size;
#if RIL_VERSION >= 6
	RIL_CardStatus_v6 *card_status;
#else
	RIL_CardStatus *card_status;
#endif
	struct ril_request *request;
	int rc;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_GET_SIM_STATUS, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	card_status_size = ril_request_data_size_get(RIL_REQUEST_GET_SIM_STATUS);
	card_status_data = ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS);

#if RIL_VERSION >= 6
	if (card_status_data != NULL && card_status_size >= sizeof(RIL_CardStatus_v6)) {
		card_status = (RIL_CardStatus_v6 *) ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS);
#else
	if (card_status_data != NULL && card_status_size >= sizeof(RIL_CardStatus)) {
		card_status = (RIL_CardStatus *) ril_request_data_get(RIL_REQUEST_GET_SIM_STATUS);
#endif
		ril_request_complete(token, RIL_E_SUCCESS, card_status_data, card_status_size);

		free(card_status_data);

		return RIL_REQUEST_COMPLETED;
	} else {
		rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_GET, NULL, 0);
		if (rc < 0) {
			ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
			return RIL_REQUEST_COMPLETED;
		}

		return RIL_REQUEST_HANDLED;
	}
}

int ipc_sec_phone_lock(struct ipc_message *message)
{
	struct ipc_sec_phone_lock_response_data *data;
	int active;

	if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_phone_lock_response_data))
		return -1;

	if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq))
		return 0;

	data = (struct ipc_sec_phone_lock_response_data *) message->data;

	active = !!data->active;

	ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &active, sizeof(active));

	return 0;
}

int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_phone_lock_request_get_data request_data;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 4 * sizeof(char *))
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	request_data.facility_type = ril2ipc_sec_facility_type(values[0]);
	if (request_data.facility_type == 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc =  RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ipc_sec_callback(struct ipc_message *message)
{
	struct ipc_sec_lock_infomation_request_data request_data;
	struct ipc_gen_phone_res_data *data;
	struct ril_request *request = NULL;
	void *request_complete_data;
	size_t request_complete_size;
	unsigned char facility_type;
	char **values;
	int retry_count;
	int rc;

	if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data))
		return -1;

	data = (struct ipc_gen_phone_res_data *) message->data;

	request = ril_request_find_token(ipc_fmt_request_token(message->aseq));
	if (request == NULL)
		goto error;

	if (request->request == RIL_REQUEST_ENTER_SIM_PIN || request->request == RIL_REQUEST_CHANGE_SIM_PIN) {
		// Grab the count of remaining tries before completing the request

		ril_request_data_set_uniq(request->request, (void *) data, sizeof(struct ipc_gen_phone_res_data));

		rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1);
		if (rc < 0) {
			ril_request_data_free(request->request);
			goto error;
		}

		rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data));
		if (rc < 0) {
			ril_request_data_free(request->request);
			goto error;
		}
	} else if (request->request == RIL_REQUEST_ENTER_SIM_PIN2 || request->request == RIL_REQUEST_CHANGE_SIM_PIN2) {
		// Grab the count of remaining tries before completing the request

		ril_request_data_set_uniq(request->request, (void *) data, sizeof(struct ipc_gen_phone_res_data));

		rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2);
		if (rc < 0) {
			ril_request_data_free(request->request);
			goto error;
		}

		rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data));
		if (rc < 0) {
			ril_request_data_free(request->request);
			goto error;
		}
	} else if (request->request == RIL_REQUEST_SET_FACILITY_LOCK) {
		values = (char **) request->data;

		request_complete_size = ril_request_data_size_get(RIL_REQUEST_SET_FACILITY_LOCK);
		request_complete_data = ril_request_data_get(RIL_REQUEST_SET_FACILITY_LOCK);

		rc = ipc_gen_phone_res_check(data);

		if (request_complete_data != NULL && request_complete_size > 0 && rc >= 0) {
			rc = ipc_gen_phone_res_expect_callback(message->aseq, IPC_SEC_PHONE_LOCK, ipc_sec_callback);
			if (rc < 0) {
				strings_array_free(values, request->size);
				goto error;
			}

			rc = ipc_fmt_send(message->aseq, IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, request_complete_data, request_complete_size);
			if (rc < 0) {
				strings_array_free(values, request->size);
				goto error;
			}
		} else {
			// When FD facility PIN2 unlock failed, ask the count of remaining tries directly

			facility_type = ril2ipc_sec_facility_type(values[0]);

			strings_array_free(values, request->size);

			// Grab the count of remaining tries before completing the request

			ril_request_data_set_uniq(RIL_REQUEST_SET_FACILITY_LOCK, (void *) data, sizeof(struct ipc_gen_phone_res_data));

			if (facility_type == IPC_SEC_FACILITY_TYPE_FD) {
				rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2);
				if (rc < 0) {
					ril_request_data_free(request->request);
					goto error;
				}
			} else {
				rc = ipc_sec_lock_infomation_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1);
				if (rc < 0) {
					ril_request_data_free(request->request);
					goto error;
				}
			}

			rc = ipc_fmt_send(message->aseq, IPC_SEC_LOCK_INFOMATION, IPC_TYPE_GET, (void *) &request_data, sizeof(request_data));
			if (rc < 0) {
				ril_request_data_free(request->request);
				goto error;
			}
		}
	} else if (request->request == RIL_REQUEST_SIM_IO) {
		request_complete_size = ril_request_data_size_get(RIL_REQUEST_SIM_IO);
		request_complete_data = ril_request_data_get(RIL_REQUEST_SIM_IO);

		rc = ipc_gen_phone_res_check(data);
		if (rc < 0) {
			ril_request_complete(request->token, RIL_E_SIM_PIN2, NULL, 0);
			goto complete;
		}

		if (request_complete_data != NULL && request_complete_size > 0) {
			rc = ipc_fmt_send(message->aseq, IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, request_complete_data, request_complete_size);
			if (rc < 0)
				goto error;
		} else {
			goto error;
		}
	} else {
		retry_count = -1;

		rc = ipc_gen_phone_res_check(data);
		if (rc < 0) {
			if ((data->code & 0xff) == 0x10) {
				RIL_LOGE("%s: Wrong password", __func__);
				ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count));
			} else if ((data->code & 0xff) == 0x0c) {
				RIL_LOGE("%s: Wrong password and no attempts left", __func__);
				retry_count = 0;
				ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count));
			} else {
				ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, &retry_count, sizeof(retry_count));
			}
		} else {
			ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &retry_count, sizeof(retry_count));
		}
	}

	if (request->request == RIL_REQUEST_ENTER_SIM_PUK || request->request == RIL_REQUEST_ENTER_SIM_PUK2)
		ril_request_unsolicited(RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);

	goto complete;

error:
	if (request != NULL)
		ril_request_complete(request->token, RIL_E_GENERIC_FAILURE, NULL, 0);

complete:
	return 0;
}

int ril_request_set_facility_lock(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_phone_lock_request_set_data request_data;
	struct ipc_sec_pin_status_request_data pin_request_data;
	struct ril_request *request;
	unsigned char facility_type;
	unsigned char active;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 4 * sizeof(char *))
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_SET_FACILITY_LOCK, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	facility_type = ril2ipc_sec_facility_type(values[0]);
	if (facility_type == 0)
		goto error;

	active = values[1][0] == '1';

	rc = ipc_sec_phone_lock_request_set_setup(&request_data, facility_type, active, values[2]);
	if (rc < 0)
		goto error;

	if (facility_type == IPC_SEC_FACILITY_TYPE_FD) {
		// FD facility requires PIN2 unlock first

		rc = ipc_sec_pin_status_setup(&pin_request_data, IPC_SEC_PIN_TYPE_PIN2, values[2], NULL);
		if (rc < 0)
			goto error;

		ril_request_data_set_uniq(RIL_REQUEST_SET_FACILITY_LOCK, &request_data, sizeof(request_data));

		rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback);
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_SET_FACILITY_LOCK);
			goto error;
		}

		rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_request_data, sizeof(pin_request_data));
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_SET_FACILITY_LOCK);
			goto error;
		}

		rc = RIL_REQUEST_HANDLED;
		goto complete;
	}

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PHONE_LOCK, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ril_request_enter_sim_pin(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_pin_status_request_data request_data;
	struct ril_request *request;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 2 * sizeof(char *) || ril_data == NULL)
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PIN, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;
	if (values[0] == NULL)
		goto error;

	if (ril_data->sim_pin != NULL)
		free(ril_data->sim_pin);

	ril_data->sim_pin = strdup(values[0]);

	rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, values[0], NULL);
	if (rc < 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ril_request_enter_sim_puk(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_pin_status_request_data request_data;
	struct ril_request *request;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 2 * sizeof(char *))
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PUK, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN1, values[1], values[0]);
	if (rc < 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ril_request_enter_sim_pin2(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_pin_status_request_data request_data;
	struct ril_request *request;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 2 * sizeof(char *))
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PIN2, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2, values[0], NULL);
	if (rc < 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ril_request_enter_sim_puk2(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_pin_status_request_data request_data;
	struct ril_request *request;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 2 * sizeof(char *))
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_ENTER_SIM_PUK2, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	rc = ipc_sec_pin_status_setup(&request_data, IPC_SEC_PIN_TYPE_PIN2, values[1], values[0]);
	if (rc < 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ril_request_change_sim_pin(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_change_locking_pw_data request_data;
	struct ril_request *request;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 3 * sizeof(char *))
		goto error;

	request = ril_request_find_request_status(RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	rc = ipc_sec_change_locking_pw_setup(&request_data, IPC_SEC_FACILITY_TYPE_SC, values[0], values[1]);
	if (rc < 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ril_request_change_sim_pin2(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_change_locking_pw_data request_data;
	struct ril_request *request;
	char **values = NULL;
	int rc;

	if (data == NULL || size < 3 * sizeof(char *))
		goto error;

	request = ril_request_find_request_status(RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

	rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	values = (char **) data;

	rc = ipc_sec_change_locking_pw_setup(&request_data, IPC_SEC_FACILITY_TYPE_FD, values[0], values[1]);
	if (rc < 0)
		goto error;

	strings_array_free(values, size);
	values = NULL;

	rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, ipc_sec_callback);
	if (rc < 0)
		goto error;

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_CHANGE_LOCKING_PW, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data));
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (values != NULL)
		strings_array_free(values, size);

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	return rc;
}

int ipc_sec_rsim_access(struct ipc_message *message)
{
	struct ipc_sec_rsim_access_response_header *header;
	struct ipc_sec_rsim_access_usim_response_header *usim_header;
	struct sim_file_response sim_file_response;
	struct ril_request *request;
	struct ril_client *client;
	struct ipc_fmt_data *ipc_fmt_data;
	RIL_SIM_IO_Response response;
#if RIL_VERSION >= 6
	RIL_SIM_IO_v6 *sim_io;
#else
	RIL_SIM_IO *sim_io;
#endif
	unsigned char *p;
	unsigned int offset;
	unsigned int i;
	void *data;
	size_t size;

	if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_rsim_access_response_header))
		return -1;

	client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
	if (client == NULL || client->data == NULL)
		return 0;

	if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq))
		return 0;

	ipc_fmt_data = (struct ipc_fmt_data *) client->data;

	header = (struct ipc_sec_rsim_access_response_header *) message->data;

	size = ipc_sec_rsim_access_size_extract(message->data, message->size);
	data = ipc_sec_rsim_access_extract(message->data, message->size);

	request = ril_request_find_token(ipc_fmt_request_token(message->aseq));
#if RIL_VERSION >= 6
	if (request == NULL || request->data == NULL || request->size < sizeof(RIL_SIM_IO_v6))
#else
	if (request == NULL || request->data == NULL || request->size < sizeof(RIL_SIM_IO))
#endif
		return 0;

#if RIL_VERSION >= 6
	sim_io = (RIL_SIM_IO_v6 *) request->data;
#else
	sim_io = (RIL_SIM_IO *) request->data;
#endif

	memset(&response, 0, sizeof(response));
	response.sw1 = header->sw1;
	response.sw2 = header->sw2;

	switch (sim_io->command) {
		case SIM_COMMAND_READ_BINARY:
		case SIM_COMMAND_READ_RECORD:
			if (header->length == 0)
				break;

			response.simResponse = data2string(data, header->length);
			break;
		case SIM_COMMAND_GET_RESPONSE:
			if (header->length == 0)
				break;

			if (ipc_fmt_data->sim_icc_type_data.type == 0x01) {
				response.simResponse = data2string(data, header->length);
				break;
			}

			if (header->length < sizeof(struct ipc_sec_rsim_access_usim_response_header))
				break;

			usim_header = (struct ipc_sec_rsim_access_usim_response_header *) data;

			memset(&sim_file_response, 0, sizeof(sim_file_response));

			offset = sizeof(struct ipc_sec_rsim_access_usim_response_header) + usim_header->offset;
			if (offset > header->length)
				break;

			offset = usim_header->offset - 2;
			p = (unsigned char *) usim_header + offset;

			sim_file_response.file_id[0] = p[0];
			sim_file_response.file_id[1] = p[1];

			offset = header->length - 2;
			p = (unsigned char *) usim_header;

			while (offset > 2) {
				if (p[offset] == 0x88) {
					offset -= 2;
					break;
				}

				offset--;
			}

			if (offset <= 2)
				break;

			p = (unsigned char *) usim_header + offset;

			sim_file_response.file_size[0] = p[0];
			sim_file_response.file_size[1] = p[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->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 (usim_header->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 = usim_header->length;

			response.simResponse = data2string((void *) &sim_file_response, sizeof(sim_file_response));
			break;
		case SIM_COMMAND_UPDATE_BINARY:
		case SIM_COMMAND_UPDATE_RECORD:
		case SIM_COMMAND_SEEK:
		default:
			response.simResponse = NULL;
			break;
	}

	ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) &response, sizeof(response));

	if (response.simResponse != NULL)
		free(response.simResponse);

	return 0;
}

int ril_request_sim_io(void *data, size_t size, RIL_Token token)
{
	struct ipc_sec_rsim_access_request_header request_header;
	struct ipc_sec_pin_status_request_data pin_request_data;
	struct ril_request *request;
#if RIL_VERSION >= 6
	RIL_SIM_IO_v6 *sim_io = NULL;
#else
	RIL_SIM_IO *sim_io = NULL;
#endif
	void *sim_io_data = NULL;
	size_t sim_io_size = 0;
	void *request_data = NULL;
	size_t request_size = 0;
	int pin_request = 0;
	int rc;

#if RIL_VERSION >= 6
	if (data == NULL || size < sizeof(RIL_SIM_IO_v6))
#else
	if (data == NULL || size < sizeof(RIL_SIM_IO))
#endif
		goto error;

	rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
	if (rc < 0)
		return RIL_REQUEST_UNHANDLED;

	request = ril_request_find_request_status(RIL_REQUEST_SIM_IO, RIL_REQUEST_HANDLED);
	if (request != NULL)
		return RIL_REQUEST_UNHANDLED;

#if RIL_VERSION >= 6
	sim_io = (RIL_SIM_IO_v6 *) data;
#else
	sim_io = (RIL_SIM_IO *) data;
#endif

	if (sim_io->data != NULL) {
		sim_io_size = string2data_size(sim_io->data);
		if (sim_io_size == 0)
			goto error;

		sim_io_data = string2data(sim_io->data);
		if (sim_io_data == NULL)
			goto error;
	}

	if (sim_io->pin2 != NULL) {
		// PIN2 unlock first

		pin_request = 1;

		rc = ipc_sec_pin_status_setup(&pin_request_data, IPC_SEC_PIN_TYPE_PIN2, sim_io->pin2, NULL);
		if (rc < 0)
			goto error;
	}

	if (sim_io->path != NULL)
		free(sim_io->path);

	if (sim_io->data != NULL)
		free(sim_io->data);

	if (sim_io->pin2 != NULL)
		free(sim_io->pin2);

#if RIL_VERSION >= 6
	if (sim_io->aidPtr != NULL)
		free(sim_io->aidPtr);
#endif

	memset(&request_header, 0, sizeof(request_header));
	request_header.command = sim_io->command;
	request_header.file_id = sim_io->fileid;
	request_header.p1 = sim_io->p1;
	request_header.p2 = sim_io->p2;
	request_header.p3 = sim_io->p3;

	sim_io = NULL;

	request_size = ipc_sec_rsim_access_size_setup(&request_header, sim_io_data, sim_io_size);
	if (request_size == 0)
		goto error;

	request_data = ipc_sec_rsim_access_setup(&request_header, sim_io_data, sim_io_size);
	if (request_data == NULL)
		goto error;

	if (pin_request) {
		// PIN2 unlock first

		ril_request_data_set_uniq(RIL_REQUEST_SIM_IO, request_data, request_size);

		rc = ipc_gen_phone_res_expect_callback(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, ipc_sec_callback);
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_SIM_IO);
			goto error;
		}

		rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_PIN_STATUS, IPC_TYPE_SET, (void *) &pin_request_data, sizeof(pin_request_data));
		if (rc < 0) {
			ril_request_data_free(RIL_REQUEST_SIM_IO);
			goto error;
		}

		rc = RIL_REQUEST_HANDLED;
		goto complete;
	}

	rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_SEC_RSIM_ACCESS, IPC_TYPE_GET, request_data, request_size);
	if (rc < 0)
		goto error;

	rc = RIL_REQUEST_HANDLED;
	goto complete;

error:
	if (sim_io != NULL) {
		if (sim_io->path != NULL)
			free(sim_io->path);

		if (sim_io->data != NULL)
			free(sim_io->data);

		if (sim_io->pin2 != NULL)
			free(sim_io->pin2);

#if RIL_VERSION >= 6
		if (sim_io->aidPtr != NULL)
			free(sim_io->aidPtr);
#endif
	}

	ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);

	rc = RIL_REQUEST_COMPLETED;

complete:
	if (sim_io_data != NULL && sim_io_size > 0)
		free(sim_io_data);

	if (request_data != NULL && request_size > 0)
		free(request_data);

	return rc;
}

int ipc_sec_sim_icc_type(struct ipc_message *message)
{
	struct ipc_sec_sim_icc_type_data *data;
	struct ril_client *client;
	struct ipc_fmt_data *ipc_fmt_data;

	if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_sim_icc_type_data))
		return -1;

	client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
	if (client == NULL || client->data == NULL)
		return 0;

	ipc_fmt_data = (struct ipc_fmt_data *) client->data;

	data = (struct ipc_sec_sim_icc_type_data *) message->data;

	if (ipc_fmt_data->sim_icc_type_data.type != data->type)
		ipc_fmt_data->sim_icc_type_data.type = data->type;

	return 0;
}

int ipc_sec_lock_infomation(struct ipc_message *message)
{
	struct ipc_sec_lock_infomation_response_data *data;
	struct ipc_gen_phone_res_data *gen_phone_res;
	int requests[] = { RIL_REQUEST_ENTER_SIM_PIN, RIL_REQUEST_CHANGE_SIM_PIN, RIL_REQUEST_ENTER_SIM_PIN2, RIL_REQUEST_CHANGE_SIM_PIN2, RIL_REQUEST_SET_FACILITY_LOCK };
	void *gen_phone_res_data = NULL;
	size_t gen_phone_res_size = 0;
	int retry_count;
	unsigned int count;
	unsigned int i;
	int rc;

	if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_sec_lock_infomation_response_data))
		return -1;

	rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY);
	if (rc < 0)
		return 0;

	if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq))
		return 0;

	data = (struct ipc_sec_lock_infomation_response_data *) message->data;
	if (data->type != IPC_SEC_PIN_TYPE_PIN1 && data->type != IPC_SEC_PIN_TYPE_PIN2)
		return 0;

	count = sizeof(requests) / sizeof(int);

	for (i = 0; i < count; i++) {
		gen_phone_res_size = ril_request_data_size_get(requests[i]);
		if (gen_phone_res_size < sizeof(struct ipc_gen_phone_res_data))
			continue;

		gen_phone_res_data = ril_request_data_get(requests[i]);
		if (gen_phone_res_data == NULL)
			continue;

		break;
	}

	if (gen_phone_res_data == NULL || gen_phone_res_size < sizeof(struct ipc_gen_phone_res_data))
		return 0;

	gen_phone_res = (struct ipc_gen_phone_res_data *) gen_phone_res_data;

	retry_count = data->retry_count;

	rc = ipc_gen_phone_res_check(gen_phone_res);
	if (rc < 0) {
		if ((gen_phone_res->code & 0xff) == 0x10) {
			RIL_LOGE("%s: Wrong password and %d attempts left", __func__, retry_count);
			ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count));
		} else if ((gen_phone_res->code & 0xff) == 0x0c) {
			RIL_LOGE("%s: Wrong password and no attempts left", __func__);
			retry_count = 0;
			ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_PASSWORD_INCORRECT, &retry_count, sizeof(retry_count));
		} else {
			ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, &retry_count, sizeof(retry_count));
		}
	} else {
		ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, &retry_count, sizeof(retry_count));
	}

	free(gen_phone_res_data);

	return 0;
}