This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
laforge gerrit-no-reply at lists.osmocom.orglaforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-remsim/+/17160 ) Change subject: client: ifd_handler (PC/SC reader driver) as remsim-client ...................................................................... client: ifd_handler (PC/SC reader driver) as remsim-client This adds a "libifd_remsim_client.so" PC/SC driver that can be used to make normal PC/SC client programs (like pySim, sysmo-usim-tool, osmo-sim-test, osmo-usim-auth, ...) talk to a remote SIM bank. Change-Id: Ib8707c6e0e46407ab39a693adfec2fa71892f6ee --- M src/client/Makefile.am M src/client/client.h A src/client/user_ifdhandler.c 3 files changed, 948 insertions(+), 0 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-remsim refs/changes/60/17160/1 diff --git a/src/client/Makefile.am b/src/client/Makefile.am index ac0d707..5b88c50 100644 --- a/src/client/Makefile.am +++ b/src/client/Makefile.am @@ -6,13 +6,24 @@ bin_PROGRAMS = osmo-remsim-client-st2 osmo-remsim-client-shell +lib_LTLIBRARIES = libifd_remsim_client.la + osmo_remsim_client_shell_SOURCES = user_shell.c remsim_client_main.c \ remsim_client.c ../rspro_client_fsm.c ../debug.c +osmo_remsim_client_shell_CFLAGS = $(AM_CFLAGS) osmo_remsim_client_shell_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \ $(top_builddir)/src/libosmo-rspro.la +libifd_remsim_client_la_SOURCES = user_ifdhandler.c \ + remsim_client.c ../rspro_client_fsm.c ../debug.c +libifd_remsim_client_la_LDFLAGS = -no-undefined +libifd_remsim_client_la_CPPFLAGS = $(PCSC_CFLAGS) +libifd_remsim_client_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \ + $(top_builddir)/src/libosmo-rspro.la + osmo_remsim_client_st2_SOURCES = simtrace2-remsim_client.c \ ../rspro_client_fsm.c ../debug.c +osmo_remsim_client_st2_CFLAGS = $(AM_CFLAGS) osmo_remsim_client_st2_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \ $(OSMOUSB_LIBS) $(OSMOSIMTRACE2_LIBS) \ $(USB_LIBS) $(OSMOSIM_LIBS) \ diff --git a/src/client/client.h b/src/client/client.h index 80381fa..0761255 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -56,6 +56,7 @@ struct client_config *cfg; struct cardem_inst *cardem; + void *data; }; #define srvc2bankd_client(srvc) container_of(srvc, struct bankd_client, srv_conn) diff --git a/src/client/user_ifdhandler.c b/src/client/user_ifdhandler.c new file mode 100644 index 0000000..677b781 --- /dev/null +++ b/src/client/user_ifdhandler.c @@ -0,0 +1,936 @@ +/* (C) 2020 by Harald Welte <laforge at gnumonks.org> + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* This is a remsim-client that provides an IFD_Handler (reader driver) + * towards the PC/SC services. This effectively allows any local PC/SC client + * application to use a remote smartcard via osmo-remsim. + * + * In order to use this, you will need an /etc/reader.conf.d/osmo-remsim-client + * file with the following content: + * + * FRIENDLYNAME "osmo-remsim-client" + * DEVICENAME 0:0:192.168.11.10:9998 + * LIBPATH /usr/lib/pcsc/drivers/serial/libifd_remsim_client.so + * + * Where DEVICENAME has the following format: + * [ClientID:[SlotNr:[ServerIp:[ServerPort]]]] + * + */ + +#include <errno.h> +#include <unistd.h> +#include <pthread.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/application.h> +extern int osmo_ctx_init(const char *id); + +#include "client.h" + +/* ensure this current thread has an osmo_ctx and hence can use OTC_GLOBAL and friends */ +static void ensure_osmo_ctx(void) +{ + if (!osmo_ctx) + osmo_ctx_init(""); +} + +/* inter-thread messages between IFD thread and remsim-client thread */ +enum itmsg_type { + ITMSG_TYPE_NONE, + + /* card present? */ + ITMSG_TYPE_CARD_PRES_REQ, + ITMSG_TYPE_CARD_PRES_RESP, + + /* obtain ATR */ + ITMSG_TYPE_ATR_REQ, + ITMSG_TYPE_ATR_RESP, + + /* transceive APDU: Send C-APDU, receive R-APDU */ + ITMSG_TYPE_C_APDU_REQ, + ITMSG_TYPE_R_APDU_IND, + + /* power off the card */ + ITMSG_TYPE_POWER_OFF_REQ, + ITMSG_TYPE_POWER_OFF_RESP, + + /* power on the card */ + ITMSG_TYPE_POWER_ON_REQ, + ITMSG_TYPE_POWER_ON_RESP, + + /* reset the card */ + ITMSG_TYPE_RESET_REQ, + ITMSG_TYPE_RESET_RESP, +}; + +struct itmsg { + enum itmsg_type type; + uint16_t status; /* 0 == success */ + uint16_t len; /* length of 'data' */ + uint8_t data[0]; +}; + +/* allocate + initialize msgb-wrapped inter-thread message (struct itmsg) */ +struct msgb *itmsg_alloc(enum itmsg_type type, uint16_t status, const uint8_t *data, uint16_t len) +{ + struct msgb *msg = msgb_alloc_c(OTC_GLOBAL, sizeof(struct itmsg)+len, "Tx itmsg"); + struct itmsg *im; + + if (!msg) + return NULL; + + im = (struct itmsg *) msgb_put(msg, sizeof(struct itmsg) + len); + im->type = type; + im->status = status; + im->len = len; + if (len) + memcpy(im->data, data, len); + + return msg; +} + +/*********************************************************************** + * remsim_client thread + ***********************************************************************/ + +void __thread *talloc_asn1_ctx; + +struct client_thread { + /* bankd client runningi inside this thread */ + struct bankd_client *bc; + + /* inter-thread osmo-fd; communication with IFD/PCSC thread */ + struct osmo_fd it_ofd; + struct llist_head it_msgq; + + /* ATR as received from remsim-bankd */ + uint8_t atr[ATR_SIZE_MAX]; + uint8_t atr_len; +}; + +/* configuration of client thread; passed in from IFD thread */ +struct client_thread_cfg { + const char *name; + const char *server_host; + int server_port; + int client_id; + int client_slot; + int it_sock_fd; +}; + +/* enqueue a msgb (containg 'struct itmsg') towards the IFD-handler thread */ +static void enqueue_to_ifd(struct client_thread *ct, struct msgb *msg) +{ + if (!msg) + return; + + msgb_enqueue(&ct->it_msgq, msg); + ct->it_ofd.when |= OSMO_FD_WRITE; +} + +/*********************************************************************** + * Incoming RSPRO messages from bank-daemon (SIM card) + ***********************************************************************/ + +static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu) +{ + const struct TpduCardToModem *card2modem; + struct client_thread *ct = bc->data; + struct msgb *msg; + + OSMO_ASSERT(pdu); + OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present); + + card2modem = &pdu->msg.choice.tpduCardToModem; + DEBUGP(DMAIN, "R-APDU: %s\n", osmo_hexdump(card2modem->data.buf, card2modem->data.size)); + /* enqueue towards IFD thread */ + msg = itmsg_alloc(ITMSG_TYPE_R_APDU_IND, 0, card2modem->data.buf, card2modem->data.size); + OSMO_ASSERT(msg); + enqueue_to_ifd(ct, msg); + + return 0; +} + +static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu) +{ + struct client_thread *ct = bc->data; + RsproPDU_t *resp; + unsigned int atr_len; + + OSMO_ASSERT(pdu); + OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present); + + DEBUGP(DMAIN, "SET_ATR: %s\n", osmo_hexdump(pdu->msg.choice.setAtrReq.atr.buf, + pdu->msg.choice.setAtrReq.atr.size)); + + /* store ATR in local data structure until somebody needs it */ + atr_len = pdu->msg.choice.setAtrReq.atr.size; + if (atr_len > sizeof(ct->atr)) + atr_len = sizeof(ct->atr); + memcpy(ct->atr, pdu->msg.choice.setAtrReq.atr.buf, atr_len); + ct->atr_len = atr_len; + + resp = rspro_gen_SetAtrRes(ResultCode_ok); + if (!resp) + return -ENOMEM; + server_conn_send_rspro(&bc->bankd_conn, resp); + + return 0; +} + + +int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu) +{ + struct bankd_client *bc = bankdc2bankd_client(bankdc); + + switch (pdu->msg.present) { + case RsproPDUchoice_PR_tpduCardToModem: + bankd_handle_tpduCardToModem(bc, pdu); + break; + case RsproPDUchoice_PR_setAtrReq: + bankd_handle_setAtrReq(bc, pdu); + break; + default: + OSMO_ASSERT(0); + } + return 0; +} + +/*********************************************************************** + * Incoming command from the user application + ***********************************************************************/ + +/* handle a single msgb-wrapped 'struct itmsg' from the IFD-handler thread */ +static void handle_it_msg(struct client_thread *ct, struct itmsg *itmsg) +{ + struct bankd_client *bc = ct->bc; + struct msgb *tx = NULL; + RsproPDU_t *pdu; + BankSlot_t bslot; + + bank_slot2rspro(&bslot, &ct->bc->bankd_slot); + + switch (itmsg->type) { + case ITMSG_TYPE_CARD_PRES_REQ: + if (bc->bankd_conn.fi->state == 2 /*SRVC_ST_CONNECTED*/) + tx = itmsg_alloc(ITMSG_TYPE_CARD_PRES_RESP, 0, NULL, 0); + else + tx = itmsg_alloc(ITMSG_TYPE_CARD_PRES_RESP, 0xffff, NULL, 0); + OSMO_ASSERT(tx); + break; + + case ITMSG_TYPE_ATR_REQ: + /* respond to IFD */ + tx = itmsg_alloc(ITMSG_TYPE_ATR_RESP, 0, ct->atr, ct->atr_len); + OSMO_ASSERT(tx); + break; + + case ITMSG_TYPE_POWER_OFF_REQ: + pdu = rspro_gen_ClientSlotStatusInd(bc->srv_conn.clslot, &bslot, + true, false, false, true); + server_conn_send_rspro(&bc->bankd_conn, pdu); + /* respond to IFD */ + tx = itmsg_alloc(ITMSG_TYPE_POWER_OFF_RESP, 0, NULL, 0); + OSMO_ASSERT(tx); + break; + + case ITMSG_TYPE_POWER_ON_REQ: + pdu = rspro_gen_ClientSlotStatusInd(bc->srv_conn.clslot, &bslot, + false, true, true, true); + server_conn_send_rspro(&bc->bankd_conn, pdu); + /* respond to IFD */ + tx = itmsg_alloc(ITMSG_TYPE_POWER_ON_RESP, 0, NULL, 0); + OSMO_ASSERT(tx); + break; + + case ITMSG_TYPE_RESET_REQ: + /* reset the [remote] card */ + pdu = rspro_gen_ClientSlotStatusInd(bc->srv_conn.clslot, &bslot, + true, true, true, true); + server_conn_send_rspro(&bc->bankd_conn, pdu); + /* and take it out of reset again */ + pdu = rspro_gen_ClientSlotStatusInd(bc->srv_conn.clslot, &bslot, + false, true, true, true); + server_conn_send_rspro(&bc->bankd_conn, pdu); + /* respond to IFD */ + tx = itmsg_alloc(ITMSG_TYPE_RESET_RESP, 0, NULL, 0); + OSMO_ASSERT(tx); + break; + case ITMSG_TYPE_C_APDU_REQ: + if (!bc->srv_conn.clslot) { + LOGP(DMAIN, LOGL_ERROR, "Cannot send command; no client slot\n"); + /* FIXME: Response? */ + return; + } + + /* Send CMD APDU to [remote] card */ + pdu = rspro_gen_TpduModem2Card(bc->srv_conn.clslot, &bslot, itmsg->data, itmsg->len); + server_conn_send_rspro(&bc->bankd_conn, pdu); + /* response will come in asynchronously */ + break; + default: + LOGP(DMAIN, LOGL_ERROR, "Unknown inter-thread msg type %u\n", itmsg->type); + break; + } + + if (tx) + enqueue_to_ifd(ct, tx); + +} + +/* call-back function for inter-thread socket */ +static int it_sock_fd_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct client_thread *ct = ofd->data; + int rc; + + if (what & OSMO_FD_READ) { + struct msgb *msg = msgb_alloc_c(OTC_GLOBAL, 1024, "Rx it_fd"); + struct itmsg *itmsg; + + OSMO_ASSERT(msg); + rc = read(ofd->fd, msg->tail, msgb_tailroom(msg)); + if (rc <= 0) { + LOGP(DMAIN, LOGL_ERROR, "Error reading from inter-thread fd: %d\n", rc); + pthread_exit(NULL); + } + msgb_put(msg, rc); + itmsg = (struct itmsg *) msgb_data(msg); + if (msgb_length(msg) < sizeof(*itmsg) || + msgb_length(msg) < sizeof(*itmsg) + itmsg->len) { + LOGP(DMAIN, LOGL_ERROR, "Dropping short inter-thread message\n"); + } else { + handle_it_msg(ct, itmsg); + } + msgb_free(msg); + } + + if (what & OSMO_FD_WRITE) { + struct msgb *msg = msgb_dequeue(&ct->it_msgq); + if (!msg) { + /* last message: disable write events */ + ofd->when &= ~OSMO_FD_WRITE; + } else { + unsigned int len = msgb_length(msg); + rc = write(ofd->fd, msgb_data(msg), len); + msgb_free(msg); + if (rc < len) { + LOGP(DMAIN, LOGL_ERROR, "Short write on inter-thread fd: %d < %d\n", + rc, len); + } + } + } + + + return 0; +} + +/* release all resources allocated by thread */ +static void client_pthread_cleanup(void *arg) +{ + struct client_thread *ct = arg; + + LOGP(DMAIN, LOGL_INFO, "Cleaning up remsim-client thread\n"); + //FIXME remsim_client_destroy(ct->bc); + ct->bc = NULL; + msgb_queue_free(&ct->it_msgq); + osmo_fd_unregister(&ct->it_ofd); + close(ct->it_ofd.fd); + ct->it_ofd.fd = -1; + talloc_free(ct); +} + +/* main function of remsim-client pthread */ +static void *client_pthread_main(void *arg) +{ + struct client_thread_cfg *cfg = arg; + struct client_thread *ct; + int rc; + + osmo_select_init(); + rc = osmo_ctx_init("client"); + OSMO_ASSERT(rc == 0); + + ct = talloc_zero(OTC_GLOBAL, struct client_thread); + OSMO_ASSERT(ct); + + if (!talloc_asn1_ctx) + talloc_asn1_ctx= talloc_named_const(ct, 0, "asn1"); + + ct->bc = remsim_client_create(ct, cfg->name, "remsim_ifdhandler"); + OSMO_ASSERT(ct->bc); + ct->bc->data = ct; + remsim_client_set_clslot(ct->bc, cfg->client_id, cfg->client_slot); + if (cfg->server_host) + ct->bc->srv_conn.server_host = (char *) cfg->server_host; + if (cfg->server_port >= 0) + ct->bc->srv_conn.server_port = cfg->server_port; + + INIT_LLIST_HEAD(&ct->it_msgq); + osmo_fd_setup(&ct->it_ofd, cfg->it_sock_fd, OSMO_FD_READ, &it_sock_fd_cb, ct, 0); + osmo_fd_register(&ct->it_ofd); + + /* ensure we get properly cleaned up if cancelled */ + pthread_cleanup_push(client_pthread_cleanup, ct); + + osmo_fsm_inst_dispatch(ct->bc->srv_conn.fi, SRVC_E_ESTABLISH, NULL); + + while (1) { + osmo_select_main(0); + } + + pthread_cleanup_pop(1); + return NULL; +} + +/*********************************************************************** + * PC/SC ifd_handler API functions + ***********************************************************************/ + +#include <ifdhandler.h> +#include <debuglog.h> + +#include <sys/types.h> +#include <sys/socket.h> + +static const struct value_string ifd_status_names[] = { + OSMO_VALUE_STRING(IFD_SUCCESS), + OSMO_VALUE_STRING(IFD_ERROR_TAG), + OSMO_VALUE_STRING(IFD_ERROR_SET_FAILURE), + OSMO_VALUE_STRING(IFD_ERROR_VALUE_READ_ONLY), + OSMO_VALUE_STRING(IFD_ERROR_PTS_FAILURE), + OSMO_VALUE_STRING(IFD_ERROR_NOT_SUPPORTED), + OSMO_VALUE_STRING(IFD_PROTOCOL_NOT_SUPPORTED), + OSMO_VALUE_STRING(IFD_ERROR_POWER_ACTION), + OSMO_VALUE_STRING(IFD_ERROR_SWALLOW), + OSMO_VALUE_STRING(IFD_ERROR_EJECT), + OSMO_VALUE_STRING(IFD_ERROR_CONFISCATE), + OSMO_VALUE_STRING(IFD_COMMUNICATION_ERROR), + OSMO_VALUE_STRING(IFD_RESPONSE_TIMEOUT), + OSMO_VALUE_STRING(IFD_NOT_SUPPORTED), + OSMO_VALUE_STRING(IFD_ICC_PRESENT), + OSMO_VALUE_STRING(IFD_ICC_NOT_PRESENT), + OSMO_VALUE_STRING(IFD_NO_SUCH_DEVICE), + OSMO_VALUE_STRING(IFD_ERROR_INSUFFICIENT_BUFFER), + { 0, NULL } +}; + +static const struct value_string ifd_tag_names[] = { + OSMO_VALUE_STRING(TAG_IFD_ATR), + OSMO_VALUE_STRING(TAG_IFD_SLOTNUM), + OSMO_VALUE_STRING(TAG_IFD_SLOT_THREAD_SAFE), + OSMO_VALUE_STRING(TAG_IFD_THREAD_SAFE), + OSMO_VALUE_STRING(TAG_IFD_SLOTS_NUMBER), + OSMO_VALUE_STRING(TAG_IFD_SIMULTANEOUS_ACCESS), + OSMO_VALUE_STRING(TAG_IFD_POLLING_THREAD), + OSMO_VALUE_STRING(TAG_IFD_POLLING_THREAD_KILLABLE), + OSMO_VALUE_STRING(TAG_IFD_STOP_POLLING_THREAD), + OSMO_VALUE_STRING(TAG_IFD_POLLING_THREAD_WITH_TIMEOUT), + { 0, NULL } +}; + +#define LOG_EXIT(Lun, r) \ + Log4(r == IFD_SUCCESS || r == IFD_ICC_NOT_PRESENT ? PCSC_LOG_DEBUG : PCSC_LOG_ERROR, \ + "%s(0x%08lx) => %s\n", __func__, Lun, get_value_string(ifd_status_names, r)) + +#define LOG_EXITF(Lun, r, fmt, args...) \ + Log5(r == IFD_SUCCESS ? PCSC_LOG_DEBUG : PCSC_LOG_ERROR, \ + "%s(0x%08lx) "fmt" => %s\n", __func__, Lun, ## args, get_value_string(ifd_status_names, r)) + +/* IFD side handle for a remsim-client [thread] */ +struct ifd_client { + /* the client pthread itself */ + pthread_t pthread; + /* socket to talk to thread */ + int it_fd; + /* configuration passed into the thread */ + struct client_thread_cfg cfg; +}; + +static struct msgb *ifd_xceive_client(struct ifd_client *ic, struct msgb *tx) +{ + struct msgb *rx = msgb_alloc_c(OTC_GLOBAL, 1024, "ifd_rx itmsg"); + struct itmsg *rx_it; + int rc; + + rc = write(ic->it_fd, msgb_data(tx), msgb_length(tx)); + msgb_free(tx); + if (rc < msgb_length(tx)) { + Log2(PCSC_LOG_ERROR, "Short write IFD->client thread: %d\n", rc); + msgb_free(rx); + return NULL; + } + rc = read(ic->it_fd, rx->tail, msgb_tailroom(rx)); + if (rc <= 0) { + Log2(PCSC_LOG_ERROR, "Short read IFD<-client thread: %d\n", rc); + msgb_free(rx); + return NULL; + } + msgb_put(rx, rc); + rx_it = (struct itmsg *) msgb_data(rx); + if (msgb_length(rx) < sizeof(*rx_it) + rx_it->len) { + Log2(PCSC_LOG_ERROR, "Short itmsg IFD<-client thread: %d\n", msgb_length(rx)); + msgb_free(rx); + return NULL; + } + return rx; +} + +/* function called on IFD side to create socketpair + start remsim-client thread */ +static struct ifd_client *create_ifd_client(const struct client_thread_cfg *cfg) +{ + struct ifd_client *ic = talloc_zero(OTC_GLOBAL, struct ifd_client); + int sp[2]; + int rc; + + /* copy over configuration */ + ic->cfg = *cfg; + + /* create socket pair for communication between threads */ + rc = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sp); + if (rc != 0) { + talloc_free(ic); + return NULL; + } + + ic->it_fd = sp[0]; + ic->cfg.it_sock_fd = sp[1]; + + /* start the thread */ + rc = pthread_create(&ic->pthread, NULL, client_pthread_main, &ic->cfg); + if (rc != 0) { + Log1(PCSC_LOG_ERROR, "Error creating remsim-client pthread\n"); + close(sp[0]); + close(sp[1]); + talloc_free(ic); + return NULL; + } + + return ic; +} + +/* function called on IFD side to destroy (terminate) remsim-client thread */ +static void destroy_ifd_client(struct ifd_client *ic) +{ + if (!ic) + return; + + pthread_cancel(ic->pthread); + pthread_join(ic->pthread, NULL); +} + +#define MAX_SLOTS 256 +static struct ifd_client *ifd_client[MAX_SLOTS]; + +#define LUN2SLOT(lun) ((lun) & 0xffff) +#define LUN2RDR(lun) ((lun) >> 16) + + +RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel) +{ + return IFD_COMMUNICATION_ERROR; +} + +RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR DeviceName) +{ + struct ifd_client *ic; + struct client_thread_cfg cfg = { + .name = "fixme-name", + .server_host = "127.0.0.1", + .server_port = -1, + .client_id = 0, + .client_slot = 0, + }; + char *r, *client_id, *slot_nr, *host, *port; + + if (LUN2RDR(Lun) != 0) + return IFD_NO_SUCH_DEVICE; + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) + return IFD_NO_SUCH_DEVICE; + + ensure_osmo_ctx(); + + client_id = strtok_r(DeviceName, ":", &r); + if (!client_id) + goto end_parse; + cfg.client_id = atoi(client_id); + + slot_nr = strtok_r(NULL, ":", &r); + if (!slot_nr) + goto end_parse; + cfg.client_slot = atoi(slot_nr); + + host = strtok_r(NULL, ":", &r); + if (!host) + goto end_parse; + cfg.server_host = strdup(host); + + port = strtok_r(NULL, ":", &r); + cfg.server_port = atoi(port); + + +end_parse: + LOGP(DMAIN, LOGL_NOTICE, "remsim-client C%d:%d bankd=%s:%d\n", + cfg.client_id, cfg.client_slot, cfg.server_host, cfg.server_port); + + ic = create_ifd_client(&cfg); + if (ic) { + ifd_client[LUN2SLOT(Lun)] = ic; + return IFD_SUCCESS; + } else + return IFD_COMMUNICATION_ERROR; +} + +RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode, PUCHAR TxBuffer, DWORD TxLength, + PUCHAR RxBuffer, DWORD RxLength, LPDWORD pdwBytesReturned) +{ + RESPONSECODE r = IFD_COMMUNICATION_ERROR; + + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (pdwBytesReturned) + *pdwBytesReturned = 0; + + r = IFD_ERROR_NOT_SUPPORTED; +err: + LOG_EXIT(Lun, r); + return r; +} + +RESPONSECODE IFDHCloseChannel(DWORD Lun) +{ + RESPONSECODE r = IFD_COMMUNICATION_ERROR; + + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + destroy_ifd_client(ifd_client[LUN2SLOT(Lun)]); + ifd_client[LUN2SLOT(Lun)] = NULL; + + r = IFD_SUCCESS; +err: + LOG_EXIT(Lun, r); + return r; +} + +RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag, PDWORD Length, PUCHAR Value) +{ + RESPONSECODE r = IFD_COMMUNICATION_ERROR; + struct ifd_client *ic; + struct msgb *rx, *tx; + struct itmsg *rx_it; + + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + ic = ifd_client[LUN2SLOT(Lun)]; + if (!ic) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (!Length || !Value) + goto err; + + switch (Tag) { + case TAG_IFD_ATR: + /* Return the ATR and its size */ + tx = itmsg_alloc(ITMSG_TYPE_ATR_REQ, 0, NULL, 0); + OSMO_ASSERT(tx); + rx = ifd_xceive_client(ic, tx); + if (!rx) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + rx_it = (struct itmsg *)msgb_data(rx); + if (*Length > rx_it->len) + *Length = rx_it->len; + memcpy(Value, rx_it->data, *Length); + msgb_free(rx); + break; + case TAG_IFD_SIMULTANEOUS_ACCESS: + /* Return the number of sessions (readers) the driver + * can handle in Value[0]. This is used for multiple + * readers sharing the same driver. */ + if (*Length < 1) + goto err; + *Value = 1; + *Length = 1; + break; + case TAG_IFD_SLOTS_NUMBER: + /* Return the number of slots in this reader in Value[0] */ + if (*Length < 1) + goto err; + *Value = 1; + *Length = 1; + break; + case TAG_IFD_THREAD_SAFE: + /* If the driver supports more than one reader (see + * TAG_IFD_SIMULTANEOUS_ACCESS above) this tag indicates + * if the driver supports access to multiple readers at + * the same time. */ + if (*Length < 1) + goto err; + *Value = 0; + *Length = 1; + break; + case TAG_IFD_SLOT_THREAD_SAFE: + /* If the reader has more than one slot (see + * TAG_IFD_SLOTS_NUMBER above) this tag indicates if the + * driver supports access to multiple slots of the same + * reader at the same time. */ + if (*Length < 1) + goto err; + *Value = 0; + *Length = 1; + break; + default: + r = IFD_ERROR_TAG; + goto err; + } + + r = IFD_SUCCESS; + +err: + if (r != IFD_SUCCESS && Length) + *Length = 0; + + LOG_EXITF(Lun, r, "%s", get_value_string(ifd_tag_names, Tag)); + return r; +} + +RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag, DWORD Length, PUCHAR Value) +{ + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) + return IFD_NO_SUCH_DEVICE; + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) + return IFD_NO_SUCH_DEVICE; + + + LOG_EXIT(Lun, IFD_NOT_SUPPORTED); + return IFD_NOT_SUPPORTED; +} + +RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol, UCHAR Flags, UCHAR PTS1, + UCHAR PTS2, UCHAR PTS3) +{ + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) + return IFD_NO_SUCH_DEVICE; + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) + return IFD_NO_SUCH_DEVICE; + + LOG_EXIT(Lun, IFD_SUCCESS); + return IFD_SUCCESS; +} + +RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action, PUCHAR Atr, PDWORD AtrLength) +{ + RESPONSECODE r = IFD_COMMUNICATION_ERROR; + struct ifd_client *ic; + struct msgb *rx, *tx; + + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + ic = ifd_client[LUN2SLOT(Lun)]; + if (!ic) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + switch (Action) { + case IFD_POWER_DOWN: + tx = itmsg_alloc(ITMSG_TYPE_POWER_OFF_REQ, 0, NULL, 0); + break; + case IFD_POWER_UP: + tx = itmsg_alloc(ITMSG_TYPE_POWER_ON_REQ, 0, NULL, 0); + break; + case IFD_RESET: + tx = itmsg_alloc(ITMSG_TYPE_RESET_REQ, 0, NULL, 0); + break; + default: + r = IFD_NOT_SUPPORTED; + goto err; + } + + rx = ifd_xceive_client(ic, tx); + if (!rx) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + r = IFD_SUCCESS; + msgb_free(rx); + +err: + if (r != IFD_SUCCESS && AtrLength) + *AtrLength = 0; + else + r = IFDHGetCapabilities(Lun, TAG_IFD_ATR, AtrLength, Atr); + + LOG_EXIT(Lun, r); + return r; +} + +RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci, PUCHAR TxBuffer, + DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength, + PSCARD_IO_HEADER RecvPci) +{ + RESPONSECODE r = IFD_COMMUNICATION_ERROR; + struct ifd_client *ic; + struct msgb *rx, *tx; + struct itmsg *rx_it; + + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + ic = ifd_client[LUN2SLOT(Lun)]; + if (!ic) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + tx = itmsg_alloc(ITMSG_TYPE_C_APDU_REQ, 0, TxBuffer, TxLength); + OSMO_ASSERT(tx); + /* transmit C-APDU to remote reader + blocking wait for response from peer */ + rx = ifd_xceive_client(ic, tx); + if (!rx) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + rx_it = (struct itmsg *) msgb_data(rx); + if (*RxLength > rx_it->len) + *RxLength = rx_it->len; + memcpy(RxBuffer, rx_it->data, *RxLength); + msgb_free(rx); + + r = IFD_SUCCESS; +err: + if (r != IFD_SUCCESS && RxLength) + *RxLength = 0; + + LOG_EXIT(Lun, r); + return r; +} + +RESPONSECODE IFDHICCPresence(DWORD Lun) +{ + RESPONSECODE r = IFD_COMMUNICATION_ERROR; + struct ifd_client *ic; + struct msgb *rx, *tx; + struct itmsg *rx_it; + + ensure_osmo_ctx(); + + if (LUN2RDR(Lun) != 0) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + if (LUN2SLOT(Lun) >= ARRAY_SIZE(ifd_client)) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + ic = ifd_client[LUN2SLOT(Lun)]; + if (!ic) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + + tx = itmsg_alloc(ITMSG_TYPE_CARD_PRES_REQ, 0, NULL, 0); + OSMO_ASSERT(tx); + rx = ifd_xceive_client(ic, tx); + if (!rx) { + r = IFD_NO_SUCH_DEVICE; + goto err; + } + rx_it = (struct itmsg *) msgb_data(rx); + if (rx_it->status == 0) + r = IFD_SUCCESS; + else + r = IFD_ICC_NOT_PRESENT; + +err: + LOG_EXIT(Lun, r); + return r; +} + +static __attribute__((constructor)) void on_dso_load_ifd(void) +{ + void *g_tall_ctx = NULL; + ensure_osmo_ctx(); + osmo_init_logging2(g_tall_ctx, &log_info); +} -- To view, visit https://gerrit.osmocom.org/c/osmo-remsim/+/17160 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-remsim Gerrit-Branch: master Gerrit-Change-Id: Ib8707c6e0e46407ab39a693adfec2fa71892f6ee Gerrit-Change-Number: 17160 Gerrit-PatchSet: 1 Gerrit-Owner: laforge <laforge at osmocom.org> Gerrit-MessageType: newchange -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20200215/96f789f1/attachment.htm>