summaryrefslogtreecommitdiffstats
path: root/sim.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim.c')
-rw-r--r--sim.c695
1 files changed, 695 insertions, 0 deletions
diff --git a/sim.c b/sim.c
new file mode 100644
index 0000000..aaeb1f3
--- /dev/null
+++ b/sim.c
@@ -0,0 +1,695 @@
+/*
+ * This file is part of QMI-RIL.
+ *
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ *
+ * QMI-RIL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QMI-RIL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QMI-RIL. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+
+#define LOG_TAG "RIL"
+#include <utils/Log.h>
+
+#include <qmi-ril.h>
+#include <sim.h>
+
+RIL_RadioState qmi2ril_pin_status_response(QmiDmsUimPinStatus pin_status,
+ RIL_CardStatus_v6 *card_status)
+{
+ RIL_AppStatus app_statuses[] = {
+ // Absent
+ { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ // Not ready
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ // Ready
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY, NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
+ // PIN lock
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
+ // PUK lock
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
+ // PUK locked
+ { RIL_APPTYPE_USIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN, NULL, NULL, 0, RIL_PINSTATE_ENABLED_PERM_BLOCKED, RIL_PINSTATE_UNKNOWN },
+ };
+ RIL_RadioState radio_state;
+ unsigned int index;
+ unsigned int count;
+
+ count = sizeof(app_statuses) / sizeof(RIL_AppStatus);
+
+ switch (pin_status) {
+ case QMI_DMS_UIM_PIN_STATUS_NOT_INITIALIZED:
+ index = 0;
+ break;
+ case QMI_DMS_UIM_PIN_STATUS_ENABLED_NOT_VERIFIED:
+ index = 3;
+ break;
+ case QMI_DMS_UIM_PIN_STATUS_ENABLED_VERIFIED:
+ case QMI_DMS_UIM_PIN_STATUS_DISABLED:
+ index = 2;
+ break;
+ default:
+ index = 0;
+ }
+
+ switch (index) {
+ case 1:
+ radio_state = RADIO_STATE_SIM_NOT_READY;
+ break;
+ case 2:
+ radio_state = RADIO_STATE_SIM_READY;
+ break;
+ default:
+ radio_state = RADIO_STATE_SIM_LOCKED_OR_ABSENT;
+ }
+
+ memset(card_status, 0, sizeof(RIL_CardStatus_v6));
+
+ if (index == 0)
+ card_status->card_state = RIL_CARDSTATE_ABSENT;
+ else
+ card_status->card_state = RIL_CARDSTATE_PRESENT;
+
+ card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
+
+ card_status->cdma_subscription_app_index = -1;
+ card_status->ims_subscription_app_index = -1;
+
+ memcpy((void *) &card_status->applications[0], (void *) &app_statuses[index], sizeof(RIL_AppStatus));
+
+ card_status->gsm_umts_subscription_app_index = 0;
+ card_status->num_applications = 1;
+
+ RIL_LOGD("%s: Selecting status application %d on %d", __func__,
+ index, count);
+
+ return radio_state;
+}
+
+static void uim_get_pin_status_ready(QmiClientDms *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ RIL_CardStatus_v6 card_status;
+ RIL_RadioState radio_state;
+ guint8 verify_retries_left;
+ guint8 unblock_retries_left;
+ QmiDmsUimPinStatus pin1_status;
+ QmiDmsUimPinStatus pin2_status;
+ QmiMessageDmsUimGetPinStatusOutput *output;
+ GError *error = NULL;
+ int rc;
+
+ output = qmi_client_dms_uim_get_pin_status_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_dms_uim_get_pin_status_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get PIN status: %s", error->message);
+
+ // assume not initialized
+ pin1_status = QMI_DMS_UIM_PIN_STATUS_NOT_INITIALIZED;
+ goto evaluation;
+ }
+
+ RIL_LOGD("PIN status retrieved successfully");
+
+ if (qmi_message_dms_uim_get_pin_status_output_get_pin1_status (
+ output, &pin1_status, &verify_retries_left,
+ &unblock_retries_left, NULL)) {
+ RIL_LOGD("PIN1:\n"
+ "\tStatus: %s\n"
+ "\tVerify: %u\n"
+ "\tUnblock: %u",
+ qmi_dms_uim_pin_status_get_string(pin1_status),
+ verify_retries_left, unblock_retries_left);
+ }
+
+ if (qmi_message_dms_uim_get_pin_status_output_get_pin2_status(
+ output, &pin2_status, &verify_retries_left,
+ &unblock_retries_left, NULL)) {
+ RIL_LOGD("PIN2:\n"
+ "\tStatus: %s\n"
+ "\tVerify: %u\n"
+ "\tUnblock: %u",
+ qmi_dms_uim_pin_status_get_string(pin2_status),
+ verify_retries_left, unblock_retries_left);
+ }
+
+evaluation:
+ radio_state = qmi2ril_pin_status_response(pin1_status, &card_status);
+
+ if (radio_state == 0)
+ goto error;
+
+ ril_radio_state_update(radio_state);
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &card_status, sizeof(card_status));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_dms_uim_get_pin_status_output_unref(output);
+}
+
+int ril_request_get_sim_status(void *data, size_t size, RIL_Token token)
+{
+ 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;
+
+ qmi_client_dms_uim_get_pin_status(ctx->DmsClient, NULL, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)uim_get_pin_status_ready,
+ token);
+
+ return RIL_REQUEST_HANDLED;
+}
+
+int ril_request_query_facility_lock(void *data, size_t size, RIL_Token token)
+{
+ int active;
+ 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;
+
+ RIL_LOGE("%s: TODO: implement me!", __func__);
+ // let's assume it's inactive
+ // corresponding libqmi call fails with my SIM card, so I
+ // can't test it anyway
+ active = 0;
+ ril_request_complete(token, RIL_E_SUCCESS, &active, sizeof(active));
+
+ rc = RIL_REQUEST_COMPLETED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ return rc;
+}
+
+static void read_transparent_ready(QmiClientUim *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageUimReadTransparentOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ GArray *read_result = NULL;
+ gchar *str = NULL;
+ RIL_SIM_IO_Response response;
+
+ response.simResponse = NULL;
+
+ output = qmi_client_uim_read_transparent_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_uim_read_transparent_output_get_result(
+ output, &error)) {
+ RIL_LOGE("error: couldn't read transparent file from the UIM: %s",
+ error->message);
+ goto card_result;
+ }
+
+ RIL_LOGD("successfully read information from the UIM");
+
+ /* Read result */
+ if (qmi_message_uim_read_transparent_output_get_read_result(
+ output, &read_result, NULL)) {
+ str = array2string(read_result);
+ RIL_LOGD("Read result:\n"
+ "%s", str);
+
+ response.simResponse = str;
+ }
+
+card_result:
+ if (qmi_message_uim_read_transparent_output_get_card_result(
+ output, &sw1, &sw2,
+ NULL)) {
+ RIL_LOGD("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'", sw1, sw2);
+ response.sw1 = sw1;
+ response.sw2 = sw2;
+ } else
+ goto error;
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &response, sizeof(response));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (str)
+ g_free(str);
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_uim_read_transparent_output_unref(output);
+}
+
+static void read_record_ready(QmiClientUim *client, GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageUimReadRecordOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ GArray *read_result = NULL;
+ gchar *str = NULL;
+ RIL_SIM_IO_Response response;
+
+ response.simResponse = NULL;
+
+ output = qmi_client_uim_read_record_finish(client, res,
+ &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_uim_read_record_output_get_result(
+ output, &error)) {
+ RIL_LOGE("error: couldn't read record file from the UIM: %s",
+ error->message);
+
+ goto card_result;
+ }
+
+ RIL_LOGD("successfully read information from the UIM");
+
+ /* Read result */
+ if (qmi_message_uim_read_record_output_get_read_result(
+ output, &read_result, NULL)) {
+ str = array2string(read_result);
+ RIL_LOGD("Read result:\n"
+ "%s", str);
+
+ response.simResponse = str;
+ }
+
+card_result:
+ if (qmi_message_uim_read_record_output_get_card_result(
+ output, &sw1, &sw2, NULL)) {
+ RIL_LOGD("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'", sw1, sw2);
+ response.sw1 = sw1;
+ response.sw2 = sw2;
+ } else
+ goto error;
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &response, sizeof(response));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (str)
+ g_free(str);
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_uim_read_record_output_unref(output);
+}
+
+static void get_file_attributes_ready(QmiClientUim *client,
+ GAsyncResult *res,
+ RIL_Token token)
+{
+ QmiMessageUimGetFileAttributesOutput *output;
+ GError *error = NULL;
+ guint8 sw1 = 0;
+ guint8 sw2 = 0;
+ guint16 file_size, file_id;
+ QmiUimFileType file_type;
+ guint16 record_size;
+ guint16 record_count;
+ struct sim_file_response sim_file_response;
+ RIL_SIM_IO_Response response;
+
+ memset(&sim_file_response, 0, sizeof(sim_file_response));
+ response.simResponse = NULL;
+
+ output = qmi_client_uim_get_file_attributes_finish(client, res, &error);
+ if (!output) {
+ RIL_LOGE("%s: error: operation failed: %s\n", __func__,
+ error->message);
+ goto error;
+ }
+
+ if (!qmi_message_uim_get_file_attributes_output_get_result(output, &error)) {
+ RIL_LOGE("error: couldn't get file attributes from the UIM: %s",
+ error->message);
+
+ goto card_result;
+ }
+
+ RIL_LOGD("Successfully got file attributes from the UIM");
+
+ if (qmi_message_uim_get_file_attributes_output_get_file_attributes(
+ output,
+ &file_size, &file_id, &file_type, &record_size,
+ &record_count, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL)) {
+
+ RIL_LOGD("File attributes:\n"
+ "\tFile size: %u\n"
+ "\tFile ID: %u\n"
+ "\tFile type: %s\n"
+ "\tRecord size: %u\n"
+ "\tRecord count: %u", (guint)file_size,
+ (guint)file_id, qmi_uim_file_type_get_string(file_type),
+ (guint)record_size, (guint)record_count);
+
+ sim_file_response.file_size = file_size;
+ sim_file_response.file_id = file_id;
+ 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 (file_type) {
+ case QMI_UIM_FILE_TYPE_TRANSPARENT:
+ sim_file_response.file_type = SIM_FILE_TYPE_EF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_TRANSPARENT;
+ break;
+ case QMI_UIM_FILE_TYPE_DEDICATED_FILE:
+ sim_file_response.file_type = SIM_FILE_TYPE_DF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED;
+ break;
+ case QMI_UIM_FILE_TYPE_MASTER_FILE:
+ sim_file_response.file_type = SIM_FILE_TYPE_MF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED;
+ break;
+ case QMI_UIM_FILE_TYPE_LINEAR_FIXED:
+ default:
+ sim_file_response.file_type = SIM_FILE_TYPE_EF;
+ sim_file_response.file_structure = SIM_FILE_STRUCTURE_LINEAR_FIXED;
+ }
+
+ sim_file_response.record_length = record_size;
+ response.simResponse = data2string((void *) &sim_file_response, sizeof(sim_file_response));
+ }
+
+card_result:
+ if (qmi_message_uim_get_file_attributes_output_get_card_result(
+ output, &sw1, &sw2, NULL)) {
+ RIL_LOGD("Card result:\n"
+ "\tSW1: '0x%02x'\n"
+ "\tSW2: '0x%02x'", sw1, sw2);
+ response.sw1 = sw1;
+ response.sw2 = sw2;
+ } else {
+ // assume file wasn't found
+ response.sw1 = 0x6a;
+ response.sw2 = 0x82;
+ }
+
+ ril_request_complete(token, RIL_E_SUCCESS, (void *) &response, sizeof(response));
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+complete:
+ if (response.simResponse != NULL)
+ free(response.simResponse);
+ if (error)
+ g_error_free(error);
+ if (output)
+ qmi_message_uim_get_file_attributes_output_unref(output);
+}
+
+int ril2qmi_sim_file_path(const gchar *file_path_str, GArray **file_path)
+{
+ guint str_len;
+ guint array_elements;
+ gchar str_item[4];
+ gulong path_item;
+ guint8 val;
+ guint i;
+
+ str_len = strlen(file_path_str);
+
+ if (str_len == 0) {
+ // assume it's 3F00 (root file)
+ file_path_str = "3F00";
+ str_len = 4;
+ } else if (str_len < 4 || str_len % 2 != 0) {
+ RIL_LOGE("file path error: len %d string %s", str_len,
+ file_path_str);
+ return -1;
+ }
+
+ array_elements = strlen(file_path_str) / 4;
+
+ *file_path = g_array_sized_new(FALSE, FALSE, sizeof (guint8),
+ array_elements);
+
+ for (i = 0; i < array_elements; i++) {
+ strncpy(str_item, &file_path_str[i*4], 4);
+ path_item = (strtoul(str_item, NULL, 16)) & 0xFFFF;
+
+ val = path_item & 0xFF;
+ g_array_append_val(*file_path, val);
+ val = (path_item >> 8) & 0xFF;
+ g_array_append_val(*file_path, val);
+ }
+
+ return 0;
+}
+
+int ril2qmi_get_attributes(RIL_SIM_IO_v6 *sim_io, RIL_Token token)
+{
+ QmiMessageUimGetFileAttributesInput *input;
+ GArray *file_path = NULL;
+ int rc;
+
+ rc = ril2qmi_sim_file_path(sim_io->path, &file_path);
+ if (rc < 0) {
+ RIL_LOGE("%s: error extracting file path", __func__);
+ return -1;
+ }
+
+ input = qmi_message_uim_get_file_attributes_input_new();
+ qmi_message_uim_get_file_attributes_input_set_session_information(
+ input, QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "", NULL);
+ qmi_message_uim_get_file_attributes_input_set_file(
+ input, sim_io->fileid, file_path, NULL);
+
+ qmi_client_uim_get_file_attributes(ctx->UimClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)get_file_attributes_ready,
+ token);
+
+ qmi_message_uim_get_file_attributes_input_unref(input);
+ g_array_unref(file_path);
+
+ return 0;
+}
+
+int ril2qmi_read_record(RIL_SIM_IO_v6 *sim_io, RIL_Token token)
+{
+ QmiMessageUimReadRecordInput *input;
+ GArray *file_path = NULL;
+ int rc;
+
+ rc = ril2qmi_sim_file_path(sim_io->path, &file_path);
+ if (rc < 0) {
+ RIL_LOGE("%s: error extracting file path", __func__);
+ return -1;
+ }
+
+ input = qmi_message_uim_read_record_input_new();
+ qmi_message_uim_read_record_input_set_session_information(
+ input, QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "", NULL);
+ qmi_message_uim_read_record_input_set_file(
+ input, sim_io->fileid, file_path, NULL);
+ qmi_message_uim_read_record_input_set_record(
+ input,sim_io->p1, sim_io->p3, NULL);
+ g_array_unref(file_path);
+
+ qmi_client_uim_read_record(ctx->UimClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)read_record_ready,
+ token);
+
+ qmi_message_uim_read_record_input_unref(input);
+ return 0;
+}
+
+int ril2qmi_read_transparent(RIL_SIM_IO_v6 *sim_io, RIL_Token token)
+{
+ QmiMessageUimReadTransparentInput *input;
+ GArray *file_path = NULL;
+ int rc;
+
+ rc = ril2qmi_sim_file_path(sim_io->path, &file_path);
+ if (rc < 0) {
+ RIL_LOGE("%s: error extracting file path", __func__);
+ return -1;
+ }
+
+ input = qmi_message_uim_read_transparent_input_new();
+ qmi_message_uim_read_transparent_input_set_session_information(
+ input, QMI_UIM_SESSION_TYPE_PRIMARY_GW_PROVISIONING,
+ "", NULL);
+ qmi_message_uim_read_transparent_input_set_file(input,
+ sim_io->fileid,
+ file_path, NULL);
+ qmi_message_uim_read_transparent_input_set_read_information(
+ input,
+ // p1 is offset high, p2 is offset low, which one is it?
+ sim_io->p1,
+ sim_io->p3, NULL);
+ g_array_unref (file_path);
+
+ qmi_client_uim_read_transparent(ctx->UimClient, input, 10,
+ ctx->cancellable,
+ (GAsyncReadyCallback)read_transparent_ready,
+ token);
+
+ qmi_message_uim_read_transparent_input_unref(input);
+ return 0;
+}
+
+int ril_request_sim_io(void *data, size_t size, RIL_Token token)
+{
+ struct ril_request *request;
+ RIL_SIM_IO_v6 *sim_io = NULL;
+ int rc;
+
+ if (data == NULL || size < sizeof(RIL_SIM_IO_v6))
+ goto error;
+
+ rc = ril_radio_state_check(RADIO_STATE_SIM_READY);
+ if (rc < 0) {
+ rc = ril_radio_state_check(RADIO_STATE_SIM_LOCKED_OR_ABSENT);
+ if (rc < 0)
+ return RIL_REQUEST_UNHANDLED;
+ else
+ RIL_LOGE("%s: SIM is locked or absent.", __func__);
+ }
+
+ request = ril_request_find_request_status(RIL_REQUEST_SIM_IO, RIL_REQUEST_HANDLED);
+ if (request != NULL)
+ return RIL_REQUEST_UNHANDLED;
+
+ sim_io = (RIL_SIM_IO_v6 *) data;
+
+ if (sim_io->data != NULL) {
+ RIL_LOGE("TODO: implement processing for data %s",
+ sim_io->data);
+ }
+
+ if (sim_io->pin2 != NULL) {
+ RIL_LOGE("TODO: implement PIN2 unlock first for PIN %s",
+ sim_io->pin2);
+ }
+
+ switch (sim_io->command) {
+ case SIM_COMMAND_GET_RESPONSE:
+ RIL_LOGD("get response command");
+ rc = ril2qmi_get_attributes(sim_io, token);
+ if (rc < 0)
+ goto error;
+ break;
+ case SIM_COMMAND_READ_BINARY:
+ RIL_LOGD("read binary command");
+ rc = ril2qmi_read_transparent(sim_io, token);
+ if (rc < 0)
+ goto error;
+
+ break;
+ case SIM_COMMAND_READ_RECORD:
+ RIL_LOGD("read record command");
+ rc = ril2qmi_read_record(sim_io, token);
+ if (rc < 0)
+ goto error;
+
+ break;
+ case SIM_COMMAND_UPDATE_BINARY:
+ case SIM_COMMAND_UPDATE_RECORD:
+ case SIM_COMMAND_SEEK:
+ default:
+ RIL_LOGD("%s: command %d not supported", __func__,
+ sim_io->command);
+ goto error;
+ }
+
+ rc = RIL_REQUEST_HANDLED;
+ goto complete;
+
+error:
+ ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0);
+
+ rc = RIL_REQUEST_COMPLETED;
+
+complete:
+ 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 (sim_io->aidPtr != NULL)
+ free(sim_io->aidPtr);
+ }
+
+ return rc;
+}