From 1200c820f0e52cae5fd6c290cc71bc350d34a9c3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 Feb 2020 20:43:27 +0100 Subject: [PATCH] client: Add new osmo-remsim-client-shell binary This is a remsim-client with an interactive 'shell', where the user can type in C-APDUs in hex formats, which will be sent to the bankd / SIM-card. Responses received from SIM Card via bankd will be printed in return. Change-Id: I636505fd9741833ccf5cbd1bcac30f7b9aa94425 --- src/client/Makefile.am | 7 +- src/client/client.h | 7 ++ src/client/remsim_client.c | 16 ++- src/client/simtrace2-remsim_client.c | 2 +- src/client/user_shell.c | 159 +++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 9 deletions(-) create mode 100644 src/client/user_shell.c diff --git a/src/client/Makefile.am b/src/client/Makefile.am index 3d4f355..ec99818 100644 --- a/src/client/Makefile.am +++ b/src/client/Makefile.am @@ -4,10 +4,11 @@ AM_CFLAGS = -Wall -I$(top_srcdir)/include -I/$(top_builddir)/include -I$(top_src $(OSMOSIMTRACE2_CFLAGS) \ -I$(top_srcdir)/include/osmocom/rspro -bin_PROGRAMS = osmo-remsim-client-st2 remsim-client +bin_PROGRAMS = osmo-remsim-client-st2 osmo-remsim-client-shell -remsim_client_SOURCES = remsim_client.c ../rspro_client_fsm.c ../debug.c -remsim_client_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \ +osmo_remsim_client_shell_SOURCES = user_shell.c \ + remsim_client.c ../rspro_client_fsm.c ../debug.c +osmo_remsim_client_shell_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \ $(top_builddir)/src/libosmo-rspro.la osmo_remsim_client_st2_SOURCES = simtrace2-remsim_client.c \ diff --git a/src/client/client.h b/src/client/client.h index 7cc7ec1..b3001ee 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -56,3 +56,10 @@ struct bankd_client { struct client_config *cfg; struct cardem_inst *cardem; }; + + +extern struct bankd_client *g_client; + +extern int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu); + +extern int client_user_main(struct bankd_client *g_client); diff --git a/src/client/remsim_client.c b/src/client/remsim_client.c index 41361c0..dbe983b 100644 --- a/src/client/remsim_client.c +++ b/src/client/remsim_client.c @@ -52,6 +52,7 @@ static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *p break; case RsproPDUchoice_PR_tpduCardToModem: case RsproPDUchoice_PR_setAtrReq: + return client_user_bankd_handle_rx(bankdc, pdu); default: LOGPFSML(bankdc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU %s\n", rspro_msgt_name(pdu)); @@ -61,7 +62,7 @@ static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *p return 0; } -static struct bankd_client *g_client; +struct bankd_client *g_client; static void *g_tall_ctx; void __thread *talloc_asn1_ctx; int asn_debug; @@ -161,7 +162,7 @@ static void handle_options(int argc, char **argv) g_client->srv_conn.clslot = talloc_zero(g_client, ClientSlot_t); g_client->srv_conn.clslot->clientId = atoi(optarg); break; - case 's': + case 'n': if (!g_client->srv_conn.clslot) g_client->srv_conn.clslot = talloc_zero(g_client, ClientSlot_t); g_client->srv_conn.clslot->slotNr = atoi(optarg); @@ -185,6 +186,7 @@ int main(int argc, char **argv) g_client = talloc_zero(g_tall_ctx, struct bankd_client); + /* create and [attempt to] establish connection to remsim-server */ srvc = &g_client->srv_conn; srvc->server_host = "localhost"; srvc->server_port = 9998; @@ -208,6 +210,11 @@ int main(int argc, char **argv) asn_debug = 0; bankdc = &g_client->bankd_conn; + if (srvc->clslot) { + bankdc->clslot = talloc_zero(g_client, ClientSlot_t); + *bankdc->clslot = *srvc->clslot; + } + /* server_host / server_port are configured from remsim-server */ bankdc->handle_rx = bankd_handle_rx; memcpy(&bankdc->own_comp_id, &srvc->own_comp_id, sizeof(bankdc->own_comp_id)); @@ -216,8 +223,7 @@ int main(int argc, char **argv) fprintf(stderr, "Unable to connect bankd conn FSM: %s\n", strerror(errno)); exit(1); } + osmo_fsm_inst_update_id(bankdc->fi, "bankd"); - while (1) { - osmo_select_main(0); - } + client_user_main(g_client); } diff --git a/src/client/simtrace2-remsim_client.c b/src/client/simtrace2-remsim_client.c index ce8ea1d..bee8fc9 100644 --- a/src/client/simtrace2-remsim_client.c +++ b/src/client/simtrace2-remsim_client.c @@ -94,7 +94,7 @@ struct cardem_inst { /* global GSMTAP instance */ static struct gsmtap_inst *g_gti; -static struct bankd_client *g_client; +struct bankd_client *g_client; static void *g_tall_ctx; void __thread *talloc_asn1_ctx; int asn_debug; diff --git a/src/client/user_shell.c b/src/client/user_shell.c new file mode 100644 index 0000000..db36aab --- /dev/null +++ b/src/client/user_shell.c @@ -0,0 +1,159 @@ +#include +#include + +#include + +#include "client.h" + +/* This is a remsim-client with an interactive 'shell', where the user + * can type in C-APDUs in hex formats, which will be sent to the bankd / + * SIM-card. Responses received from SIM Card via bankd will be printed + * in return. */ + + +/*********************************************************************** + * Incoming RSPRO messages from bank-daemon (SIM card) + ***********************************************************************/ + +static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu) +{ + OSMO_ASSERT(pdu); + OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present); + + const struct TpduCardToModem *card2modem = &pdu->msg.choice.tpduCardToModem; + + printf("R-APDU: %s\n", osmo_hexdump(card2modem->data.buf, card2modem->data.size)); + + return 0; +} + +static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu) +{ + RsproPDU_t *resp; + + OSMO_ASSERT(pdu); + OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present); + + printf("SET_ATR: %s\n", osmo_hexdump(pdu->msg.choice.setAtrReq.atr.buf, + pdu->msg.choice.setAtrReq.atr.size)); + + 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) +{ + switch (pdu->msg.present) { + case RsproPDUchoice_PR_tpduCardToModem: + bankd_handle_tpduCardToModem(g_client, pdu); + break; + case RsproPDUchoice_PR_setAtrReq: + bankd_handle_setAtrReq(g_client, pdu); + break; + default: + OSMO_ASSERT(0); + } + return 0; +} + +/*********************************************************************** + * Incoming command from the user application (stdin shell in our case) + ***********************************************************************/ + +struct stdin_state { + struct osmo_fd ofd; + struct msgb *rx_msg; +}; + +/* called every time a command on stdin was received */ +static void handle_stdin_command(struct stdin_state *ss, char *cmd) +{ + RsproPDU_t *pdu; + BankSlot_t bslot; + uint8_t buf[1024]; + int rc; + + bank_slot2rspro(&bslot, &g_client->bankd_slot); + + OSMO_ASSERT(ss->rx_msg); + + printf("stdin: `%s'\n", cmd); + + if (!strcasecmp(cmd, "RESET")) { + /* reset the [remote] card */ + pdu = rspro_gen_ClientSlotStatusInd(g_client->srv_conn.clslot, &bslot, + true, false, false, true); + server_conn_send_rspro(&g_client->bankd_conn, pdu); + } else { + /* we assume the user has entered a C-APDU as hex string. parse + send */ + rc = osmo_hexparse(cmd, buf, sizeof(buf)); + if (rc < 0) { + fprintf(stderr, "ERROR parsing C-APDU `%s'!\n", cmd); + return; + } + if (!g_client->srv_conn.clslot) { + fprintf(stderr, "Cannot send command; no client slot\n"); + return; + } + + /* Send CMD APDU to [remote] card */ + pdu = rspro_gen_TpduModem2Card(g_client->srv_conn.clslot, &bslot, buf, rc); + server_conn_send_rspro(&g_client->bankd_conn, pdu); + } +} + +/* call-back function for stdin read. Gather bytes in buffer until CR/LF received */ +static int stdin_fd_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct stdin_state *ss = ofd->data; + char *cur; + int rc, i; + + OSMO_ASSERT(what & OSMO_FD_READ); + + if (!ss->rx_msg) { + ss->rx_msg = msgb_alloc(1024, "stdin"); + OSMO_ASSERT(ss->rx_msg); + } + + cur = (char *) ss->rx_msg->tail; + rc = read(ofd->fd, cur, msgb_tailroom(ss->rx_msg)); + if (rc < 0) + return rc; + msgb_put(ss->rx_msg, rc); + + for (i = 0; i < rc; i++) { + if (cur[i] == '\r' || cur[i] == '\n') { + cur[i] = '\0'; + /* dispatch the command */ + handle_stdin_command(ss, cur); + /* FIXME: possibly other commands */ + msgb_free(ss->rx_msg); + ss->rx_msg = NULL; + } + } + + return 0; +} + + + +/* main function */ +int client_user_main(struct bankd_client *g_client) +{ + struct stdin_state ss; + + /* register stdin file descriptor with osmocom select loop abstraction */ + memset(&ss, 0, sizeof(ss)); + osmo_fd_setup(&ss.ofd, fileno(stdin), OSMO_FD_READ, &stdin_fd_cb, &ss, 0); + osmo_fd_register(&ss.ofd); + + while (1) { + osmo_select_main(0); + } +}