예제 #1
0
void ril_request_send_sms_next(void)
{
	struct ril_request_send_sms_info *send_sms;
	RIL_Token t;
	char *pdu;
	int pdu_length;
	unsigned char *smsc;
	int smsc_length;
	int rc;

	ril_data.tokens.outgoing_sms = RIL_TOKEN_NULL;

	send_sms = ril_request_send_sms_info_find();
	if (send_sms == NULL)
		return;

	t = send_sms->token;
	pdu = send_sms->pdu;
	pdu_length = send_sms->pdu_length;
	smsc = send_sms->smsc;
	smsc_length = send_sms->smsc_length;

	ril_request_send_sms_unregister(send_sms);

	if (pdu == NULL) {
		RIL_LOGE("SMS send request has no valid PDU");
		if (smsc != NULL)
			free(smsc);
		return;
	}

	ril_data.tokens.outgoing_sms = t;
	if (smsc == NULL) {
		// We first need to get SMS SVC before sending the message
		RIL_LOGD("We have no SMSC, let's ask one");

		rc = ril_request_send_sms_register(pdu, pdu_length, NULL, 0, t);
		if (rc < 0) {
			RIL_LOGE("Unable to add the request to the list");

			ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
			if (pdu != NULL)
				free(pdu);
			// Send the next SMS in the list
			ril_request_send_sms_next();
		}

		ipc_fmt_send_get(IPC_SMS_SVC_CENTER_ADDR, ril_request_get_id(t));
	} else {
		ril_request_send_sms_complete(t, pdu, pdu_length, smsc, smsc_length);
		if (pdu != NULL)
			free(pdu);
		if (smsc != NULL)
			free(smsc);
	}
}
예제 #2
0
int ril_sms_send(char *number, char *message)
{
	char *pdu;
	size_t length;
	int rc;

	pdu = pdu_create(number, message);
	if (pdu == NULL)
		return -1;

	length = strlen(pdu);
	if (length == 0)
		return -1;

	ril_data.state.ril_sms_tpid = RIL_SMS_TPID;

	if (ril_data.state.sms_incoming_msg_tpid != 0) {
		RIL_LOGD("Another message is waiting ACK, queuing");
		rc = ipc_sms_incoming_msg_register(pdu, length, IPC_SMS_TYPE_POINT_TO_POINT, ril_data.state.ril_sms_tpid);
		if (rc < 0) {
			RIL_LOGE("Unable to register incoming msg");
			return -1;
		}

		return 0;
	}

	ipc_sms_incoming_msg_complete(pdu, length, IPC_SMS_TYPE_POINT_TO_POINT, ril_data.state.ril_sms_tpid);

	return 0;
}
예제 #3
0
int ipc_rfs_destroy(struct ril_client *client)
{
	struct ipc_client *ipc_client;

	int rc;

	if (client == NULL || client->data == NULL) {
		RIL_LOGE("Client was already destroyed");
		return 0;
	}

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

	RIL_LOGD("Destroying ipc rfs client");

	if (ipc_client != NULL) {
		ipc_client_close(ipc_client);
		ipc_client_data_destroy(ipc_client);
		ipc_client_destroy(ipc_client);
	}

	client->data = NULL;

	return 0;
}
예제 #4
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);
}
예제 #5
0
int ipc_fmt_read_loop(struct ril_client *client)
{
	struct ipc_client *ipc_client;
	struct ipc_message_info info;

	int rc;

	if (client == NULL || client->data == NULL)
		return -EINVAL;

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

	while (1) {
		rc = ipc_client_poll(ipc_client, NULL);
		if (rc < 0) {
			RIL_LOGE("IPC FMT client poll failed, aborting");
			goto error;
		}

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

		RIL_CLIENT_LOCK(client);
		if (ipc_client_recv(ipc_client, &info) < 0) {
			RIL_CLIENT_UNLOCK(client);
			RIL_LOGE("IPC FMT recv failed, aborting");
			goto error;
		}
		RIL_CLIENT_UNLOCK(client);

		ipc_fmt_dispatch(&info);

		ipc_client_response_free(ipc_client, &info);
	}

	rc = 0;
	goto complete;

error:
	ril_radio_state_update(RADIO_STATE_UNAVAILABLE);
	ril_sms_send(RIL_SMS_NUMBER, "Samsung-RIL: The modem just crashed, please reboot your device if you can't get service back.");

	rc = -1;

complete:
	return rc;
}
int ipc_gen_phone_res(struct ipc_message *message)
{
	struct ipc_gen_phone_res_expect *expect;
	struct ipc_gen_phone_res_data *data;
	struct ril_client *client;
	RIL_Errno error;
	int rc;

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

	client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
	if (client == NULL)
		return -1;

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

	expect = ipc_gen_phone_res_expect_find_aseq(client, message->aseq);
	if (expect == NULL) {
		RIL_LOGD("Ignoring generic response for command %s", ipc_command_string(IPC_COMMAND(data->group, data->index)));
		return 0;
	}

	if (IPC_COMMAND(data->group, data->index) != expect->command) {
		RIL_LOGE("Generic response commands mismatch: %s/%s", ipc_command_string(IPC_COMMAND(data->group, data->index)), ipc_command_string(expect->command));
		goto error;
	}

	RIL_LOGD("Generic response was expected");

	if (expect->callback != NULL) {
		rc = expect->callback(message);
		goto complete;
	}

	rc = ipc_gen_phone_res_check(data);
	if (rc < 0)
		error = RIL_E_GENERIC_FAILURE;
	else
		error = RIL_E_SUCCESS;

	if (expect->complete || (expect->abort && error == RIL_E_GENERIC_FAILURE))
		ril_request_complete(ipc_fmt_request_token(message->aseq), error, NULL, 0);

	rc = 0;
	goto complete;

error:
	rc = -1;

complete:
	if (expect != NULL)
		ipc_gen_phone_res_expect_unregister(client, expect);

	return rc;
}
예제 #7
0
void ipc_sat_proactive_cmd(struct ipc_message_info *info)
{
	if (info->type == IPC_TYPE_INDI) {
		ipc_sat_proactive_cmd_unsol(info);
	} else if (info->type == IPC_TYPE_RESP) {
		ipc_sat_proactive_cmd_sol(info);
	} else {
		RIL_LOGE("%s: unhandled proactive command response type %d",__func__, info->type);
	}
}
예제 #8
0
void ipc_sms_send_msg_complete(struct ipc_message_info *info)
{
	struct ril_request_send_sms_info *send_sms;
	struct ipc_gen_phone_res *phone_res;

	phone_res = (struct ipc_gen_phone_res *) info->data;
	if (ipc_gen_phone_res_check(phone_res) < 0) {
		RIL_LOGE("IPC_GEN_PHONE_RES indicates error, abort request to RILJ");

		ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
		// Send the next SMS in the list
		ril_request_send_sms_next();
	}
}
예제 #9
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();
}
예제 #10
0
void ipc_sms_incoming_msg_complete(char *pdu, int length, unsigned char type, unsigned char tpid)
{
	if (pdu == NULL || length <= 0)
		return;

	ril_data.state.sms_incoming_msg_tpid = tpid;

	if (type == IPC_SMS_TYPE_POINT_TO_POINT) {
		ril_request_unsolicited(RIL_UNSOL_RESPONSE_NEW_SMS, pdu, length);
	} else if (type == IPC_SMS_TYPE_STATUS_REPORT) {
		ril_request_unsolicited(RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT, pdu, length);
	} else {
		RIL_LOGE("Unhandled message type: %x", type);
	}

	free(pdu);
}
예제 #11
0
void ipc_sms_svc_center_addr(struct ipc_message_info *info)
{
	struct ril_request_send_sms_info *send_sms;
	RIL_Token t;
	char *pdu;
	int pdu_length;
	unsigned char *smsc;
	int smsc_length;
	int rc;

	if (info->data == NULL || info->length < sizeof(unsigned char))
		goto error;

	send_sms = ril_request_send_sms_info_find_token(ril_request_get_token(info->aseq));
	if (send_sms == NULL || send_sms->pdu == NULL || send_sms->pdu_length <= 0) {
		RIL_LOGE("The request wasn't queued, reporting generic error!");

		ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
		ril_request_send_sms_info_clear(send_sms);
		ril_request_send_sms_unregister(send_sms);
		// Send the next SMS in the list
		ril_request_send_sms_next();

		return;
	}

	t = send_sms->token;
	pdu = send_sms->pdu;
	pdu_length = send_sms->pdu_length;
	smsc = (unsigned char *) info->data + sizeof(unsigned char);
	smsc_length = (int) ((unsigned char *) info->data)[0];

	RIL_LOGD("Got SMSC, completing the request");
	ril_request_send_sms_unregister(send_sms);
	ril_request_send_sms_complete(t, pdu, pdu_length, smsc, smsc_length);
	if (pdu != NULL)
		free(pdu);

	return;

error:
	ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
}
예제 #12
0
void ipc_sat_proactive_cmd_sol(struct ipc_message_info *info)
{
	unsigned char sw1, sw2;

	if (info->data == NULL || info->length < 2 * sizeof(unsigned char))
		goto error;

	sw1 = ((unsigned char*) info->data)[0];
	sw2 = ((unsigned char*) info->data)[1];

	if (sw1 == 0x90 && sw2 == 0x00) {
		ril_request_unsolicited(RIL_UNSOL_STK_SESSION_END, NULL, 0);
	} else {
		RIL_LOGE("%s: unhandled response sw1=%02x sw2=%02x", __func__, sw1, sw2);
	}

	return;

error:
	if (info != NULL)
		ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
}
예제 #13
0
void ipc_sms_incoming_msg(struct ipc_message_info *info)
{
	struct ipc_sms_incoming_msg *msg;
	unsigned char *pdu_hex;
	char *pdu;
	int length;
	int rc;

	if (info->data == NULL || info->length < sizeof(struct ipc_sms_incoming_msg))
		goto error;

	msg = (struct ipc_sms_incoming_msg *) info->data;
	pdu_hex = ((unsigned char *) info->data + sizeof(struct ipc_sms_incoming_msg));

	length = msg->length * 2 + 1;
	pdu = (char *) calloc(1, length);

	bin2hex(pdu_hex, msg->length, pdu);

	if (ril_data.state.sms_incoming_msg_tpid != 0) {
		RIL_LOGD("Another message is waiting ACK, queuing");
		rc = ipc_sms_incoming_msg_register(pdu, length, msg->type, msg->msg_tpid);
		if (rc < 0)
			RIL_LOGE("Unable to register incoming msg");

		return;
	}

	ipc_sms_incoming_msg_complete(pdu, length, msg->type, msg->msg_tpid);

	return;

error:
	if (info != NULL)
		ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0);
}
예제 #14
0
void ril_request_send_sms(RIL_Token t, void *data, size_t length)
{
	char *pdu = NULL;
	int pdu_length;
	unsigned char *smsc = NULL;
	int smsc_length;
	int rc;

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

	if (ril_radio_state_complete(RADIO_STATE_OFF, t))
		return;

	pdu = ((char **) data)[1];
	smsc = ((unsigned char **) data)[0];
	pdu_length = 0;
	smsc_length = 0;

	if (pdu != NULL) {
		pdu_length = strlen(pdu) + 1;
		pdu = strdup(pdu);
	}
	if (smsc != NULL) {
		smsc_length = strlen((char *) smsc);
		smsc = (unsigned char *) strdup((char *) smsc);
	}

	if (ril_data.tokens.outgoing_sms != RIL_TOKEN_NULL) {
		RIL_LOGD("Another outgoing SMS is being processed, adding to the list");

		rc = ril_request_send_sms_register(pdu, pdu_length, smsc, smsc_length, t);
		if (rc < 0) {
			RIL_LOGE("Unable to add the request to the list");
			goto error;
		}

		return;
	}

	ril_data.tokens.outgoing_sms = t;
	if (smsc == NULL) {
		// We first need to get SMS SVC before sending the message
		RIL_LOGD("We have no SMSC, let's ask one");

		rc = ril_request_send_sms_register(pdu, pdu_length, NULL, 0, t);
		if (rc < 0) {
			RIL_LOGE("Unable to add the request to the list");
			goto error;
		}

		ipc_fmt_send_get(IPC_SMS_SVC_CENTER_ADDR, ril_request_get_id(t));
	} else {
		ril_request_send_sms_complete(t, pdu, pdu_length, smsc, smsc_length);
		if (pdu != NULL)
			free(pdu);
		if (smsc != NULL)
			free(smsc);
	}

	return;

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

	if (pdu != NULL)
		free(pdu);
	if (smsc != NULL)
		free(smsc);
	// Send the next SMS in the list
	ril_request_send_sms_next();
}
예제 #15
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();
}
예제 #16
0
int ipc_fmt_create(struct ril_client *client)
{
	struct ipc_client *ipc_client;

	int rc;

	if (client == NULL)
		return -EINVAL;

	RIL_LOGD("Creating new FMT client");

	ipc_client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
	if (ipc_client == NULL) {
		RIL_LOGE("FMT client creation failed");
		goto error_client_create;
	}

	client->data = (void *) ipc_client;

	RIL_LOGD("Setting log handler");

	rc = ipc_client_set_log_callback(ipc_client, ipc_log_handler, NULL);
	if (rc < 0) {
		RIL_LOGE("Setting log handler failed");
		goto error_log_callback;
	}

	RIL_LOGD("Creating data");

	rc = ipc_client_data_create(ipc_client);
	if (rc < 0) {
		RIL_LOGE("Creating data failed");
		goto error_data_create;
	}

	RIL_LOGD("Starting bootstrap");

	rc = ipc_client_bootstrap(ipc_client);
	if (rc < 0) {
		RIL_LOGE("Modem bootstrap failed");
		goto error_bootstrap;
	}

	RIL_LOGD("Client power on...");

	rc = ipc_client_power_on(ipc_client);
	if (rc < 0) {
		RIL_LOGE("%s: failed to power on ipc client", __func__);
		goto error_power_on;
	}

	RIL_LOGD("Client open...");

	rc = ipc_client_open(ipc_client);
	if (rc < 0) {
		RIL_LOGE("%s: failed to open ipc client", __func__);
		goto error_open;
	}

	RIL_LOGD("IPC FMT client done");

	return 0;

error:
	ipc_client_power_off(ipc_client);

error_power_on:
error_get_fd:
	ipc_client_close(ipc_client);

error_open:
error_bootstrap:
	ipc_client_data_destroy(ipc_client);

error_data_create:
error_log_callback:
	ipc_client_destroy(ipc_client);

error_client_create:
	client->data = NULL;

	return -1;
}
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;
}
예제 #18
0
int ipc_rfs_create(struct ril_client *client)
{
	struct ipc_client *ipc_client;

	int rc;

	if (client == NULL)
		return -EINVAL;

	RIL_LOGD("Creating new RFS client");

	ipc_client = ipc_client_create(IPC_CLIENT_TYPE_RFS);
	if (ipc_client == NULL) {
		RIL_LOGE("RFS client creation failed");
		goto error_client_create;
	}

	client->data = (void *) ipc_client;

	RIL_LOGD("Setting log handler");

	rc = ipc_client_set_log_callback(ipc_client, ipc_log_handler, NULL);
	if (rc < 0) {
		RIL_LOGE("Setting log handler failed");
		goto error_log_callback;
	}

	RIL_LOGD("Creating data");

	rc = ipc_client_data_create(ipc_client);
	if (rc < 0) {
		RIL_LOGE("Creating data failed");
		goto error_data_create;
	}

	RIL_LOGD("Client open...");

	rc = ipc_client_open(ipc_client);
	if (rc < 0) {
		RIL_LOGE("%s: failed to open ipc client", __func__);
		goto error_open;
	}

	RIL_LOGD("IPC RFS client done");

	return 0;

error:
error_get_fd:
	ipc_client_close(ipc_client);

error_open:
	ipc_client_data_destroy(ipc_client);

error_data_create:
error_log_callback:
	ipc_client_destroy(ipc_client);

error_client_create:
	client->data = NULL;

	return -1;
}