diff --git a/docs/ENVVARS.md b/docs/ENVVARS.md index 5a5a5fa..e99e804 100644 --- a/docs/ENVVARS.md +++ b/docs/ENVVARS.md @@ -6,6 +6,7 @@ - `at`: use AT commands interface used by LTE module - `pcsc`: use PC/SC Smart Card API - `stdio`: use standard input/output + - `qmi`: use QMI - `qmi_qrtr`: use QMI over QRTR - GBinder-based backends for `libhybris` (Halium) distributions: - `gbinder_hidl`: use HIDL IRadio (SoC launched before Android 13) @@ -13,7 +14,8 @@ - `curl`: use libcurl - `stdio`: use standard input/ouput * `AT_DEVICE`: specify which serial port device will be used by AT APDU backend. -* `UIM_SLOT`: specify which UIM slot will be used by QMI QRTR APDU backend. (default: 1) +* `QMI_DEVICE`: specify which QMI device will be used by QMI APDU backend. +* `UIM_SLOT`: specify which UIM slot will be used by QMI APDU backends. (default: 1) * `DRIVER_IFID`: specify which PC/SC interface will be used by PC/SC APDU backend. ## Debug diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt index 4745291..4b72258 100644 --- a/driver/CMakeLists.txt +++ b/driver/CMakeLists.txt @@ -4,6 +4,7 @@ cmake_dependent_option(LPAC_DYNAMIC_DRIVERS "Build lpac/libeuicc driver backends option(LPAC_WITH_APDU_PCSC "Build APDU PCSC Backend (requires PCSC libraries)" ON) option(LPAC_WITH_APDU_AT "Build APDU AT Backend" ON) option(LPAC_WITH_APDU_GBINDER "Build APDU Gbinder backend for libhybris devices (requires gbinder headers)" OFF) +option(LPAC_WITH_APDU_QMI "Build QMI backend for Qualcomm devices (requires libqmi)" OFF) option(LPAC_WITH_APDU_QMI_QRTR "Build QMI-over-QRTR backend for Qualcomm devices (requires libqrtr and libqmi headers)" OFF) option(LPAC_WITH_HTTP_CURL "Build HTTP Curl interface" ON) @@ -59,9 +60,26 @@ if(LPAC_WITH_APDU_GBINDER) endif() endif() +if(LPAC_WITH_APDU_QMI) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLPAC_WITH_APDU_QMI") + target_sources(euicc-drivers PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi.c + ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_helpers.c + ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_common.c) + find_package(PkgConfig REQUIRED) + pkg_check_modules(QMI_GLIB REQUIRED IMPORTED_TARGET qmi-glib) + target_link_libraries(euicc-drivers PkgConfig::QMI_GLIB) + if(LPAC_DYNAMIC_DRIVERS) + list(APPEND LIBEUICC_DRIVERS_REQUIRES "qmi-glib") + endif() +endif() + if(LPAC_WITH_APDU_QMI_QRTR) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLPAC_WITH_APDU_QMI_QRTR") - target_sources(euicc-drivers PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_qrtr.c ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_qrtr_helpers.c) + target_sources(euicc-drivers PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_qrtr.c + ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_helpers.c + ${CMAKE_CURRENT_SOURCE_DIR}/apdu/qmi_common.c) find_package(PkgConfig REQUIRED) pkg_check_modules(QRTR_GLIB REQUIRED IMPORTED_TARGET qrtr-glib) pkg_check_modules(QMI_GLIB REQUIRED IMPORTED_TARGET qmi-glib) diff --git a/driver/apdu/at.c b/driver/apdu/at.c index d2c9cb7..1f0de0d 100644 --- a/driver/apdu/at.c +++ b/driver/apdu/at.c @@ -218,7 +218,7 @@ static int libapduinterface_main(int argc, char **argv) return 0; } -static void libapduinterface_fini(void) +static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { } @@ -227,5 +227,5 @@ const struct euicc_driver driver_apdu_at = { .name = "at", .init = (int (*)(void *))libapduinterface_init, .main = libapduinterface_main, - .fini = libapduinterface_fini, + .fini = (void (*)(void *))libapduinterface_fini, }; diff --git a/driver/apdu/gbinder_hidl.c b/driver/apdu/gbinder_hidl.c index 27cd6e5..6c0bde5 100644 --- a/driver/apdu/gbinder_hidl.c +++ b/driver/apdu/gbinder_hidl.c @@ -314,7 +314,7 @@ static int libapduinterface_main(int argc, char **argv) return 0; } -static void libapduinterface_fini(void) +static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { } diff --git a/driver/apdu/pcsc.c b/driver/apdu/pcsc.c index ee7feed..7fae2c1 100644 --- a/driver/apdu/pcsc.c +++ b/driver/apdu/pcsc.c @@ -453,7 +453,7 @@ static int libapduinterface_main(int argc, char **argv) return 0; } -static void libapduinterface_fini(void) +static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { } @@ -462,5 +462,5 @@ const struct euicc_driver driver_apdu_pcsc = { .name = "pcsc", .init = (int (*)(void *))libapduinterface_init, .main = libapduinterface_main, - .fini = libapduinterface_fini, + .fini = (void (*)(void *))libapduinterface_fini, }; diff --git a/driver/apdu/qmi.c b/driver/apdu/qmi.c new file mode 100644 index 0000000..43dff80 --- /dev/null +++ b/driver/apdu/qmi.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2024, Robert Marko + */ +#include "qmi.h" + +#include +#include "qmi_common.h" + +static int apdu_interface_connect(struct euicc_ctx *ctx) +{ + struct qmi_data *qmi_priv = ctx->apdu.interface->userdata; + g_autoptr(GError) error = NULL; + QmiDevice *device = NULL; + QmiClient *client = NULL; + const char *device_path; + GFile *file; + + if (!(device_path = getenv("QMI_DEVICE"))) { + fprintf(stderr, "No QMI device path specified!\n"); + return -1; + } + file = g_file_new_for_path(device_path); + + qmi_priv->context = g_main_context_new(); + + device = qmi_device_new_from_path(file, qmi_priv->context, &error); + if (!device) { + fprintf(stderr, "error: create QMI device from path failed: %s\n", error->message); + return -1; + } + + qmi_device_open_sync(device, qmi_priv->context, &error); + if (error) { + fprintf(stderr, "error: open QMI device failed: %s\n", error->message); + return -1; + } + + client = qmi_device_allocate_client_sync(device, qmi_priv->context, &error); + if (!client) { + fprintf(stderr, "error: allocate QMI client failed: %s\n", error->message); + return -1; + } + + qmi_priv->uimClient = QMI_CLIENT_UIM(client); + + return 0; +} + +static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) +{ + struct qmi_data *qmi_priv; + + qmi_priv = malloc(sizeof(struct qmi_data)); + if(!qmi_priv) { + fprintf(stderr, "Failed allocating memory\n"); + return -1; + } + + memset(ifstruct, 0, sizeof(struct euicc_apdu_interface)); + ifstruct->connect = apdu_interface_connect; + ifstruct->disconnect = qmi_apdu_interface_disconnect; + ifstruct->logic_channel_open = qmi_apdu_interface_logic_channel_open; + ifstruct->logic_channel_close = qmi_apdu_interface_logic_channel_close; + ifstruct->transmit = qmi_apdu_interface_transmit; + + /* + * Allow the user to select the SIM card slot via environment variable. + * Use the primary SIM slot if not set. + */ + if (getenv("UIM_SLOT")) + qmi_priv->uimSlot = atoi(getenv("UIM_SLOT")); + else + qmi_priv->uimSlot = 1; + + ifstruct->userdata = qmi_priv; + + return 0; +} + +static int libapduinterface_main(int argc, char **argv) +{ + return 0; +} + +static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) +{ + struct qmi_data *qmi_priv = ifstruct->userdata; + + qmi_cleanup(qmi_priv); + + free(qmi_priv); +} + +const struct euicc_driver driver_apdu_qmi = { + .type = DRIVER_APDU, + .name = "qmi", + .init = (int (*)(void *))libapduinterface_init, + .main = libapduinterface_main, + .fini = (void (*)(void *))libapduinterface_fini, +}; diff --git a/driver/apdu/qmi.h b/driver/apdu/qmi.h new file mode 100644 index 0000000..7c007f7 --- /dev/null +++ b/driver/apdu/qmi.h @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2024, Robert Marko + */ +#pragma once +#include + +extern const struct euicc_driver driver_apdu_qmi; diff --git a/driver/apdu/qmi_common.c b/driver/apdu/qmi_common.c new file mode 100644 index 0000000..6f73646 --- /dev/null +++ b/driver/apdu/qmi_common.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2024, Luca Weiss + */ + +#include + +#include "qmi_common.h" + +int qmi_apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len) +{ + struct qmi_data *qmi_priv = ctx->apdu.interface->userdata; + g_autoptr(GError) error = NULL; + g_autoptr(GArray) apdu_data = NULL; + + /* Convert tx into request GArray */ + apdu_data = g_array_new(FALSE, FALSE, sizeof(guint8)); + for (uint32_t i = 0; i < tx_len; i++) + g_array_append_val(apdu_data, tx[i]); + + QmiMessageUimSendApduInput *input; + input = qmi_message_uim_send_apdu_input_new(); + qmi_message_uim_send_apdu_input_set_slot(input, qmi_priv->uimSlot, NULL); + qmi_message_uim_send_apdu_input_set_channel_id(input, qmi_priv->lastChannelId, NULL); + qmi_message_uim_send_apdu_input_set_apdu(input, apdu_data, NULL); + + QmiMessageUimSendApduOutput *output; + output = qmi_client_uim_send_apdu_sync(qmi_priv->uimClient, input, qmi_priv->context, &error); + + qmi_message_uim_send_apdu_input_unref(input); + + if (!qmi_message_uim_send_apdu_output_get_result(output, &error)) + { + fprintf(stderr, "error: send apdu operation failed: %s\n", error->message); + return -1; + } + + GArray *apdu_res = NULL; + if (!qmi_message_uim_send_apdu_output_get_apdu_response(output, &apdu_res, &error)) + { + fprintf(stderr, "error: get apdu response operation failed: %s\n", error->message); + return -1; + } + + /* Convert response GArray into rx */ + *rx_len = apdu_res->len; + *rx = malloc(*rx_len); + if (!*rx) + return -1; + for (guint i = 0; i < apdu_res->len; i++) + (*rx)[i] = apdu_res->data[i]; + + qmi_message_uim_send_apdu_output_unref(output); + + return 0; +} + +int qmi_apdu_interface_logic_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, uint8_t aid_len) +{ + struct qmi_data *qmi_priv = ctx->apdu.interface->userdata; + g_autoptr(GError) error = NULL; + guint8 channel_id; + + GArray *aid_data = g_array_new(FALSE, FALSE, sizeof(guint8)); + for (int i = 0; i < aid_len; i++) + g_array_append_val(aid_data, aid[i]); + + QmiMessageUimOpenLogicalChannelInput *input; + input = qmi_message_uim_open_logical_channel_input_new(); + qmi_message_uim_open_logical_channel_input_set_slot(input, qmi_priv->uimSlot, NULL); + qmi_message_uim_open_logical_channel_input_set_aid(input, aid_data, NULL); + + QmiMessageUimOpenLogicalChannelOutput *output; + output = qmi_client_uim_open_logical_channel_sync(qmi_priv->uimClient, input, qmi_priv->context, &error); + + qmi_message_uim_open_logical_channel_input_unref(input); + g_array_unref(aid_data); + + if (!output) + { + fprintf(stderr, "error: send Open Logical Channel command failed: %s\n", error->message); + return -1; + } + + if (!qmi_message_uim_open_logical_channel_output_get_result(output, &error)) + { + fprintf(stderr, "error: open logical channel operation failed: %s\n", error->message); + return -1; + } + + if (!qmi_message_uim_open_logical_channel_output_get_channel_id(output, &channel_id, &error)) + { + fprintf(stderr, "error: get channel id operation failed: %s\n", error->message); + return -1; + } + qmi_priv->lastChannelId = channel_id; + + g_debug("Opened logical channel with id %d", channel_id); + + qmi_message_uim_open_logical_channel_output_unref(output); + + return channel_id; +} + +void qmi_apdu_interface_logic_channel_close(struct euicc_ctx *ctx, uint8_t channel) +{ + struct qmi_data *qmi_priv = ctx->apdu.interface->userdata; + g_autoptr(GError) error = NULL; + + QmiMessageUimLogicalChannelInput *input; + input = qmi_message_uim_logical_channel_input_new(); + qmi_message_uim_logical_channel_input_set_slot(input, qmi_priv->uimSlot, NULL); + qmi_message_uim_logical_channel_input_set_channel_id(input, channel, NULL); + + QmiMessageUimLogicalChannelOutput *output; + output = qmi_client_uim_logical_channel_sync(qmi_priv->uimClient, input, qmi_priv->context, &error); + + qmi_message_uim_logical_channel_input_unref(input); + + if (error) + { + fprintf(stderr, "error: send Close Logical Channel command failed: %s\n", error->message); + return; + } + + if (!qmi_message_uim_logical_channel_output_get_result(output, &error)) + { + fprintf(stderr, "error: logical channel operation failed: %s\n", error->message); + return; + } + + /* Mark channel as having been cleaned up */ + if (channel == qmi_priv->lastChannelId) + qmi_priv->lastChannelId = -1; + + g_debug("Closed logical channel with id %d", channel); + + qmi_message_uim_logical_channel_output_unref(output); +} + +void qmi_apdu_interface_disconnect(struct euicc_ctx *ctx) +{ + struct qmi_data *qmi_priv = ctx->apdu.interface->userdata; + g_autoptr(GError) error = NULL; + QmiClient *client = QMI_CLIENT(qmi_priv->uimClient); + QmiDevice *device = QMI_DEVICE(qmi_client_get_device(client)); + + qmi_device_release_client_sync(device, client, qmi_priv->context, &error); + qmi_priv->uimClient = NULL; + + g_main_context_unref(qmi_priv->context); + qmi_priv->context = NULL; +} + +void qmi_cleanup(struct qmi_data *qmi_priv) +{ + if (qmi_priv->lastChannelId != -1) + { + fprintf(stderr, "Cleaning up leaked APDU channel %d\n", qmi_priv->lastChannelId); + qmi_apdu_interface_logic_channel_close(NULL, qmi_priv->lastChannelId); + qmi_priv->lastChannelId = -1; + } +} diff --git a/driver/apdu/qmi_common.h b/driver/apdu/qmi_common.h new file mode 100644 index 0000000..2ddb692 --- /dev/null +++ b/driver/apdu/qmi_common.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2024, Luca Weiss + */ + +#include +#include +#include "qmi_helpers.h" + +struct qmi_data { + int lastChannelId; + int uimSlot; + GMainContext *context; + QmiClientUim *uimClient; +}; + +int qmi_apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len); +int qmi_apdu_interface_logic_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, uint8_t aid_len); +void qmi_apdu_interface_logic_channel_close(struct euicc_ctx *ctx, uint8_t channel); +void qmi_apdu_interface_disconnect(struct euicc_ctx *ctx); +void qmi_cleanup(struct qmi_data *qmi_priv); diff --git a/driver/apdu/qmi_qrtr_helpers.c b/driver/apdu/qmi_helpers.c similarity index 88% rename from driver/apdu/qmi_qrtr_helpers.c rename to driver/apdu/qmi_helpers.c index c18504b..bc3e2d0 100644 --- a/driver/apdu/qmi_qrtr_helpers.c +++ b/driver/apdu/qmi_helpers.c @@ -3,7 +3,7 @@ * Copyright (c) 2024, Luca Weiss */ -#include "qmi_qrtr_helpers.h" +#include "qmi_helpers.h" static void async_result_ready(GObject *source_object, @@ -16,6 +16,7 @@ async_result_ready(GObject *source_object, *result_out = g_object_ref(res); } +#ifdef LPAC_WITH_APDU_QMI_QRTR QrtrBus * qrtr_bus_new_sync(GMainContext *context, GError **error) @@ -56,6 +57,33 @@ qmi_device_new_from_node_sync(QrtrNode *node, return qmi_device_new_from_node_finish(result, error); } +#endif + +#ifdef LPAC_WITH_APDU_QMI +QmiDevice * +qmi_device_new_from_path(GFile *file, + GMainContext *context, + GError **error) +{ + g_autoptr(GMainContextPusher) pusher = NULL; + g_autoptr(GAsyncResult) result = NULL; + g_autofree gchar *id = NULL; + + pusher = g_main_context_pusher_new(context); + + id = g_file_get_path (file); + if (id) + qmi_device_new(file, + NULL, + async_result_ready, + &result); + + while (result == NULL) + g_main_context_iteration(context, TRUE); + + return qmi_device_new_finish(result, error); +} +#endif gboolean qmi_device_open_sync(QmiDevice *device, @@ -68,7 +96,7 @@ qmi_device_open_sync(QmiDevice *device, pusher = g_main_context_pusher_new(context); qmi_device_open(device, - QMI_DEVICE_OPEN_FLAGS_NONE, + QMI_DEVICE_OPEN_FLAGS_PROXY, 15, NULL, async_result_ready, diff --git a/driver/apdu/qmi_qrtr_helpers.h b/driver/apdu/qmi_helpers.h similarity index 87% rename from driver/apdu/qmi_qrtr_helpers.h rename to driver/apdu/qmi_helpers.h index 5a910f5..0184b88 100644 --- a/driver/apdu/qmi_qrtr_helpers.h +++ b/driver/apdu/qmi_helpers.h @@ -3,9 +3,11 @@ * Copyright (c) 2024, Luca Weiss */ -#include #include +#ifdef LPAC_WITH_APDU_QMI_QRTR +#include + QrtrBus *qrtr_bus_new_sync( GMainContext *context, GError **error); @@ -15,6 +17,15 @@ qmi_device_new_from_node_sync( QrtrNode *node, GMainContext *context, GError **error); +#endif + +#ifdef LPAC_WITH_APDU_QMI +QmiDevice * +qmi_device_new_from_path( + GFile *file, + GMainContext *context, + GError **error); +#endif gboolean qmi_device_open_sync( diff --git a/driver/apdu/qmi_qrtr.c b/driver/apdu/qmi_qrtr.c index 0925245..cb395c9 100644 --- a/driver/apdu/qmi_qrtr.c +++ b/driver/apdu/qmi_qrtr.c @@ -11,25 +11,22 @@ #include #include #include -#include "qmi_qrtr_helpers.h" +#include "qmi_common.h" -static int lastChannelId = -1; -static int uimSlot = -1; -static GMainContext *context = NULL; static QrtrBus *bus = NULL; -static QmiClientUim *uimClient = NULL; static int apdu_interface_connect(struct euicc_ctx *ctx) { + struct qmi_data *qmi_priv = ctx->apdu.interface->userdata; g_autoptr(GError) error = NULL; QrtrNode *node = NULL; QmiDevice *device = NULL; QmiClient *client = NULL; bool found = false; - context = g_main_context_new(); + qmi_priv->context = g_main_context_new(); - bus = qrtr_bus_new_sync(context, &error); + bus = qrtr_bus_new_sync(qmi_priv->context, &error); if (bus == NULL) { fprintf(stderr, "error: connect to QRTR bus failed: %s\n", error->message); @@ -54,202 +51,49 @@ static int apdu_interface_connect(struct euicc_ctx *ctx) return -1; } - device = qmi_device_new_from_node_sync(node, context, &error); + device = qmi_device_new_from_node_sync(node, qmi_priv->context, &error); if (!device) { fprintf(stderr, "error: create QMI device from QRTR node failed: %s\n", error->message); return -1; } - qmi_device_open_sync(device, context, &error); + qmi_device_open_sync(device, qmi_priv->context, &error); if (error) { fprintf(stderr, "error: open QMI device failed: %s\n", error->message); return -1; } - client = qmi_device_allocate_client_sync(device, context, &error); + client = qmi_device_allocate_client_sync(device, qmi_priv->context, &error); if (!client) { fprintf(stderr, "error: allocate QMI client failed: %s\n", error->message); return -1; } - uimClient = QMI_CLIENT_UIM(client); + qmi_priv->uimClient = QMI_CLIENT_UIM(client); return 0; } -static void apdu_interface_disconnect(struct euicc_ctx *ctx) -{ - g_autoptr(GError) error = NULL; - QmiClient *client = QMI_CLIENT(uimClient); - QmiDevice *device = QMI_DEVICE(qmi_client_get_device(client)); - - qmi_device_release_client_sync(device, client, context, &error); - uimClient = NULL; - - g_main_context_unref(context); - context = NULL; -} - -static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len) -{ - g_autoptr(GError) error = NULL; - g_autoptr(GArray) apdu_data = NULL; - - /* Convert tx into request GArray */ - apdu_data = g_array_new(FALSE, FALSE, sizeof(guint8)); - for (uint32_t i = 0; i < tx_len; i++) - g_array_append_val(apdu_data, tx[i]); - - QmiMessageUimSendApduInput *input; - input = qmi_message_uim_send_apdu_input_new(); - qmi_message_uim_send_apdu_input_set_slot(input, uimSlot, NULL); - qmi_message_uim_send_apdu_input_set_channel_id(input, lastChannelId, NULL); - qmi_message_uim_send_apdu_input_set_apdu(input, apdu_data, NULL); - - QmiMessageUimSendApduOutput *output; - output = qmi_client_uim_send_apdu_sync(uimClient, input, context, &error); - - qmi_message_uim_send_apdu_input_unref(input); - - if (!qmi_message_uim_send_apdu_output_get_result(output, &error)) - { - fprintf(stderr, "error: send apdu operation failed: %s\n", error->message); - return -1; - } - - GArray *apdu_res = NULL; - if (!qmi_message_uim_send_apdu_output_get_apdu_response(output, &apdu_res, &error)) - { - fprintf(stderr, "error: get apdu response operation failed: %s\n", error->message); - return -1; - } - - /* Convert response GArray into rx */ - *rx_len = apdu_res->len; - *rx = malloc(*rx_len); - if (!*rx) - return -1; - for (guint i = 0; i < apdu_res->len; i++) - (*rx)[i] = apdu_res->data[i]; - - qmi_message_uim_send_apdu_output_unref(output); - - return 0; -} - -static int apdu_interface_logic_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, uint8_t aid_len) -{ - g_autoptr(GError) error = NULL; - guint8 channel_id; - - GArray *aid_data = g_array_new(FALSE, FALSE, sizeof(guint8)); - for (int i = 0; i < aid_len; i++) - g_array_append_val(aid_data, aid[i]); - - QmiMessageUimOpenLogicalChannelInput *input; - input = qmi_message_uim_open_logical_channel_input_new(); - qmi_message_uim_open_logical_channel_input_set_slot(input, uimSlot, NULL); - qmi_message_uim_open_logical_channel_input_set_aid(input, aid_data, NULL); - - QmiMessageUimOpenLogicalChannelOutput *output; - output = qmi_client_uim_open_logical_channel_sync(uimClient, input, context, &error); - - qmi_message_uim_open_logical_channel_input_unref(input); - g_array_unref(aid_data); - - if (!output) - { - fprintf(stderr, "error: send Open Logical Channel command failed: %s\n", error->message); - return -1; - } - - if (!qmi_message_uim_open_logical_channel_output_get_result(output, &error)) - { - fprintf(stderr, "error: open logical channel operation failed: %s\n", error->message); - return -1; - } - - if (!qmi_message_uim_open_logical_channel_output_get_channel_id(output, &channel_id, &error)) - { - fprintf(stderr, "error: get channel id operation failed: %s\n", error->message); - return -1; - } - lastChannelId = channel_id; - - g_debug("Opened logical channel with id %d", channel_id); - - qmi_message_uim_open_logical_channel_output_unref(output); - - return channel_id; -} - -static void apdu_interface_logic_channel_close(struct euicc_ctx *ctx, uint8_t channel) -{ - g_autoptr(GError) error = NULL; - - QmiMessageUimLogicalChannelInput *input; - input = qmi_message_uim_logical_channel_input_new(); - qmi_message_uim_logical_channel_input_set_slot(input, uimSlot, NULL); - qmi_message_uim_logical_channel_input_set_channel_id(input, channel, NULL); - - QmiMessageUimLogicalChannelOutput *output; - output = qmi_client_uim_logical_channel_sync(uimClient, input, context, &error); - - qmi_message_uim_logical_channel_input_unref(input); - - if (error) - { - fprintf(stderr, "error: send Close Logical Channel command failed: %s\n", error->message); - return; - } - - if (!qmi_message_uim_logical_channel_output_get_result(output, &error)) - { - fprintf(stderr, "error: logical channel operation failed: %s\n", error->message); - return; - } - - /* Mark channel as having been cleaned up */ - if (channel == lastChannelId) - lastChannelId = -1; - - g_debug("Closed logical channel with id %d", channel); - - qmi_message_uim_logical_channel_output_unref(output); -} - -static void cleanup(void) -{ - if (lastChannelId != -1) - { - fprintf(stderr, "Cleaning up leaked APDU channel %d\n", lastChannelId); - apdu_interface_logic_channel_close(NULL, lastChannelId); - lastChannelId = -1; - } -} - -static void sighandler(int sig) -{ - // This triggers atexit() hooks and therefore call cleanup() - exit(0); -} - static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) { + struct qmi_data *qmi_priv; + + qmi_priv = malloc(sizeof(struct qmi_data)); + if(!qmi_priv) { + fprintf(stderr, "Failed allocating memory\n"); + return -1; + } + memset(ifstruct, 0, sizeof(struct euicc_apdu_interface)); ifstruct->connect = apdu_interface_connect; - ifstruct->disconnect = apdu_interface_disconnect; - ifstruct->logic_channel_open = apdu_interface_logic_channel_open; - ifstruct->logic_channel_close = apdu_interface_logic_channel_close; - ifstruct->transmit = apdu_interface_transmit; - - // Install cleanup routine - atexit(cleanup); - signal(SIGINT, sighandler); + ifstruct->disconnect = qmi_apdu_interface_disconnect; + ifstruct->logic_channel_open = qmi_apdu_interface_logic_channel_open; + ifstruct->logic_channel_close = qmi_apdu_interface_logic_channel_close; + ifstruct->transmit = qmi_apdu_interface_transmit; /* * Allow the user to select the SIM card slot via environment variable. @@ -257,13 +101,15 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) */ if (getenv("UIM_SLOT")) { - uimSlot = atoi(getenv("UIM_SLOT")); + qmi_priv->uimSlot = atoi(getenv("UIM_SLOT")); } else { - uimSlot = 1; + qmi_priv->uimSlot = 1; } + ifstruct->userdata = qmi_priv; + return 0; } @@ -272,8 +118,13 @@ static int libapduinterface_main(int argc, char **argv) return 0; } -static void libapduinterface_fini(void) +static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { + struct qmi_data *qmi_priv = ifstruct->userdata; + + qmi_cleanup(qmi_priv); + + free(qmi_priv); } const struct euicc_driver driver_apdu_qmi_qrtr = { @@ -281,5 +132,5 @@ const struct euicc_driver driver_apdu_qmi_qrtr = { .name = "qmi_qrtr", .init = (int (*)(void *))libapduinterface_init, .main = libapduinterface_main, - .fini = libapduinterface_fini, + .fini = (void (*)(void *))libapduinterface_fini, }; diff --git a/driver/apdu/stdio.c b/driver/apdu/stdio.c index 9c513aa..dfabc46 100644 --- a/driver/apdu/stdio.c +++ b/driver/apdu/stdio.c @@ -340,7 +340,7 @@ static int libapduinterface_main(int argc, char **argv) return 0; } -static void libapduinterface_fini(void) +static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { } @@ -349,5 +349,5 @@ const struct euicc_driver driver_apdu_stdio = { .name = "stdio", .init = (int (*)(void *))libapduinterface_init, .main = libapduinterface_main, - .fini = libapduinterface_fini, + .fini = (void (*)(void *))libapduinterface_fini, }; diff --git a/driver/driver.c b/driver/driver.c index 1ee8c0c..1fd07cf 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -8,6 +8,10 @@ #include "driver/apdu/gbinder_hidl.h" #endif +#ifdef LPAC_WITH_APDU_QMI +#include "driver/apdu/qmi.h" +#endif + #ifdef LPAC_WITH_APDU_QMI_QRTR #include "driver/apdu/qmi_qrtr.h" #endif @@ -28,6 +32,9 @@ static const struct euicc_driver *drivers[] = { #ifdef LPAC_WITH_APDU_GBINDER &driver_apdu_gbinder_hidl, #endif +#ifdef LPAC_WITH_APDU_QMI + &driver_apdu_qmi, +#endif #ifdef LPAC_WITH_APDU_QMI_QRTR &driver_apdu_qmi_qrtr, #endif @@ -112,10 +119,10 @@ void euicc_driver_fini() { if (_driver_apdu != NULL) { - _driver_apdu->fini(); + _driver_apdu->fini(&euicc_driver_interface_apdu); } if (_driver_http != NULL) { - _driver_http->fini(); + _driver_http->fini(&euicc_driver_interface_http); } } diff --git a/driver/driver.private.h b/driver/driver.private.h index d1686d3..c882789 100644 --- a/driver/driver.private.h +++ b/driver/driver.private.h @@ -12,5 +12,5 @@ struct euicc_driver const char *name; int (*init)(void *interface); int (*main)(int argc, char **argv); - void (*fini)(void); + void (*fini)(void *interface); }; diff --git a/driver/http/curl.c b/driver/http/curl.c index c237485..a243ada 100644 --- a/driver/http/curl.c +++ b/driver/http/curl.c @@ -192,7 +192,7 @@ static int libhttpinterface_main(int argc, char **argv) return 0; } -static void libhttpinterface_fini(void) +static void libhttpinterface_fini(struct euicc_http_interface *ifstruct) { } @@ -201,5 +201,5 @@ const struct euicc_driver driver_http_curl = { .name = "curl", .init = (int (*)(void *))libhttpinterface_init, .main = libhttpinterface_main, - .fini = libhttpinterface_fini, + .fini = (void (*)(void *))libhttpinterface_fini, }; diff --git a/driver/http/stdio.c b/driver/http/stdio.c index f0ca865..c035495 100644 --- a/driver/http/stdio.c +++ b/driver/http/stdio.c @@ -272,7 +272,7 @@ static int libhttpinterface_main(int argc, char **argv) return 0; } -static void libhttpinterface_fini(void) +static void libhttpinterface_fini(struct euicc_http_interface *ifstruct) { } @@ -281,5 +281,5 @@ const struct euicc_driver driver_http_stdio = { .name = "stdio", .init = (int (*)(void *))libhttpinterface_init, .main = libhttpinterface_main, - .fini = libhttpinterface_fini, + .fini = (void (*)(void *))libhttpinterface_fini, };