summaryrefslogtreecommitdiffstats
path: root/sim.c
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-09-06 00:19:36 +0200
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2017-09-06 00:19:36 +0200
commitf35a9bbd1ebb52433f313c675fbe01bb1ca96d7d (patch)
treec1aff224fd4a2ea2e5e06805c7caff5406b0ab42 /sim.c
parent06cf4fe68ad096961b4b9c653ba2bc31d270f009 (diff)
downloadqmi-ril-f35a9bbd1ebb52433f313c675fbe01bb1ca96d7d.tar.gz
qmi-ril-f35a9bbd1ebb52433f313c675fbe01bb1ca96d7d.tar.bz2
qmi-ril-f35a9bbd1ebb52433f313c675fbe01bb1ca96d7d.zip
initial version of QMI-RILHEADmaster
The RIL uses libqmi. qmicli and ModemManager were used as references for using libqmi. The request processing is modelled after Samsung-RIL and a lot of code could be reused for QMI-RIL. Establishing a data connection succeeds and mobile data is working in early testing. However, there is not yet a routine for handling interruptions and notifying Android about them. Information about the serving network including signal strength are retrieved and an unlocked SIM card is recognized. Reading data from the SIM and requesting the usual device information should work as well. Support for voice calls and SMS is completely missing at this point. Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
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;
+}