<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-remsim/+/17361">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">client: major restructuring around new main_fsm<br><br>The remsim_client code already used FSMs for the connections<br>to both remsim-server and remsim-bankd.  However the 'main' part of the<br>program was not yet implemented as a FSM, making it somewhat difficult<br>to perform the right actions in every possible situation.<br><br>This commit re-structures the code around a central main_fsm, which<br>gets notified from the per-connection FSMs and which handles the common<br>processing.  It also handles the execution of external script commands,<br>and hence further unifies the code base between the different backends<br>(simtrace2, ifd_handler, shell)<br><br>Closes: #4414<br><br>Change-Id: I44a430bc5674dea00ed72a0b28729ac8bcb4e022<br>---<br>M src/client/Makefile.am<br>M src/client/client.h<br>A src/client/main_fsm.c<br>M src/client/remsim_client.c<br>M src/client/remsim_client_main.c<br>D src/client/simtrace2-remsim_client.c<br>M src/client/user_ifdhandler.c<br>M src/client/user_shell.c<br>A src/client/user_simtrace2.c<br>M src/rspro_client_fsm.c<br>10 files changed, 1,119 insertions(+), 1,392 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-remsim refs/changes/61/17361/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/client/Makefile.am b/src/client/Makefile.am</span><br><span>index f37126a..43b030f 100644</span><br><span>--- a/src/client/Makefile.am</span><br><span>+++ b/src/client/Makefile.am</span><br><span>@@ -7,7 +7,7 @@</span><br><span> bin_PROGRAMS = osmo-remsim-client-st2 osmo-remsim-client-shell</span><br><span> </span><br><span> osmo_remsim_client_shell_SOURCES = user_shell.c remsim_client_main.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                              remsim_client.c ../rspro_client_fsm.c ../debug.c</span><br><span style="color: hsl(120, 100%, 40%);">+                              remsim_client.c main_fsm.c ../rspro_client_fsm.c ../debug.c</span><br><span> osmo_remsim_client_shell_CFLAGS = $(AM_CFLAGS)</span><br><span> osmo_remsim_client_shell_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \</span><br><span>                   $(top_builddir)/src/libosmo-rspro.la</span><br><span>@@ -19,15 +19,16 @@</span><br><span> bundlelinuxdir=$(bundledir)/Linux</span><br><span> bundlelinux_LTLIBRARIES = libifd_remsim_client.la</span><br><span> libifd_remsim_client_la_SOURCES = user_ifdhandler.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                                remsim_client.c ../rspro_client_fsm.c ../debug.c</span><br><span style="color: hsl(120, 100%, 40%);">+                              remsim_client.c main_fsm.c ../rspro_client_fsm.c ../debug.c</span><br><span> libifd_remsim_client_la_CFLAGS = $(AM_CFLAGS)</span><br><span> libifd_remsim_client_la_CPPFLAGS = $(PCSC_CFLAGS)</span><br><span> libifd_remsim_client_la_LDFLAGS = -no-undefined</span><br><span> libifd_remsim_client_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \</span><br><span>                    $(top_builddir)/src/libosmo-rspro.la</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-osmo_remsim_client_st2_SOURCES = simtrace2-remsim_client.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                               ../rspro_client_fsm.c ../debug.c</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_remsim_client_st2_SOURCES = user_simtrace2.c remsim_client_main.c \</span><br><span style="color: hsl(120, 100%, 40%);">+                            remsim_client.c main_fsm.c ../rspro_client_fsm.c ../debug.c</span><br><span style="color: hsl(120, 100%, 40%);">+osmo_remsim_client_st2_CPPFLAGS = -DUSB_SUPPORT</span><br><span> osmo_remsim_client_st2_CFLAGS = $(AM_CFLAGS)</span><br><span> osmo_remsim_client_st2_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \</span><br><span>                         $(OSMOUSB_LIBS) $(OSMOSIMTRACE2_LIBS) \</span><br><span>diff --git a/src/client/client.h b/src/client/client.h</span><br><span>index 0761255..b828882 100644</span><br><span>--- a/src/client/client.h</span><br><span>+++ b/src/client/client.h</span><br><span>@@ -10,9 +10,49 @@</span><br><span> #include "slotmap.h"</span><br><span> #include "debug.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * frontend interface</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct bankd_client;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct frontend_phys_status {</span><br><span style="color: hsl(120, 100%, 40%);">+       struct {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* all members can be 0 (inactive), 1 (active) or -1 (not supported/known) */</span><br><span style="color: hsl(120, 100%, 40%);">+         int reset_active;</span><br><span style="color: hsl(120, 100%, 40%);">+             int vcc_present;</span><br><span style="color: hsl(120, 100%, 40%);">+              int clk_active;</span><br><span style="color: hsl(120, 100%, 40%);">+               int card_present;</span><br><span style="color: hsl(120, 100%, 40%);">+     } flags;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t voltage_mv;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t fi;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t di;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t wi;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t waiting_time;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct frontend_pts {</span><br><span style="color: hsl(120, 100%, 40%);">+    const uint8_t *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct frontend_tpdu {</span><br><span style="color: hsl(120, 100%, 40%);">+     const uint8_t *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* API from generic core to frontend (modem/cardem) */</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_card_insert(struct bankd_client *bc);</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_sim_remote(struct bankd_client *bc);</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_modem_reset(struct bankd_client *bc);</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts);</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* main.c */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct cardem_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_st2_cardem_inst;</span><br><span> </span><br><span> #define ATR_SIZE_MAX            55</span><br><span> struct client_config {</span><br><span>@@ -48,6 +88,8 @@</span><br><span>         struct rspro_server_conn srv_conn;</span><br><span>   /* connection to the remsim-bankd (data) */</span><br><span>  struct rspro_server_conn bankd_conn;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* CLIENT_MAIN fsm */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_fsm_inst *main_fi;</span><br><span> </span><br><span>   /* remote component ID */</span><br><span>    struct app_comp_id peer_comp_id;</span><br><span>@@ -55,17 +97,43 @@</span><br><span>       struct bank_slot bankd_slot;</span><br><span> </span><br><span>     struct client_config *cfg;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct cardem_inst *cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_st2_cardem_inst *cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct frontend_phys_status last_status;</span><br><span>     void *data;</span><br><span> };</span><br><span> </span><br><span> #define srvc2bankd_client(srvc)                container_of(srvc, struct bankd_client, srv_conn)</span><br><span> #define bankdc2bankd_client(bdc)   container_of(bdc, struct bankd_client, bankd_conn)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software);</span><br><span style="color: hsl(120, 100%, 40%);">+struct client_config *client_config_init(void *ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         struct client_config *cfg);</span><br><span> void remsim_client_set_clslot(struct bankd_client *bc, int client_id, int slot_nr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-extern int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> extern int client_user_main(struct bankd_client *g_client);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * main FSM</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum main_fsm_event {</span><br><span style="color: hsl(120, 100%, 40%);">+        MF_E_SRVC_CONNECTED,    /* connection to server established (TCP + RSPRO level) */</span><br><span style="color: hsl(120, 100%, 40%);">+    MF_E_SRVC_LOST,         /* connection to server was lost */</span><br><span style="color: hsl(120, 100%, 40%);">+   MF_E_SRVC_CONFIG_BANK,  /* server instructs us to connect to bankd/slot */</span><br><span style="color: hsl(120, 100%, 40%);">+    MF_E_SRVC_RESET_REQ,    /* RsproPDUchoice_PR_ResetStateReq */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       MF_E_BANKD_CONNECTED,   /* connection to bankd established (TCP + RSPRO level) */</span><br><span style="color: hsl(120, 100%, 40%);">+     MF_E_BANKD_LOST,        /* connection to bankd was lost */</span><br><span style="color: hsl(120, 100%, 40%);">+    MF_E_BANKD_TPDU,        /* RsproPDUchoice_PR_tpduCardToModem */</span><br><span style="color: hsl(120, 100%, 40%);">+       MF_E_BANKD_ATR,         /* RsproPDUchoice_PR_setAtrReq */</span><br><span style="color: hsl(120, 100%, 40%);">+     MF_E_BANKD_SLOT_STATUS, /* bankSlotStatusInd */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     MF_E_MDM_STATUS_IND,    /* status from modem/cardem */</span><br><span style="color: hsl(120, 100%, 40%);">+        MF_E_MDM_PTS_IND,       /* PTS indication from modem/cardem */</span><br><span style="color: hsl(120, 100%, 40%);">+        MF_E_MDM_TPDU,          /* TPDU from modem/cardem */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *main_fsm_alloc(void *ctx, struct bankd_client *bc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/src/client/main_fsm.c b/src/client/main_fsm.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b94af26</span><br><span>--- /dev/null</span><br><span>+++ b/src/client/main_fsm.c</span><br><span>@@ -0,0 +1,377 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2020 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/exec.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "rspro_util.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "client.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "debug.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define S(x)        (1 << (x))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* build the (additional) environment for executing a script */</span><br><span style="color: hsl(120, 100%, 40%);">+static char **build_script_env(struct bankd_client *bc, const char *cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       char **env = talloc_zero_size(bc, 256*sizeof(char *));</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc, i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!env)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_VERSION=%s", VERSION);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     env[i++] = talloc_asprintf(env, "REMSIM_SERVER_ADDR=%s:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                            bc->srv_conn.server_host, bc->srv_conn.server_port);</span><br><span style="color: hsl(120, 100%, 40%);">+ env[i++] = talloc_asprintf(env, "REMSIM_SERVER_STATE=%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                              osmo_fsm_inst_state_name(bc->srv_conn.fi));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   env[i++] = talloc_asprintf(env, "REMSIM_BANKD_ADDR=%s:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                             bc->bankd_conn.server_host, bc->bankd_conn.server_port);</span><br><span style="color: hsl(120, 100%, 40%);">+     env[i++] = talloc_asprintf(env, "REMSIM_BANKD_STATE=%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_fsm_inst_state_name(bc->bankd_conn.fi));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bc->srv_conn.clslot) {</span><br><span style="color: hsl(120, 100%, 40%);">+         env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_SLOT=%lu:%lu",</span><br><span style="color: hsl(120, 100%, 40%);">+                                          bc->srv_conn.clslot->clientId,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          bc->srv_conn.clslot->slotNr);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     env[i++] = talloc_asprintf(env, "REMSIM_BANKD_SLOT=%u:%u",</span><br><span style="color: hsl(120, 100%, 40%);">+                             bc->bankd_slot.bank_id, bc->bankd_slot.slot_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   env[i++] = talloc_asprintf(env, "REMSIM_SIM_VCC=%u", bc->last_status.flags.vcc_present);</span><br><span style="color: hsl(120, 100%, 40%);">+ env[i++] = talloc_asprintf(env, "REMSIM_SIM_RST=%u", bc->last_status.flags.reset_active);</span><br><span style="color: hsl(120, 100%, 40%);">+        /* TODO: SIM card state CLK */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      env[i++] = talloc_asprintf(env, "REMSIM_CAUSE=%s", cause);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* ask frontend to append any frontend-speccific additional environment vars */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = frontend_append_script_env(bc, env+i, 256-i);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                i += rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* terminate last entry */</span><br><span style="color: hsl(120, 100%, 40%);">+    env[i++] = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      return env;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int call_script(struct bankd_client *bc, const char *cause)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       char **env, *cmd;</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bc->cfg->event_script)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   env = build_script_env(bc, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!env)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     cmd = talloc_asprintf(env, "%s %s", bc->cfg->event_script, cause);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+           talloc_free(env);</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = osmo_system_nowait(cmd, osmo_environment_whitelist, env);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(env);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum main_fsm_state {</span><br><span style="color: hsl(120, 100%, 40%);">+       MF_ST_INIT,</span><br><span style="color: hsl(120, 100%, 40%);">+   MF_ST_UNCONFIGURED,     /* waiting for configuration from server */</span><br><span style="color: hsl(120, 100%, 40%);">+   MF_ST_WAIT_BANKD,       /* configured; waiting for bankd conn */</span><br><span style="color: hsl(120, 100%, 40%);">+      MF_ST_OPERATIONAL,      /* fully operational (configured + bankd conn live */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct value_string main_fsm_event_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_VALUE_STRING(MF_E_SRVC_CONNECTED),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(MF_E_SRVC_LOST),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(MF_E_SRVC_CONFIG_BANK),</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_VALUE_STRING(MF_E_SRVC_RESET_REQ),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(MF_E_BANKD_CONNECTED),</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_VALUE_STRING(MF_E_BANKD_LOST),</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_VALUE_STRING(MF_E_BANKD_TPDU),</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_VALUE_STRING(MF_E_BANKD_ATR),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(MF_E_BANKD_SLOT_STATUS),</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(MF_E_MDM_STATUS_IND),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(MF_E_MDM_PTS_IND),</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_VALUE_STRING(MF_E_MDM_TPDU),</span><br><span style="color: hsl(120, 100%, 40%);">+     { 0, NULL }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_operational(struct osmo_fsm_inst *fi, uint32_t event, void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bankd_client *bc = (struct bankd_client *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case MF_E_SRVC_CONNECTED:</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_state_chg(fi, MF_ST_UNCONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                call_script(bc, "event-server-connect");</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_unconfigured_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct bankd_client *bc = (struct bankd_client *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* we might be called from a 'higher' state such as operational; clean up */</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_DISCONNECT, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case MF_E_SRVC_CONFIG_BANK:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* same treatment as below */</span><br><span style="color: hsl(120, 100%, 40%);">+         main_st_operational(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_wait_bankd(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bankd_client *bc = (struct bankd_client *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case MF_E_SRVC_CONFIG_BANK:</span><br><span style="color: hsl(120, 100%, 40%);">+           /* same treatment as below */</span><br><span style="color: hsl(120, 100%, 40%);">+         main_st_operational(fi, event, data);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_BANKD_CONNECTED:</span><br><span style="color: hsl(120, 100%, 40%);">+            osmo_fsm_inst_state_chg(fi, MF_ST_OPERATIONAL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+         call_script(bc, "event-bankd-connect");</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_operational_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct bankd_client *bc = (struct bankd_client *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Simulate card-insert to modem */</span><br><span style="color: hsl(120, 100%, 40%);">+   frontend_request_card_insert(bc);</span><br><span style="color: hsl(120, 100%, 40%);">+     call_script(bc, "request-card-insert");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Select remote (forwarded) SIM */</span><br><span style="color: hsl(120, 100%, 40%);">+   frontend_request_sim_remote(bc);</span><br><span style="color: hsl(120, 100%, 40%);">+      call_script(bc, "request-sim-remote");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Set the ATR */</span><br><span style="color: hsl(120, 100%, 40%);">+     frontend_handle_set_atr(bc, bc->cfg->atr.data, bc->cfg->atr.len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Reset the modem */</span><br><span style="color: hsl(120, 100%, 40%);">+ frontend_request_modem_reset(bc);</span><br><span style="color: hsl(120, 100%, 40%);">+     call_script(bc, "request-modem-reset");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_st_operational(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct bankd_client *bc = (struct bankd_client *) fi->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct frontend_phys_status *pstatus = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct frontend_pts *pts = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct frontend_tpdu *tpdu = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    RsproPDU_t *pdu_rx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    RsproPDU_t *resp;</span><br><span style="color: hsl(120, 100%, 40%);">+     BankSlot_t bslot;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case MF_E_BANKD_LOST:</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_fsm_inst_state_chg(fi, MF_ST_WAIT_BANKD, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_SRVC_CONFIG_BANK:</span><br><span style="color: hsl(120, 100%, 40%);">+           pdu_rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(pdu_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_configClientBankReq);</span><br><span style="color: hsl(120, 100%, 40%);">+         /* store/set the bankd ip/port as instructed by the server */</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_talloc_replace_string(bc, &bc->bankd_conn.server_host,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       rspro_IpAddr2str(&pdu_rx->msg.choice.configClientBankReq.bankd.ip));</span><br><span style="color: hsl(120, 100%, 40%);">+                bc->bankd_conn.server_port = pdu_rx->msg.choice.configClientBankReq.bankd.port;</span><br><span style="color: hsl(120, 100%, 40%);">+         rspro2bank_slot(&bc->bankd_slot, &pdu_rx->msg.choice.configClientBankReq.bankSlot);</span><br><span style="color: hsl(120, 100%, 40%);">+             /* bankd port 0 is a magic value to indicate "no bankd" */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (bc->bankd_conn.server_port == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmo_fsm_inst_state_chg(fi, MF_ST_UNCONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                else {</span><br><span style="color: hsl(120, 100%, 40%);">+                        osmo_fsm_inst_state_chg(fi, MF_ST_WAIT_BANKD, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* TODO: do we need to disconnect before? */</span><br><span style="color: hsl(120, 100%, 40%);">+                  osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_ESTABLISH, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* send response to server */</span><br><span style="color: hsl(120, 100%, 40%);">+         resp = rspro_gen_ConfigClientBankRes(ResultCode_ok);</span><br><span style="color: hsl(120, 100%, 40%);">+          server_conn_send_rspro(&bc->srv_conn, resp);</span><br><span style="color: hsl(120, 100%, 40%);">+           call_script(bc, "event-config-bankd");</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_BANKD_TPDU:</span><br><span style="color: hsl(120, 100%, 40%);">+         pdu_rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(pdu_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_tpduCardToModem);</span><br><span style="color: hsl(120, 100%, 40%);">+             /* forward to modem/cardem (via API) */</span><br><span style="color: hsl(120, 100%, 40%);">+               frontend_handle_card2modem(bc, pdu_rx->msg.choice.tpduCardToModem.data.buf,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           pdu_rx->msg.choice.tpduCardToModem.data.size);</span><br><span style="color: hsl(120, 100%, 40%);">+          /* response happens indirectly via tpduModemToCard */</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_BANKD_ATR:</span><br><span style="color: hsl(120, 100%, 40%);">+          pdu_rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(pdu_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_setAtrReq);</span><br><span style="color: hsl(120, 100%, 40%);">+           /* forward to modem/cardem (via API) */</span><br><span style="color: hsl(120, 100%, 40%);">+               frontend_handle_set_atr(bc, pdu_rx->msg.choice.setAtrReq.atr.buf,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  pdu_rx->msg.choice.setAtrReq.atr.size);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* send response to bankd */</span><br><span style="color: hsl(120, 100%, 40%);">+          resp = rspro_gen_SetAtrRes(ResultCode_ok);</span><br><span style="color: hsl(120, 100%, 40%);">+            server_conn_send_rspro(&bc->bankd_conn, resp);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_BANKD_SLOT_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+          pdu_rx = data;</span><br><span style="color: hsl(120, 100%, 40%);">+                OSMO_ASSERT(pdu_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_bankSlotStatusInd);</span><br><span style="color: hsl(120, 100%, 40%);">+           /* forward to modem/cardem (via API) */</span><br><span style="color: hsl(120, 100%, 40%);">+               frontend_handle_slot_status(bc, &pdu_rx->msg.choice.bankSlotStatusInd.slotPhysStatus);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_MDM_STATUS_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+             pstatus = data;</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(pstatus);</span><br><span style="color: hsl(120, 100%, 40%);">+         /* forward to bankd */</span><br><span style="color: hsl(120, 100%, 40%);">+                bank_slot2rspro(&bslot, &bc->bankd_slot);</span><br><span style="color: hsl(120, 100%, 40%);">+          resp = rspro_gen_ClientSlotStatusInd(bc->srv_conn.clslot, &bslot,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                   pstatus->flags.reset_active,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               pstatus->flags.vcc_present,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                pstatus->flags.clk_active,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 pstatus->flags.card_present);</span><br><span style="color: hsl(120, 100%, 40%);">+         server_conn_send_rspro(&bc->bankd_conn, resp);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!memcmp(&bc->last_status.flags, &pstatus->flags, sizeof(pstatus->flags)))</span><br><span style="color: hsl(120, 100%, 40%);">+                        call_script(bc, "event-modem-status");</span><br><span style="color: hsl(120, 100%, 40%);">+              bc->last_status = *pstatus;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_MDM_PTS_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+                pts = data;</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(pts);</span><br><span style="color: hsl(120, 100%, 40%);">+             /* forward to bankd? */</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_MDM_TPDU:</span><br><span style="color: hsl(120, 100%, 40%);">+           tpdu = data;</span><br><span style="color: hsl(120, 100%, 40%);">+          OSMO_ASSERT(tpdu);</span><br><span style="color: hsl(120, 100%, 40%);">+            /* forward to bankd */</span><br><span style="color: hsl(120, 100%, 40%);">+                bank_slot2rspro(&bslot, &bc->bankd_slot);</span><br><span style="color: hsl(120, 100%, 40%);">+          resp = rspro_gen_TpduModem2Card(bc->srv_conn.clslot, &bslot, tpdu->buf, tpdu->len);</span><br><span style="color: hsl(120, 100%, 40%);">+              server_conn_send_rspro(&bc->bankd_conn, resp);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void main_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case MF_E_SRVC_LOST:</span><br><span style="color: hsl(120, 100%, 40%);">+          /* should we do anything? The SRVC fsm will take care of reconnect, and we</span><br><span style="color: hsl(120, 100%, 40%);">+             * can continue to talk to the bankd without any trouble... */</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MF_E_SRVC_RESET_REQ:</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_fsm_inst_state_chg(fi, MF_ST_UNCONFIGURED, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(0);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct osmo_fsm_state main_fsm_states[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    [MF_ST_INIT] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .name = "INIT",</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(MF_E_SRVC_CONNECTED),</span><br><span style="color: hsl(120, 100%, 40%);">+              .out_state_mask = S(MF_ST_UNCONFIGURED),</span><br><span style="color: hsl(120, 100%, 40%);">+              .action = main_st_init,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [MF_ST_UNCONFIGURED] = {</span><br><span style="color: hsl(120, 100%, 40%);">+              .name = "UNCONFIGURED",</span><br><span style="color: hsl(120, 100%, 40%);">+             .in_event_mask = S(MF_E_SRVC_CONFIG_BANK),</span><br><span style="color: hsl(120, 100%, 40%);">+            .out_state_mask = S(MF_ST_INIT) | S(MF_ST_WAIT_BANKD),</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = main_st_unconfigured,</span><br><span style="color: hsl(120, 100%, 40%);">+               .onenter = main_st_unconfigured_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+      },</span><br><span style="color: hsl(120, 100%, 40%);">+    [MF_ST_WAIT_BANKD] = {</span><br><span style="color: hsl(120, 100%, 40%);">+                .name = "WAIT_BANKD",</span><br><span style="color: hsl(120, 100%, 40%);">+               .in_event_mask = S(MF_E_SRVC_CONFIG_BANK) | S(MF_E_BANKD_CONNECTED),</span><br><span style="color: hsl(120, 100%, 40%);">+          .out_state_mask = S(MF_ST_INIT) | S(MF_ST_UNCONFIGURED) | S(MF_ST_OPERATIONAL),</span><br><span style="color: hsl(120, 100%, 40%);">+               .action = main_st_wait_bankd,</span><br><span style="color: hsl(120, 100%, 40%);">+ },</span><br><span style="color: hsl(120, 100%, 40%);">+    [MF_ST_OPERATIONAL] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .name = "OPERATIONAL",</span><br><span style="color: hsl(120, 100%, 40%);">+              .in_event_mask = S(MF_E_SRVC_CONFIG_BANK) |</span><br><span style="color: hsl(120, 100%, 40%);">+                            S(MF_E_BANKD_LOST) |</span><br><span style="color: hsl(120, 100%, 40%);">+                          S(MF_E_BANKD_TPDU) |</span><br><span style="color: hsl(120, 100%, 40%);">+                          S(MF_E_BANKD_ATR) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(MF_E_BANKD_SLOT_STATUS) |</span><br><span style="color: hsl(120, 100%, 40%);">+                           S(MF_E_MDM_STATUS_IND) |</span><br><span style="color: hsl(120, 100%, 40%);">+                              S(MF_E_MDM_PTS_IND) |</span><br><span style="color: hsl(120, 100%, 40%);">+                                 S(MF_E_MDM_TPDU),</span><br><span style="color: hsl(120, 100%, 40%);">+            .out_state_mask = S(MF_ST_INIT) | S(MF_ST_UNCONFIGURED) | S(MF_ST_WAIT_BANKD),</span><br><span style="color: hsl(120, 100%, 40%);">+                .action = main_st_operational,</span><br><span style="color: hsl(120, 100%, 40%);">+                .onenter = main_st_operational_onenter,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_fsm client_main_fsm = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .name = "CLIENT_MAIN",</span><br><span style="color: hsl(120, 100%, 40%);">+      .states = main_fsm_states,</span><br><span style="color: hsl(120, 100%, 40%);">+    .num_states = ARRAY_SIZE(main_fsm_states),</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_event_mask = S(MF_E_SRVC_LOST) | S(MF_E_SRVC_RESET_REQ),</span><br><span style="color: hsl(120, 100%, 40%);">+    .allstate_action = main_allstate_action,</span><br><span style="color: hsl(120, 100%, 40%);">+      .log_subsys = DMAIN,</span><br><span style="color: hsl(120, 100%, 40%);">+  .event_names = main_fsm_event_names,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst *main_fsm_alloc(void *ctx, struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return osmo_fsm_inst_alloc(&client_main_fsm, ctx, bc, LOGL_DEBUG, "main");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute((constructor)) void on_dso_load_main_fsm(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(osmo_fsm_register(&client_main_fsm) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/client/remsim_client.c b/src/client/remsim_client.c</span><br><span>index dd78c8e..182894f 100644</span><br><span>--- a/src/client/remsim_client.c</span><br><span>+++ b/src/client/remsim_client.c</span><br><span>@@ -20,6 +20,10 @@</span><br><span>  *</span><br><span>  */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* This file contains code shared among all remsim client applications,</span><br><span style="color: hsl(120, 100%, 40%);">+ * including the ifd-handler, which is not an executable program with a main()</span><br><span style="color: hsl(120, 100%, 40%);">+ * function or command line parsing, but a shared library */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <errno.h></span><br><span> #include <string.h></span><br><span> </span><br><span>@@ -33,8 +37,38 @@</span><br><span> #include "client.h"</span><br><span> #include "debug.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct client_config *client_config_init(void *ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct client_config *cfg = talloc_zero(ctx, struct client_config);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!cfg)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        cfg->server_host = talloc_strdup(cfg, "127.0.0.1");</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg->server_port = 9998;</span><br><span style="color: hsl(120, 100%, 40%);">+   cfg->client_id = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+       cfg->client_slot = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+     cfg->gsmtap_host = talloc_strdup(cfg, "127.0.0.1");</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg->keep_running = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       cfg->usb.vendor_id = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   cfg->usb.product_id = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  cfg->usb.config_id = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+   cfg->usb.if_num = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+      cfg->usb.altsetting = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   cfg->usb.addr = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+        cfg->usb.path = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    cfg->atr.data[0] = 0x3B;</span><br><span style="color: hsl(120, 100%, 40%);">+   cfg->atr.data[1] = 0x00; // the shortest simplest ATR possible</span><br><span style="color: hsl(120, 100%, 40%);">+     cfg->atr.len = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct bankd_client *bc = bankdc2bankd_client(bankdc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     switch (pdu->msg.present) {</span><br><span>       case RsproPDUchoice_PR_connectClientRes:</span><br><span>             /* Store 'identity' of bankd to in peer_comp_id */</span><br><span>@@ -42,8 +76,11 @@</span><br><span>              osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu);</span><br><span>                 break;</span><br><span>       case RsproPDUchoice_PR_tpduCardToModem:</span><br><span style="color: hsl(120, 100%, 40%);">+               return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_TPDU, (void *) pdu);</span><br><span>        case RsproPDUchoice_PR_setAtrReq:</span><br><span style="color: hsl(0, 100%, 40%);">-               return client_user_bankd_handle_rx(bankdc, pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+              return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_ATR, (void *) pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+  case RsproPDUchoice_PR_bankSlotStatusInd:</span><br><span style="color: hsl(120, 100%, 40%);">+             return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_SLOT_STATUS, (void *) pdu);</span><br><span>         default:</span><br><span>             LOGPFSML(bankdc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU %s\n",</span><br><span>                   rspro_msgt_name(pdu));</span><br><span>@@ -78,19 +115,7 @@</span><br><span>                server_conn_send_rspro(srvc, resp);</span><br><span>          break;</span><br><span>       case RsproPDUchoice_PR_configClientBankReq:</span><br><span style="color: hsl(0, 100%, 40%);">-             /* store/set the bankd ip/port as instructed by the server */</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_talloc_replace_string(bc, &bc->bankd_conn.server_host,</span><br><span style="color: hsl(0, 100%, 40%);">-                                         rspro_IpAddr2str(&pdu->msg.choice.configClientBankReq.bankd.ip));</span><br><span style="color: hsl(0, 100%, 40%);">-             rspro2bank_slot(&bc->bankd_slot, &pdu->msg.choice.configClientBankReq.bankSlot);</span><br><span style="color: hsl(0, 100%, 40%);">-          bc->bankd_conn.server_port = pdu->msg.choice.configClientBankReq.bankd.port;</span><br><span style="color: hsl(0, 100%, 40%);">-              /* bankd port 0 is a magic value to indicate "no bankd" */</span><br><span style="color: hsl(0, 100%, 40%);">-            if (bc->bankd_conn.server_port == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                 osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_DISCONNECT, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-          else</span><br><span style="color: hsl(0, 100%, 40%);">-                    osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_ESTABLISH, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-           /* send response to server */</span><br><span style="color: hsl(0, 100%, 40%);">-           resp = rspro_gen_ConfigClientBankRes(ResultCode_ok);</span><br><span style="color: hsl(0, 100%, 40%);">-            server_conn_send_rspro(srvc, resp);</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fsm_inst_dispatch(bc->main_fi, MF_E_SRVC_CONFIG_BANK, (void *) pdu);</span><br><span>                 break;</span><br><span>       default:</span><br><span>             LOGPFSML(srvc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU type: %s\n",</span><br><span>@@ -101,7 +126,8 @@</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software)</span><br><span style="color: hsl(120, 100%, 40%);">+struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    struct client_config *cfg)</span><br><span> {</span><br><span>    struct bankd_client *bc = talloc_zero(ctx, struct bankd_client);</span><br><span>     struct rspro_server_conn *srvc, *bankdc;</span><br><span>@@ -110,10 +136,20 @@</span><br><span>     if (!bc)</span><br><span>             return NULL;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      bc->cfg = cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   bc->main_fi = main_fsm_alloc(bc, bc);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bc->main_fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+                fprintf(stderr, "Unable to create main client FSM: %s\n", strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+         exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   remsim_client_set_clslot(bc, cfg->client_id, cfg->client_slot);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      /* create and [attempt to] establish connection to remsim-server */</span><br><span>  srvc = &bc->srv_conn;</span><br><span style="color: hsl(0, 100%, 40%);">-    srvc->server_host = "localhost";</span><br><span style="color: hsl(0, 100%, 40%);">-   srvc->server_port = 9998;</span><br><span style="color: hsl(120, 100%, 40%);">+  srvc->server_host = cfg->server_host;</span><br><span style="color: hsl(120, 100%, 40%);">+   srvc->server_port = cfg->server_port;</span><br><span>  srvc->handle_rx = srvc_handle_rx;</span><br><span>         srvc->own_comp_id.type = ComponentType_remsimClient;</span><br><span>      OSMO_STRLCPY_ARRAY(srvc->own_comp_id.name, name);</span><br><span>@@ -125,6 +161,9 @@</span><br><span>           fprintf(stderr, "Unable to create Server conn FSM: %s\n", strerror(errno));</span><br><span>                exit(1);</span><br><span>     }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fsm_inst_change_parent(srvc->fi, bc->main_fi, MF_E_SRVC_LOST);</span><br><span style="color: hsl(120, 100%, 40%);">+     srvc->parent_conn_evt = MF_E_SRVC_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+       srvc->parent_disc_evt = MF_E_SRVC_LOST;</span><br><span> </span><br><span>       bankdc = &bc->bankd_conn;</span><br><span>     /* server_host / server_port are configured from remsim-server */</span><br><span>@@ -136,6 +175,9 @@</span><br><span>              exit(1);</span><br><span>     }</span><br><span>    osmo_fsm_inst_update_id(bankdc->fi, "bankd");</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_fsm_inst_change_parent(bankdc->fi, bc->main_fi, MF_E_BANKD_LOST);</span><br><span style="color: hsl(120, 100%, 40%);">+  bankdc->parent_conn_evt = MF_E_BANKD_CONNECTED;</span><br><span style="color: hsl(120, 100%, 40%);">+    bankdc->parent_disc_evt = MF_E_BANKD_LOST;</span><br><span> </span><br><span>    return bc;</span><br><span> }</span><br><span>diff --git a/src/client/remsim_client_main.c b/src/client/remsim_client_main.c</span><br><span>index 95eb089..6587e6b 100644</span><br><span>--- a/src/client/remsim_client_main.c</span><br><span>+++ b/src/client/remsim_client_main.c</span><br><span>@@ -23,27 +23,56 @@</span><br><span> {</span><br><span>  printf(</span><br><span>              "  -h --help                  Print this help message\n"</span><br><span style="color: hsl(120, 100%, 40%);">+            "  -v --version               Print program version\n"</span><br><span>             "  -i --server-ip A.B.C.D     remsim-server IP address\n"</span><br><span>          "  -p --server-port 13245     remsim-server TCP port\n"</span><br><span style="color: hsl(0, 100%, 40%);">-               "  -i --client-id <0-65535>   RSPRO ClientId of this client\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                "  -c --client-id <0-65535>   RSPRO ClientId of this client\n"</span><br><span>               "  -n --client-slot <0-65535> RSPRO SlotNr of this client\n"</span><br><span style="color: hsl(120, 100%, 40%);">+          "  -e --event-script <path>   event script to be called by client\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef USB_SUPPORT</span><br><span style="color: hsl(120, 100%, 40%);">+              "  -V --usb-vendor VENDOR_ID\n"</span><br><span style="color: hsl(120, 100%, 40%);">+             "  -P --usb-product PRODUCT_ID\n"</span><br><span style="color: hsl(120, 100%, 40%);">+           "  -C --usb-config CONFIG_ID\n"</span><br><span style="color: hsl(120, 100%, 40%);">+             "  -I --usb-interface INTERFACE_ID\n"</span><br><span style="color: hsl(120, 100%, 40%);">+               "  -S --usb-altsetting ALTSETTING_ID\n"</span><br><span style="color: hsl(120, 100%, 40%);">+             "  -A --usb-address ADDRESS\n"</span><br><span style="color: hsl(120, 100%, 40%);">+              "  -H --usb-path PATH\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>         );</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void handle_options(struct bankd_client *bc, int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_options(struct client_config *cfg, int argc, char **argv)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    while (1) {</span><br><span>          int option_index = 0, c;</span><br><span>             static const struct option long_options[] = {</span><br><span>                        { "help", 0, 0, 'h' },</span><br><span style="color: hsl(120, 100%, 40%);">+                      { "version", 0, 0, 'v' },</span><br><span>                  { "server-ip", 1, 0, 'i' },</span><br><span>                        { "server-port", 1, 0, 'p' },</span><br><span>                      { "client-id", 1, 0, 'c' },</span><br><span>                        { "client-slot", 1, 0, 'n' },</span><br><span style="color: hsl(120, 100%, 40%);">+                       { "atr", 1, 0, 'a' },</span><br><span style="color: hsl(120, 100%, 40%);">+                       { "event-script", 1, 0, 'e' },</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef USB_SUPPORT</span><br><span style="color: hsl(120, 100%, 40%);">+                  { "usb-vendor", 1, 0, 'V' },</span><br><span style="color: hsl(120, 100%, 40%);">+                        { "usb-product", 1, 0, 'P' },</span><br><span style="color: hsl(120, 100%, 40%);">+                       { "usb-config", 1, 0, 'C' },</span><br><span style="color: hsl(120, 100%, 40%);">+                        { "usb-interface", 1, 0, 'I' },</span><br><span style="color: hsl(120, 100%, 40%);">+                     { "usb-altsetting", 1, 0, 'S' },</span><br><span style="color: hsl(120, 100%, 40%);">+                    { "usb-address", 1, 0, 'A' },</span><br><span style="color: hsl(120, 100%, 40%);">+                       { "usb-path", 1, 0, 'H' },</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>                         { 0, 0, 0, 0 }</span><br><span>               };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-          c = getopt_long(argc, argv, "hi:p:c:n:",</span><br><span style="color: hsl(120, 100%, 40%);">+            c = getopt_long(argc, argv, "hvi:p:c:n:e:"</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef USB_SUPPORT</span><br><span style="color: hsl(120, 100%, 40%);">+                                              "V:P:C:I:S:A:H:"</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+                            ,</span><br><span>                            long_options, &option_index);</span><br><span>            if (c == -1)</span><br><span>                         break;</span><br><span>@@ -53,18 +82,55 @@</span><br><span>                         printf_help();</span><br><span>                       exit(0);</span><br><span>                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'v':</span><br><span style="color: hsl(120, 100%, 40%);">+                     printf("osmo-remsim-client version %s\n", VERSION);</span><br><span style="color: hsl(120, 100%, 40%);">+                 exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span>               case 'i':</span><br><span style="color: hsl(0, 100%, 40%);">-                       bc->srv_conn.server_host = optarg;</span><br><span style="color: hsl(120, 100%, 40%);">+                 osmo_talloc_replace_string(cfg, &cfg->server_host, optarg);</span><br><span>                   break;</span><br><span>               case 'p':</span><br><span style="color: hsl(0, 100%, 40%);">-                       bc->srv_conn.server_port = atoi(optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                   cfg->server_port = atoi(optarg);</span><br><span>                  break;</span><br><span>               case 'c':</span><br><span style="color: hsl(0, 100%, 40%);">-                       remsim_client_set_clslot(bc, atoi(optarg), -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                       cfg->client_id = atoi(optarg);</span><br><span>                    break;</span><br><span>               case 'n':</span><br><span style="color: hsl(0, 100%, 40%);">-                       remsim_client_set_clslot(bc, -1, atoi(optarg));</span><br><span style="color: hsl(120, 100%, 40%);">+                       cfg->client_slot = atoi(optarg);</span><br><span>                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'a':</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc = osmo_hexparse(optarg, cfg->atr.data, ARRAY_SIZE(cfg->atr.data));</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (rc < 2 || rc > ARRAY_SIZE(cfg->atr.data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              fprintf(stderr, "ATR malformed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                         exit(2);</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'e':</span><br><span style="color: hsl(120, 100%, 40%);">+                     osmo_talloc_replace_string(cfg, &cfg->event_script, optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                   break;</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef USB_SUPPORT</span><br><span style="color: hsl(120, 100%, 40%);">+            case 'V':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.vendor_id = strtol(optarg, NULL, 16);</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'P':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.product_id = strtol(optarg, NULL, 16);</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'C':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.config_id = atoi(optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'I':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.if_num = atoi(optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'S':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.altsetting = atoi(optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'A':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.addr = atoi(optarg);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 'H':</span><br><span style="color: hsl(120, 100%, 40%);">+                     cfg->usb.path = optarg;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span>               default:</span><br><span>                     break;</span><br><span>               }</span><br><span>@@ -74,6 +140,7 @@</span><br><span> int main(int argc, char **argv)</span><br><span> {</span><br><span>       struct bankd_client *g_client;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct client_config *cfg;</span><br><span>   char hostname[256];</span><br><span> </span><br><span>      gethostname(hostname, sizeof(hostname));</span><br><span>@@ -84,9 +151,11 @@</span><br><span> </span><br><span>   osmo_init_logging2(g_tall_ctx, &log_info);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      g_client = remsim_client_create(g_tall_ctx, hostname, "remsim-client");</span><br><span style="color: hsl(120, 100%, 40%);">+     cfg = client_config_init(g_tall_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+     handle_options(cfg, argc, argv);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    handle_options(g_client, argc, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+ g_client = remsim_client_create(g_tall_ctx, hostname, "remsim-client",cfg);</span><br><span> </span><br><span>    osmo_fsm_inst_dispatch(g_client->srv_conn.fi, SRVC_E_ESTABLISH, NULL);</span><br><span> </span><br><span>diff --git a/src/client/simtrace2-remsim_client.c b/src/client/simtrace2-remsim_client.c</span><br><span>deleted file mode 100644</span><br><span>index e495f10..0000000</span><br><span>--- a/src/client/simtrace2-remsim_client.c</span><br><span>+++ /dev/null</span><br><span>@@ -1,1284 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-/* (C) 2018-2020 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(0, 100%, 40%);">- * (C) 2018 by sysmocom - s.f.m.c. GmbH, Author: Kevin Redon</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * All Rights Reserved</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(0, 100%, 40%);">- * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(0, 100%, 40%);">- * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(0, 100%, 40%);">- * (at your option) any later version.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(0, 100%, 40%);">- * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(0, 100%, 40%);">- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(0, 100%, 40%);">- * GNU General Public License for more details.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(0, 100%, 40%);">- * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(0, 100%, 40%);">- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <errno.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <string.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <talloc.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/msgb.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/fsm.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/utils.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/logging.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/application.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/exec.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/abis/ipa.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/gsm/protocol/ipaccess.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include "rspro_util.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "client.h"</span><br><span style="color: hsl(0, 100%, 40%);">-#include "debug.h"</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <unistd.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <stdio.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <linux/limits.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <sys/stat.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <fcntl.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <signal.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <getopt.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <libusb.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/usb/libusb.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/simtrace2/simtrace_prot.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/simtrace2/simtrace_usb.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/simtrace2/apdu_dispatch.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/gsmtap.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/gsmtap_util.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/utils.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/socket.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/core/msgb.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/sim/class_tables.h></span><br><span style="color: hsl(0, 100%, 40%);">-#include <osmocom/sim/sim.h></span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* transport to a SIMtrace device */</span><br><span style="color: hsl(0, 100%, 40%);">-struct st_transport {</span><br><span style="color: hsl(0, 100%, 40%);">-     /* USB */</span><br><span style="color: hsl(0, 100%, 40%);">-       struct libusb_device_handle *usb_devh;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct {</span><br><span style="color: hsl(0, 100%, 40%);">-                uint8_t in;</span><br><span style="color: hsl(0, 100%, 40%);">-             uint8_t out;</span><br><span style="color: hsl(0, 100%, 40%);">-            uint8_t irq_in;</span><br><span style="color: hsl(0, 100%, 40%);">- } usb_ep;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* a SIMtrace slot; communicates over a transport */</span><br><span style="color: hsl(0, 100%, 40%);">-struct st_slot {</span><br><span style="color: hsl(0, 100%, 40%);">- /* transport through which the slot can be reached */</span><br><span style="color: hsl(0, 100%, 40%);">-   struct st_transport *transp;</span><br><span style="color: hsl(0, 100%, 40%);">-    /* number of the slot within the transport */</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t slot_nr;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* One istance of card emulation */</span><br><span style="color: hsl(0, 100%, 40%);">-struct cardem_inst {</span><br><span style="color: hsl(0, 100%, 40%);">-       /* slot on which this card emulation instance runs */</span><br><span style="color: hsl(0, 100%, 40%);">-   struct st_slot *slot;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct cardemu_usb_msg_status last_status;</span><br><span style="color: hsl(0, 100%, 40%);">-      char *usb_path;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* global GSMTAP instance */</span><br><span style="color: hsl(0, 100%, 40%);">-static struct gsmtap_inst *g_gti;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-struct bankd_client *g_client;</span><br><span style="color: hsl(0, 100%, 40%);">-static void *g_tall_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-void __thread *talloc_asn1_ctx;</span><br><span style="color: hsl(0, 100%, 40%);">-int asn_debug;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* should we leave main loop processing? */</span><br><span style="color: hsl(0, 100%, 40%);">-bool g_leave_main = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-__attribute__((unused)) static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct gsmtap_hdr *gh;</span><br><span style="color: hsl(0, 100%, 40%);">-  unsigned int gross_len = len + sizeof(*gh);</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t *buf = malloc(gross_len);</span><br><span style="color: hsl(0, 100%, 40%);">-       int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!buf)</span><br><span style="color: hsl(0, 100%, 40%);">-               return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- memset(buf, 0, sizeof(*gh));</span><br><span style="color: hsl(0, 100%, 40%);">-    gh = (struct gsmtap_hdr *) buf;</span><br><span style="color: hsl(0, 100%, 40%);">- gh->version = GSMTAP_VERSION;</span><br><span style="color: hsl(0, 100%, 40%);">-        gh->hdr_len = sizeof(*gh)/4;</span><br><span style="color: hsl(0, 100%, 40%);">- gh->type = GSMTAP_TYPE_SIM;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  memcpy(buf + sizeof(*gh), apdu, len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   rc = write(gsmtap_inst_fd(g_gti), buf, gross_len);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                perror("write gsmtap");</span><br><span style="color: hsl(0, 100%, 40%);">-               free(buf);</span><br><span style="color: hsl(0, 100%, 40%);">-              return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       free(buf);</span><br><span style="color: hsl(0, 100%, 40%);">-      return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* build the (additional) environment for executing a script */</span><br><span style="color: hsl(0, 100%, 40%);">-static char **build_script_env(struct bankd_client *clnt, const char *cause)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct cardem_inst *ci = clnt->cardem;</span><br><span style="color: hsl(0, 100%, 40%);">-       char **env = talloc_zero_size(clnt, 256*sizeof(char *));</span><br><span style="color: hsl(0, 100%, 40%);">-        int i = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!env)</span><br><span style="color: hsl(0, 100%, 40%);">-               return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_VERSION=%s", VERSION);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- env[i++] = talloc_asprintf(env, "REMSIM_SERVER_ADDR=%s:%u",</span><br><span style="color: hsl(0, 100%, 40%);">-                              clnt->srv_conn.server_host, clnt->srv_conn.server_port);</span><br><span style="color: hsl(0, 100%, 40%);">-       env[i++] = talloc_asprintf(env, "REMSIM_SERVER_STATE=%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                                osmo_fsm_inst_state_name(clnt->srv_conn.fi));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     env[i++] = talloc_asprintf(env, "REMSIM_BANKD_ADDR=%s:%u",</span><br><span style="color: hsl(0, 100%, 40%);">-                               clnt->bankd_conn.server_host, clnt->bankd_conn.server_port);</span><br><span style="color: hsl(0, 100%, 40%);">-   env[i++] = talloc_asprintf(env, "REMSIM_BANKD_STATE=%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                                 osmo_fsm_inst_state_name(clnt->bankd_conn.fi));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (clnt->srv_conn.clslot) {</span><br><span style="color: hsl(0, 100%, 40%);">-         env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_SLOT=%lu:%lu",</span><br><span style="color: hsl(0, 100%, 40%);">-                                    g_client->srv_conn.clslot->clientId,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      g_client->srv_conn.clslot->slotNr);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-       env[i++] = talloc_asprintf(env, "REMSIM_BANKD_SLOT=%u:%u",</span><br><span style="color: hsl(0, 100%, 40%);">-                               clnt->bankd_slot.bank_id, clnt->bankd_slot.slot_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   env[i++] = talloc_asprintf(env, "REMSIM_USB_PATH=%s", ci->usb_path);</span><br><span style="color: hsl(0, 100%, 40%);">-       env[i++] = talloc_asprintf(env, "REMSIM_USB_INTERFACE=%u", clnt->cfg->usb.if_num);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* TODO: SIM card state VCC/CLK/RST */</span><br><span style="color: hsl(0, 100%, 40%);">-  env[i++] = talloc_asprintf(env, "REMSIM_SIM_VCC=%u",</span><br><span style="color: hsl(0, 100%, 40%);">-                             !!(ci->last_status.flags & CEMU_STATUS_F_VCC_PRESENT));</span><br><span style="color: hsl(0, 100%, 40%);">-       env[i++] = talloc_asprintf(env, "REMSIM_SIM_RST=%u",</span><br><span style="color: hsl(0, 100%, 40%);">-                             !!(ci->last_status.flags & CEMU_STATUS_F_RESET_ACTIVE));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      env[i++] = talloc_asprintf(env, "REMSIM_CAUSE=%s", cause);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* terminate last entry */</span><br><span style="color: hsl(0, 100%, 40%);">-      env[i++] = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-        return env;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int call_script(struct bankd_client *clnt, const char *cause)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       char **env, *cmd;</span><br><span style="color: hsl(0, 100%, 40%);">-       int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!clnt->cfg->event_script)</span><br><span style="color: hsl(0, 100%, 40%);">-             return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       env = build_script_env(clnt, cause);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!env)</span><br><span style="color: hsl(0, 100%, 40%);">-               return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- cmd = talloc_asprintf(env, "%s %s", clnt->cfg->event_script, cause);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!cmd) {</span><br><span style="color: hsl(0, 100%, 40%);">-             talloc_free(env);</span><br><span style="color: hsl(0, 100%, 40%);">-               return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = osmo_system_nowait(cmd, osmo_environment_whitelist, env);</span><br><span style="color: hsl(0, 100%, 40%);">-  talloc_free(env);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * SIMTRACE core protocol</span><br><span style="color: hsl(0, 100%, 40%);">- ***********************************************************************/</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief allocate a message buffer for simtrace use */</span><br><span style="color: hsl(0, 100%, 40%);">-static struct msgb *st_msgb_alloc(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   return msgb_alloc_headroom(1024+32, 32, "SIMtrace");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">-static void apdu_out_cb(uint8_t *buf, unsigned int len, void *user_data)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   printf("APDU: %s\n", osmo_hexdump(buf, len));</span><br><span style="color: hsl(0, 100%, 40%);">- gsmtap_send_sim(buf, len);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void usb_out_xfer_cb(struct libusb_transfer *xfer)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct msgb *msg = xfer->user_data;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  switch (xfer->status) {</span><br><span style="color: hsl(0, 100%, 40%);">-      case LIBUSB_TRANSFER_COMPLETED:</span><br><span style="color: hsl(0, 100%, 40%);">-         break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case LIBUSB_TRANSFER_NO_DEVICE:</span><br><span style="color: hsl(0, 100%, 40%);">-         fprintf(stderr, "USB device disappeared\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          g_leave_main = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "USB OUT transfer failed, status=%u\n", xfer->status);</span><br><span style="color: hsl(0, 100%, 40%);">-             g_leave_main = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       msgb_free(msg);</span><br><span style="color: hsl(0, 100%, 40%);">- libusb_free_transfer(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Transmit a given command to the SIMtrace2 device */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_transp_tx_msg(struct st_transport *transp, struct msgb *msg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct libusb_transfer *xfer;</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("SIMtrace <- %s\n", msgb_hexdump(msg));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     xfer = libusb_alloc_transfer(0);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->dev_handle = transp->usb_devh;</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->flags = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     xfer->type = LIBUSB_TRANSFER_TYPE_BULK;</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->endpoint = transp->usb_ep.out;</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->timeout = 1000;</span><br><span style="color: hsl(0, 100%, 40%);">-        xfer->user_data = msg;</span><br><span style="color: hsl(0, 100%, 40%);">-       xfer->length = msgb_length(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-     xfer->buffer = msgb_data(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-       xfer->callback = usb_out_xfer_cb;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* submit the OUT transfer */</span><br><span style="color: hsl(0, 100%, 40%);">-   rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct simtrace_msg_hdr *st_push_hdr(struct msgb *msg, uint8_t msg_class, uint8_t msg_type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       uint8_t slot_nr)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   struct simtrace_msg_hdr *sh;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    sh = (struct simtrace_msg_hdr *) msgb_push(msg, sizeof(*sh));</span><br><span style="color: hsl(0, 100%, 40%);">-   memset(sh, 0, sizeof(*sh));</span><br><span style="color: hsl(0, 100%, 40%);">-     sh->msg_class = msg_class;</span><br><span style="color: hsl(0, 100%, 40%);">-   sh->msg_type = msg_type;</span><br><span style="color: hsl(0, 100%, 40%);">-     sh->slot_nr = slot_nr;</span><br><span style="color: hsl(0, 100%, 40%);">-       sh->msg_len = msgb_length(msg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      return sh;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* transmit a given message to a specified slot. Expects all headers</span><br><span style="color: hsl(0, 100%, 40%);">- * present before calling the function */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_slot_tx_msg(struct st_slot *slot, struct msgb *msg,</span><br><span style="color: hsl(0, 100%, 40%);">-                 uint8_t msg_class, uint8_t msg_type)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        st_push_hdr(msg, msg_class, msg_type, slot->slot_nr);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        return st_transp_tx_msg(slot->transp, msg);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * Card Emulation protocol</span><br><span style="color: hsl(0, 100%, 40%);">- ***********************************************************************/</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Request the SIMtrace2 to generate a card-insert signal */</span><br><span style="color: hsl(0, 100%, 40%);">-static int cardem_request_card_insert(struct cardem_inst *ci, bool inserted)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct cardemu_usb_msg_cardinsert *cins;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        cins = (struct cardemu_usb_msg_cardinsert *) msgb_put(msg, sizeof(*cins));</span><br><span style="color: hsl(0, 100%, 40%);">-      memset(cins, 0, sizeof(*cins));</span><br><span style="color: hsl(0, 100%, 40%);">- if (inserted)</span><br><span style="color: hsl(0, 100%, 40%);">-           cins->card_insert = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_CARDINSERT);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Rx */</span><br><span style="color: hsl(0, 100%, 40%);">-static int cardem_request_pb_and_rx(struct cardem_inst *ci, uint8_t pb, uint8_t le)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct cardemu_usb_msg_tx_data *txd;</span><br><span style="color: hsl(0, 100%, 40%);">-    txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   printf("SIMtrace <= %s(%02x, %d)\n", __func__, pb, le);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    memset(txd, 0, sizeof(*txd));</span><br><span style="color: hsl(0, 100%, 40%);">-   txd->data_len = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-   txd->flags = CEMU_DATA_F_PB_AND_RX;</span><br><span style="color: hsl(0, 100%, 40%);">-  /* one data byte */</span><br><span style="color: hsl(0, 100%, 40%);">-     msgb_put_u8(msg, pb);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */</span><br><span style="color: hsl(0, 100%, 40%);">-static int cardem_request_pb_and_tx(struct cardem_inst *ci, uint8_t pb,</span><br><span style="color: hsl(0, 100%, 40%);">-                              const uint8_t *data, uint16_t data_len_in)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct cardemu_usb_msg_tx_data *txd;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t *cur;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   printf("SIMtrace <= %s(%02x, %s, %d)\n", __func__, pb,</span><br><span style="color: hsl(0, 100%, 40%);">-             osmo_hexdump(data, data_len_in), data_len_in);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  memset(txd, 0, sizeof(*txd));</span><br><span style="color: hsl(0, 100%, 40%);">-   txd->data_len = 1 + data_len_in;</span><br><span style="color: hsl(0, 100%, 40%);">-     txd->flags = CEMU_DATA_F_PB_AND_TX;</span><br><span style="color: hsl(0, 100%, 40%);">-  /* procedure byte */</span><br><span style="color: hsl(0, 100%, 40%);">-    msgb_put_u8(msg, pb);</span><br><span style="color: hsl(0, 100%, 40%);">-   /* data */</span><br><span style="color: hsl(0, 100%, 40%);">-      cur = msgb_put(msg, data_len_in);</span><br><span style="color: hsl(0, 100%, 40%);">-       memcpy(cur, data, data_len_in);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Request the SIMtrace2 to send a Status Word */</span><br><span style="color: hsl(0, 100%, 40%);">-static int cardem_request_sw_tx(struct cardem_inst *ci, const uint8_t *sw)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct cardemu_usb_msg_tx_data *txd;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint8_t *cur;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   printf("SIMtrace <= %s(%02x %02x)\n", __func__, sw[0], sw[1]);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     memset(txd, 0, sizeof(*txd));</span><br><span style="color: hsl(0, 100%, 40%);">-   txd->data_len = 2;</span><br><span style="color: hsl(0, 100%, 40%);">-   txd->flags = CEMU_DATA_F_PB_AND_TX | CEMU_DATA_F_FINAL;</span><br><span style="color: hsl(0, 100%, 40%);">-      cur = msgb_put(msg, 2);</span><br><span style="color: hsl(0, 100%, 40%);">- cur[0] = sw[0];</span><br><span style="color: hsl(0, 100%, 40%);">- cur[1] = sw[1];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Request the SIMtrace2 to send a Status Word */</span><br><span style="color: hsl(0, 100%, 40%);">-static int cardem_request_config(struct cardem_inst *ci, uint32_t features)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct cardemu_usb_msg_config *cfg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg = (struct cardemu_usb_msg_config *) msgb_put(msg, sizeof(*cfg));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    printf("SIMtrace <= %s(%08x)\n", __func__, features);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      memset(cfg, 0, sizeof(*cfg));</span><br><span style="color: hsl(0, 100%, 40%);">-   cfg->features = features;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_BD_CEMU_CONFIG);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-// FIXME check if the ATR actually includes a checksum</span><br><span style="color: hsl(0, 100%, 40%);">-__attribute__((unused)) static void atr_update_csum(uint8_t *atr, unsigned int atr_len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     uint8_t csum = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       int i;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  for (i = 1; i < atr_len - 1; i++)</span><br><span style="color: hsl(0, 100%, 40%);">-            csum = csum ^ atr[i];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   atr[atr_len-1] = csum;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int cardem_request_set_atr(struct cardem_inst *ci, const uint8_t *atr, unsigned int atr_len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct cardemu_usb_msg_set_atr *satr;</span><br><span style="color: hsl(0, 100%, 40%);">-   uint8_t *cur;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   satr = (struct cardemu_usb_msg_set_atr *) msgb_put(msg, sizeof(*satr));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("SIMtrace <= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      memset(satr, 0, sizeof(*satr));</span><br><span style="color: hsl(0, 100%, 40%);">- satr->atr_len = atr_len;</span><br><span style="color: hsl(0, 100%, 40%);">-     cur = msgb_put(msg, atr_len);</span><br><span style="color: hsl(0, 100%, 40%);">-   memcpy(cur, atr, atr_len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * Modem Control protocol</span><br><span style="color: hsl(0, 100%, 40%);">- ***********************************************************************/</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int _modem_reset(struct st_slot *slot, uint8_t asserted, uint16_t pulse_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct st_modem_reset *sr ;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     sr = (struct st_modem_reset *) msgb_put(msg, sizeof(*sr));</span><br><span style="color: hsl(0, 100%, 40%);">-      sr->asserted = asserted;</span><br><span style="color: hsl(0, 100%, 40%);">-     sr->pulse_duration_msec = pulse_ms;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_RESET);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief pulse the RESET line of the modem for \a duration_ms milli-seconds*/</span><br><span style="color: hsl(0, 100%, 40%);">-int st_modem_reset_pulse(struct st_slot *slot, uint16_t duration_ms)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       return _modem_reset(slot, 2, duration_ms);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief assert the RESET line of the modem */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_modem_reset_active(struct st_slot *slot)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     return _modem_reset(slot, 1, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief de-assert the RESET line of the modem */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_modem_reset_inactive(struct st_slot *slot)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  return _modem_reset(slot, 0, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int _modem_sim_select(struct st_slot *slot, uint8_t remote_sim)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-     struct st_modem_sim_select *ss;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ss = (struct st_modem_sim_select *) msgb_put(msg, sizeof(*ss));</span><br><span style="color: hsl(0, 100%, 40%);">- ss->remote_sim = remote_sim;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_SIM_SELECT);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief select local (physical) SIM for given slot */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_modem_sim_select_local(struct st_slot *slot)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  return _modem_sim_select(slot, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief select remote (emulated/forwarded) SIM for given slot */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_modem_sim_select_remote(struct st_slot *slot)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     return _modem_sim_select(slot, 1);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Request slot to send us status information about the modem */</span><br><span style="color: hsl(0, 100%, 40%);">-int st_modem_get_status(struct st_slot *slot)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct msgb *msg = st_msgb_alloc();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_BD_MODEM_STATUS);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * Incoming Messages</span><br><span style="color: hsl(0, 100%, 40%);">- ***********************************************************************/</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Process a STATUS message from the SIMtrace2 */</span><br><span style="color: hsl(0, 100%, 40%);">-static int process_do_status(struct cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct cardemu_usb_msg_status *status;</span><br><span style="color: hsl(0, 100%, 40%);">-  status = (struct cardemu_usb_msg_status *) buf;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("SIMtrace => STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-           status->flags, status->fi, status->di, status->wi,</span><br><span style="color: hsl(0, 100%, 40%);">-          status->waiting_time);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Process a PTS indication message from the SIMtrace2 */</span><br><span style="color: hsl(0, 100%, 40%);">-static int process_do_pts(struct cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct cardemu_usb_msg_pts_info *pts;</span><br><span style="color: hsl(0, 100%, 40%);">-   pts = (struct cardemu_usb_msg_pts_info *) buf;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  printf("SIMtrace => PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req)));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Process a ERROR indication message from the SIMtrace2 */</span><br><span style="color: hsl(0, 100%, 40%);">-__attribute__((unused)) static int process_do_error(struct cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct cardemu_usb_msg_error *err;</span><br><span style="color: hsl(0, 100%, 40%);">-      err = (struct cardemu_usb_msg_error *) buf;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     printf("SIMtrace => ERROR: %u/%u/%u: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                err->severity, err->subsystem, err->code,</span><br><span style="color: hsl(0, 100%, 40%);">-              err->msg_len ? (char *)err->msg : "");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct osmo_apdu_context ac; // this will hold the complete APDU (across calls)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Process a RX-DATA indication message from the SIMtrace2 */</span><br><span style="color: hsl(0, 100%, 40%);">-static int process_do_rx_da(struct cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct cardemu_usb_msg_rx_data *data = (struct cardemu_usb_msg_rx_data *) buf; // cast the data from the USB message</span><br><span style="color: hsl(0, 100%, 40%);">-    int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("SIMtrace => DATA: flags=%x, %s: ", data->flags,</span><br><span style="color: hsl(0, 100%, 40%);">-         osmo_hexdump(data->data, data->data_len));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        rc = osmo_apdu_segment_in(&ac, data->data, data->data_len,</span><br><span style="color: hsl(0, 100%, 40%);">-                              data->flags & CEMU_DATA_F_TPDU_HDR); // parse the APDU data in the USB message</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (rc & APDU_ACT_TX_CAPDU_TO_CARD) { // there is no pending data coming from the modem</span><br><span style="color: hsl(0, 100%, 40%);">-             uint8_t apdu_command[sizeof(ac.hdr) + ac.lc.tot]; // to store the APDU command to send</span><br><span style="color: hsl(0, 100%, 40%);">-          memcpy(apdu_command, &ac.hdr, sizeof(ac.hdr)); // copy APDU command header</span><br><span style="color: hsl(0, 100%, 40%);">-          if (ac.lc.tot) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        memcpy(apdu_command + sizeof(ac.hdr), ac.dc, ac.lc.tot); // copy APDU command data </span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-               // send APDU to card</span><br><span style="color: hsl(0, 100%, 40%);">-            BankSlot_t bslot;</span><br><span style="color: hsl(0, 100%, 40%);">-               bank_slot2rspro(&bslot, &g_client->bankd_slot);</span><br><span style="color: hsl(0, 100%, 40%);">-              RsproPDU_t *pdu = rspro_gen_TpduModem2Card(g_client->srv_conn.clslot, &bslot, apdu_command, sizeof(ac.hdr) + ac.lc.tot); // create RSPRO packet</span><br><span style="color: hsl(0, 100%, 40%);">-          server_conn_send_rspro(&g_client->bankd_conn, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-              // the response will come separately</span><br><span style="color: hsl(0, 100%, 40%);">-    } else if (ac.lc.tot > ac.lc.cur) { // there is pending data from the modem</span><br><span style="color: hsl(0, 100%, 40%);">-          cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur); // send procedure byte to get remaining data</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">- case SIMTRACE_CMD_DO_ERROR</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = process_do_error(ci, buf, len);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Process an incoming message from the SIMtrace2 */</span><br><span style="color: hsl(0, 100%, 40%);">-static int process_usb_msg(struct cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("SIMtrace -> %s\n", osmo_hexdump(buf, len));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        buf += sizeof(*sh);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     switch (sh->msg_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-      case SIMTRACE_MSGT_BD_CEMU_STATUS:</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = process_do_status(ci, buf, len);</span><br><span style="color: hsl(0, 100%, 40%);">-           break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case SIMTRACE_MSGT_DO_CEMU_PTS:</span><br><span style="color: hsl(0, 100%, 40%);">-         rc = process_do_pts(ci, buf, len);</span><br><span style="color: hsl(0, 100%, 40%);">-              break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case SIMTRACE_MSGT_DO_CEMU_RX_DATA:</span><br><span style="color: hsl(0, 100%, 40%);">-             rc = process_do_rx_da(ci, buf, len);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case SIMTRACE_MSGT_BD_CEMU_CONFIG:</span><br><span style="color: hsl(0, 100%, 40%);">-              /* firmware confirms configuration change; ignore */</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */</span><br><span style="color: hsl(0, 100%, 40%);">-static int process_irq_status(struct cardem_inst *ci, const uint8_t *buf, int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    printf("SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-             status->flags, status->fi, status->di, status->wi,</span><br><span style="color: hsl(0, 100%, 40%);">-          status->waiting_time);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       BankSlot_t bslot;</span><br><span style="color: hsl(0, 100%, 40%);">-       bank_slot2rspro(&bslot, &g_client->bankd_slot);</span><br><span style="color: hsl(0, 100%, 40%);">-      RsproPDU_t *pdu = rspro_gen_ClientSlotStatusInd(g_client->srv_conn.clslot, &bslot,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                       status->flags & CEMU_STATUS_F_RESET_ACTIVE,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                      status->flags & CEMU_STATUS_F_VCC_PRESENT,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                       status->flags & CEMU_STATUS_F_CLK_ACTIVE,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                        -1 /* FIXME: make this dependent on board */);</span><br><span style="color: hsl(0, 100%, 40%);">-  server_conn_send_rspro(&g_client->bankd_conn, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if (ci->last_status.flags != status->flags) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ci->last_status = *status;</span><br><span style="color: hsl(0, 100%, 40%);">-           call_script(g_client, "event-modem-status");</span><br><span style="color: hsl(0, 100%, 40%);">-  } else</span><br><span style="color: hsl(0, 100%, 40%);">-          ci->last_status = *status;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int process_usb_msg_irq(struct cardem_inst *ci, const uint8_t *buf, unsigned int len)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("SIMtrace IRQ %s\n", osmo_hexdump(buf, len));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  buf += sizeof(*sh);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     switch (sh->msg_type) {</span><br><span style="color: hsl(0, 100%, 40%);">-      case SIMTRACE_MSGT_BD_CEMU_STATUS:</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = process_irq_status(ci, buf, len);</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return rc;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void usb_in_xfer_cb(struct libusb_transfer *xfer)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct cardem_inst *ci = xfer->user_data;</span><br><span style="color: hsl(0, 100%, 40%);">-    int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (xfer->status) {</span><br><span style="color: hsl(0, 100%, 40%);">-      case LIBUSB_TRANSFER_COMPLETED:</span><br><span style="color: hsl(0, 100%, 40%);">-         /* hand the message up the stack */</span><br><span style="color: hsl(0, 100%, 40%);">-             process_usb_msg(ci, xfer->buffer, xfer->actual_length);</span><br><span style="color: hsl(0, 100%, 40%);">-           break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case LIBUSB_TRANSFER_NO_DEVICE:</span><br><span style="color: hsl(0, 100%, 40%);">-         fprintf(stderr, "USB device disappeared\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          g_leave_main = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "USB IN transfer failed, status=%u\n", xfer->status);</span><br><span style="color: hsl(0, 100%, 40%);">-              g_leave_main = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* re-submit the IN transfer */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void allocate_and_submit_in(struct cardem_inst *ci)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       struct st_transport *transp = ci->slot->transp;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct libusb_transfer *xfer;</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- xfer = libusb_alloc_transfer(0);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->dev_handle = transp->usb_devh;</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->flags = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     xfer->type = LIBUSB_TRANSFER_TYPE_BULK;</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->endpoint = transp->usb_ep.in;</span><br><span style="color: hsl(0, 100%, 40%);">-       xfer->timeout = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-   xfer->user_data = ci;</span><br><span style="color: hsl(0, 100%, 40%);">-        xfer->length = 16*256;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(xfer->buffer);</span><br><span style="color: hsl(0, 100%, 40%);">-   xfer->callback = usb_in_xfer_cb;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     /* submit the IN transfer */</span><br><span style="color: hsl(0, 100%, 40%);">-    rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void usb_irq_xfer_cb(struct libusb_transfer *xfer)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        struct cardem_inst *ci = xfer->user_data;</span><br><span style="color: hsl(0, 100%, 40%);">-    int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- switch (xfer->status) {</span><br><span style="color: hsl(0, 100%, 40%);">-      case LIBUSB_TRANSFER_COMPLETED:</span><br><span style="color: hsl(0, 100%, 40%);">-         process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length);</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case LIBUSB_TRANSFER_NO_DEVICE:</span><br><span style="color: hsl(0, 100%, 40%);">-         fprintf(stderr, "USB device disappeared\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          g_leave_main = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "USB IRQ transfer failed, status=%u\n", xfer->status);</span><br><span style="color: hsl(0, 100%, 40%);">-             g_leave_main = true;</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* re-submit the IN transfer */</span><br><span style="color: hsl(0, 100%, 40%);">- rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void allocate_and_submit_irq(struct cardem_inst *ci)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      struct st_transport *transp = ci->slot->transp;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct libusb_transfer *xfer;</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- xfer = libusb_alloc_transfer(0);</span><br><span style="color: hsl(0, 100%, 40%);">-        OSMO_ASSERT(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->dev_handle = transp->usb_devh;</span><br><span style="color: hsl(0, 100%, 40%);">-      xfer->flags = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;</span><br><span style="color: hsl(0, 100%, 40%);">- xfer->endpoint = transp->usb_ep.irq_in;</span><br><span style="color: hsl(0, 100%, 40%);">-   xfer->timeout = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-   xfer->user_data = ci;</span><br><span style="color: hsl(0, 100%, 40%);">-        xfer->length = 64;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(xfer->buffer);</span><br><span style="color: hsl(0, 100%, 40%);">-   xfer->callback = usb_irq_xfer_cb;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* submit the IN transfer */</span><br><span style="color: hsl(0, 100%, 40%);">-    rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct st_transport _transp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct st_slot _slot = {</span><br><span style="color: hsl(0, 100%, 40%);">-        .transp = &_transp,</span><br><span style="color: hsl(0, 100%, 40%);">- .slot_nr = 0,</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct cardem_inst *g_ci;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void signal_handler(int signal)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  switch (signal) {</span><br><span style="color: hsl(0, 100%, 40%);">-       case SIGINT:</span><br><span style="color: hsl(0, 100%, 40%);">-            cardem_request_card_insert(g_ci, false);</span><br><span style="color: hsl(0, 100%, 40%);">-                exit(0);</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/** remsim_client **/</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  const struct TpduCardToModem *card2modem = &pdu->msg.choice.tpduCardToModem;</span><br><span style="color: hsl(0, 100%, 40%);">-     if (card2modem->data.size < 2) { // at least the two SW bytes are needed</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       // save SW to our current APDU context</span><br><span style="color: hsl(0, 100%, 40%);">-  ac.sw[0] = card2modem->data.buf[card2modem->data.size - 2];</span><br><span style="color: hsl(0, 100%, 40%);">-       ac.sw[1] = card2modem->data.buf[card2modem->data.size - 1];</span><br><span style="color: hsl(0, 100%, 40%);">-       printf("SIMtrace <= SW=0x%02x%02x, len_rx=%d\n", ac.sw[0], ac.sw[1], card2modem->data.size - 2);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (card2modem->data.size > 2) { // send PB and data to modem</span><br><span style="color: hsl(0, 100%, 40%);">-             cardem_request_pb_and_tx(bc->cardem, ac.hdr.ins, card2modem->data.buf, card2modem->data.size - 2);</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-       cardem_request_sw_tx(bc->cardem, ac.sw); // send SW to modem</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    RsproPDU_t *resp;</span><br><span style="color: hsl(0, 100%, 40%);">-       int rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* FIXME: is this permitted at any time by the SIMtrace2 cardemfirmware? */</span><br><span style="color: hsl(0, 100%, 40%);">-     rc = cardem_request_set_atr(bc->cardem, pdu->msg.choice.setAtrReq.atr.buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    pdu->msg.choice.setAtrReq.atr.size);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (rc == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-            resp = rspro_gen_SetAtrRes(ResultCode_ok);</span><br><span style="color: hsl(0, 100%, 40%);">-      else</span><br><span style="color: hsl(0, 100%, 40%);">-            resp = rspro_gen_SetAtrRes(ResultCode_cardTransmissionError);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!resp)</span><br><span style="color: hsl(0, 100%, 40%);">-              return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- server_conn_send_rspro(&g_client->bankd_conn, resp);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* handle incoming message from bankd */</span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  switch (pdu->msg.present) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_connectClientRes:</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Store 'identity' of bankd to in peer_comp_id */</span><br><span style="color: hsl(0, 100%, 40%);">-              rspro_comp_id_retrieve(&bankdc->peer_comp_id, &pdu->msg.choice.connectClientRes.identity);</span><br><span style="color: hsl(0, 100%, 40%);">-                osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-            call_script(g_client, "event-bankd-connect");</span><br><span style="color: hsl(0, 100%, 40%);">-         break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_tpduCardToModem: // APDU response from card received</span><br><span style="color: hsl(0, 100%, 40%);">-             bankd_handle_tpduCardToModem(g_client, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_setAtrReq:</span><br><span style="color: hsl(0, 100%, 40%);">-               bankd_handle_setAtrReq(g_client, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGPFSML(bankdc->fi, LOGL_ERROR, "Unknown/Unsuppoerted RSPRO PDU %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                     rspro_msgt_name(pdu));</span><br><span style="color: hsl(0, 100%, 40%);">-         return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* handle incoming messages from server */</span><br><span style="color: hsl(0, 100%, 40%);">-static int srvc_handle_rx(struct rspro_server_conn *srvc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   RsproPDU_t  *resp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      switch (pdu->msg.present) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_connectClientRes:</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Store 'identity' of server in srvc->peer_comp_id */</span><br><span style="color: hsl(0, 100%, 40%);">-               rspro_comp_id_retrieve(&srvc->peer_comp_id, &pdu->msg.choice.connectClientRes.identity);</span><br><span style="color: hsl(0, 100%, 40%);">-          osmo_fsm_inst_dispatch(srvc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-              call_script(g_client, "event-server-connect");</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_configClientIdReq:</span><br><span style="color: hsl(0, 100%, 40%);">-               /* store/set the clientID as instructed by the server */</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!g_client->srv_conn.clslot)</span><br><span style="color: hsl(0, 100%, 40%);">-                      g_client->srv_conn.clslot = talloc_zero(g_client, ClientSlot_t);</span><br><span style="color: hsl(0, 100%, 40%);">-             *g_client->srv_conn.clslot = pdu->msg.choice.configClientIdReq.clientSlot;</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!g_client->bankd_conn.clslot)</span><br><span style="color: hsl(0, 100%, 40%);">-                    g_client->bankd_conn.clslot = talloc_zero(g_client, ClientSlot_t);</span><br><span style="color: hsl(0, 100%, 40%);">-           *g_client->bankd_conn.clslot = *g_client->srv_conn.clslot;</span><br><span style="color: hsl(0, 100%, 40%);">-                /* send response to server */</span><br><span style="color: hsl(0, 100%, 40%);">-           resp = rspro_gen_ConfigClientIdRes(ResultCode_ok);</span><br><span style="color: hsl(0, 100%, 40%);">-              server_conn_send_rspro(srvc, resp);</span><br><span style="color: hsl(0, 100%, 40%);">-             break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_configClientBankReq:</span><br><span style="color: hsl(0, 100%, 40%);">-             /* store/set the bankd ip/port as instructed by the server */</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_talloc_replace_string(g_client, &g_client->bankd_conn.server_host,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     rspro_IpAddr2str(&pdu->msg.choice.configClientBankReq.bankd.ip));</span><br><span style="color: hsl(0, 100%, 40%);">-             rspro2bank_slot(&g_client->bankd_slot, &pdu->msg.choice.configClientBankReq.bankSlot);</span><br><span style="color: hsl(0, 100%, 40%);">-            g_client->bankd_conn.server_port = pdu->msg.choice.configClientBankReq.bankd.port;</span><br><span style="color: hsl(0, 100%, 40%);">-                /* bankd port 0 is a magic value to indicate "no bankd" */</span><br><span style="color: hsl(0, 100%, 40%);">-            if (g_client->bankd_conn.server_port == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                   osmo_fsm_inst_dispatch(g_client->bankd_conn.fi, SRVC_E_DISCONNECT, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-            else</span><br><span style="color: hsl(0, 100%, 40%);">-                    osmo_fsm_inst_dispatch(g_client->bankd_conn.fi, SRVC_E_ESTABLISH, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-             /* send response to server */</span><br><span style="color: hsl(0, 100%, 40%);">-           resp = rspro_gen_ConfigClientBankRes(ResultCode_ok);</span><br><span style="color: hsl(0, 100%, 40%);">-            server_conn_send_rspro(srvc, resp);</span><br><span style="color: hsl(0, 100%, 40%);">-             call_script(g_client, "event-config-bankd");</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                LOGPFSML(srvc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU type: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  rspro_msgt_name(pdu));</span><br><span style="color: hsl(0, 100%, 40%);">-         return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void handle_sig_usr1(int signal)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(signal == SIGUSR1);</span><br><span style="color: hsl(0, 100%, 40%);">- talloc_report_full(g_tall_ctx, stderr);</span><br><span style="color: hsl(0, 100%, 40%);">- printf("===== NULL\n");</span><br><span style="color: hsl(0, 100%, 40%);">-       talloc_report_full(NULL, stderr);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void print_welcome(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      printf("simtrace2-remsim-client - Remote SIM card client for SIMtrace\n"</span><br><span style="color: hsl(0, 100%, 40%);">-             "(C) 2010-2020, Harald Welte <laforge@gnumonks.org>\n"</span><br><span style="color: hsl(0, 100%, 40%);">-          "(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void print_help(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        printf( "\t-s\t--server-host HOST\n"</span><br><span style="color: hsl(0, 100%, 40%);">-          "\t-p\t--server-port PORT\n"</span><br><span style="color: hsl(0, 100%, 40%);">-          "\t-c\t--client-id <0-65535>\n"</span><br><span style="color: hsl(0, 100%, 40%);">-         "\t-n\t--client-slot <0-65535>\n"</span><br><span style="color: hsl(0, 100%, 40%);">-               "\t-h\t--help\n"</span><br><span style="color: hsl(0, 100%, 40%);">-              "\t-v\t--version\n"</span><br><span style="color: hsl(0, 100%, 40%);">-           "\t-i\t--gsmtap-ip\tA.B.C.D\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                "\t-k\t--keep-running\n"</span><br><span style="color: hsl(0, 100%, 40%);">-              "\t-V\t--usb-vendor\tVENDOR_ID\n"</span><br><span style="color: hsl(0, 100%, 40%);">-             "\t-P\t--usb-product\tPRODUCT_ID\n"</span><br><span style="color: hsl(0, 100%, 40%);">-           "\t-C\t--usb-config\tCONFIG_ID\n"</span><br><span style="color: hsl(0, 100%, 40%);">-             "\t-I\t--usb-interface\tINTERFACE_ID\n"</span><br><span style="color: hsl(0, 100%, 40%);">-               "\t-S\t--usb-altsetting ALTSETTING_ID\n"</span><br><span style="color: hsl(0, 100%, 40%);">-              "\t-A\t--usb-address\tADDRESS\n"</span><br><span style="color: hsl(0, 100%, 40%);">-              "\t-H\t--usb-path\tPATH\n"</span><br><span style="color: hsl(0, 100%, 40%);">-            "\t-a\t--atr\tATR\n"</span><br><span style="color: hsl(0, 100%, 40%);">-          "\t-e\t--event-script\tPATH\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                "\n"</span><br><span style="color: hsl(0, 100%, 40%);">-          );</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct client_config *client_config_init(void *ctx)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  struct client_config *cfg = talloc_zero(ctx, struct client_config);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!cfg)</span><br><span style="color: hsl(0, 100%, 40%);">-               return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    cfg->server_host = talloc_strdup(cfg, "127.0.0.1");</span><br><span style="color: hsl(0, 100%, 40%);">-        cfg->server_port = 9998;</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg->client_id = -1;</span><br><span style="color: hsl(0, 100%, 40%);">- cfg->client_slot = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-       cfg->gsmtap_host = talloc_strdup(cfg, "127.0.0.1");</span><br><span style="color: hsl(0, 100%, 40%);">-        cfg->keep_running = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   cfg->usb.vendor_id = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg->usb.product_id = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-    cfg->usb.config_id = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg->usb.if_num = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-        cfg->usb.altsetting = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg->usb.addr = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-  cfg->usb.path = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        cfg->atr.data[0] = 0x3B;</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg->atr.data[1] = 0x00; // the shortest simplest ATR possible</span><br><span style="color: hsl(0, 100%, 40%);">-       cfg->atr.len = 2;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return cfg;</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void handle_options(struct client_config *cfg, int argc, char **argv)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      const struct option opts[] = {</span><br><span style="color: hsl(0, 100%, 40%);">-          { "server-host", 1, 0, 's' },</span><br><span style="color: hsl(0, 100%, 40%);">-         { "server-port", 1, 0, 'p' },</span><br><span style="color: hsl(0, 100%, 40%);">-         { "client-id", 1, 0, 'c' },</span><br><span style="color: hsl(0, 100%, 40%);">-           { "client-slot", 1, 0, 'n' },</span><br><span style="color: hsl(0, 100%, 40%);">-         { "help", 0, 0, 'h' },</span><br><span style="color: hsl(0, 100%, 40%);">-                { "version", 0, 0, 'v' },</span><br><span style="color: hsl(0, 100%, 40%);">-             { "gsmtap-ip", 1, 0, 'i' },</span><br><span style="color: hsl(0, 100%, 40%);">-           { "keep-running", 0, 0, 'k' },</span><br><span style="color: hsl(0, 100%, 40%);">-                { "usb-vendor", 1, 0, 'V' },</span><br><span style="color: hsl(0, 100%, 40%);">-          { "usb-product", 1, 0, 'P' },</span><br><span style="color: hsl(0, 100%, 40%);">-         { "usb-config", 1, 0, 'C' },</span><br><span style="color: hsl(0, 100%, 40%);">-          { "usb-interface", 1, 0, 'I' },</span><br><span style="color: hsl(0, 100%, 40%);">-               { "usb-altsetting", 1, 0, 'S' },</span><br><span style="color: hsl(0, 100%, 40%);">-              { "usb-address", 1, 0, 'A' },</span><br><span style="color: hsl(0, 100%, 40%);">-         { "usb-path", 1, 0, 'H' },</span><br><span style="color: hsl(0, 100%, 40%);">-            { "atr", 1, 0, 'a' },</span><br><span style="color: hsl(0, 100%, 40%);">-         { "event-script", 1, 0, 'e' },</span><br><span style="color: hsl(0, 100%, 40%);">-                { NULL, 0, 0, 0 }</span><br><span style="color: hsl(0, 100%, 40%);">-       };</span><br><span style="color: hsl(0, 100%, 40%);">-      int c, rc;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      while (1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             int option_index = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           c = getopt_long(argc, argv, "s:p:c:n:hvi:kV:P:C:I:S:A:H:a:e:", opts, &option_index);</span><br><span style="color: hsl(0, 100%, 40%);">-              if (c == -1)</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span style="color: hsl(0, 100%, 40%);">-          switch (c) {</span><br><span style="color: hsl(0, 100%, 40%);">-            case 's':</span><br><span style="color: hsl(0, 100%, 40%);">-                       osmo_talloc_replace_string(cfg, &cfg->server_host, optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'p':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->server_port = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                     break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'c':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->client_id = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                       break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'n':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->client_slot = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                     break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'h':</span><br><span style="color: hsl(0, 100%, 40%);">-                       print_help();</span><br><span style="color: hsl(0, 100%, 40%);">-                   exit(0);</span><br><span style="color: hsl(0, 100%, 40%);">-                        break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'v':</span><br><span style="color: hsl(0, 100%, 40%);">-                       printf("osmo-remsim-client version %s\n", VERSION);</span><br><span style="color: hsl(0, 100%, 40%);">-                   exit(0);</span><br><span style="color: hsl(0, 100%, 40%);">-                        break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'i':</span><br><span style="color: hsl(0, 100%, 40%);">-                       osmo_talloc_replace_string(cfg, &cfg->gsmtap_host, optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'k':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->keep_running = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                       break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'V':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.vendor_id = strtol(optarg, NULL, 16);</span><br><span style="color: hsl(0, 100%, 40%);">-                       break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'P':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.product_id = strtol(optarg, NULL, 16);</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'C':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.config_id = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'I':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.if_num = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'S':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.altsetting = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                  break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'A':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.addr = atoi(optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                        break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'H':</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->usb.path = optarg;</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'a':</span><br><span style="color: hsl(0, 100%, 40%);">-                       rc = osmo_hexparse(optarg, cfg->atr.data, ARRAY_SIZE(cfg->atr.data));</span><br><span style="color: hsl(0, 100%, 40%);">-                     if (rc < 2 || rc > ARRAY_SIZE(cfg->atr.data)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                fprintf(stderr, "ATR malformed\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                           exit(2);</span><br><span style="color: hsl(0, 100%, 40%);">-                        }</span><br><span style="color: hsl(0, 100%, 40%);">-                       cfg->atr.len = rc;</span><br><span style="color: hsl(0, 100%, 40%);">-                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 'e':</span><br><span style="color: hsl(0, 100%, 40%);">-                       osmo_talloc_replace_string(cfg, &cfg->event_script, optarg);</span><br><span style="color: hsl(0, 100%, 40%);">-                     break;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (argc > optind) {</span><br><span style="color: hsl(0, 100%, 40%);">-         fprintf(stderr, "Unsupported positional arguments on command line\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                exit(2);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void main_body(struct cardem_inst *ci, struct client_config *cfg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-     struct st_transport *transp = ci->slot->transp;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct usb_interface_match _ifm, *ifm = &_ifm;</span><br><span style="color: hsl(0, 100%, 40%);">-      int rc, i;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      ifm->vendor = cfg->usb.vendor_id;</span><br><span style="color: hsl(0, 100%, 40%);">- ifm->product = cfg->usb.product_id;</span><br><span style="color: hsl(0, 100%, 40%);">-       ifm->configuration = cfg->usb.config_id;</span><br><span style="color: hsl(0, 100%, 40%);">-  ifm->interface = cfg->usb.if_num;</span><br><span style="color: hsl(0, 100%, 40%);">- ifm->altsetting = cfg->usb.altsetting;</span><br><span style="color: hsl(0, 100%, 40%);">-    ifm->addr = cfg->usb.addr;</span><br><span style="color: hsl(0, 100%, 40%);">-        if (cfg->usb.path)</span><br><span style="color: hsl(0, 100%, 40%);">-           osmo_strlcpy(ifm->path, cfg->usb.path, sizeof(ifm->path));</span><br><span style="color: hsl(0, 100%, 40%);">-     transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (!transp->usb_devh) {</span><br><span style="color: hsl(0, 100%, 40%);">-             fprintf(stderr, "can't open USB device\n");</span><br><span style="color: hsl(0, 100%, 40%);">-               return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* (re)determine the USB path of the opened device */</span><br><span style="color: hsl(0, 100%, 40%);">-   talloc_free(ci->usb_path);</span><br><span style="color: hsl(0, 100%, 40%);">-   ci->usb_path = osmo_libusb_dev_get_path_c(ci, libusb_get_device(transp->usb_devh));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = libusb_claim_interface(transp->usb_devh, cfg->usb.if_num);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "can't claim interface %d; rc=%d\n", cfg->usb.if_num, rc);</span><br><span style="color: hsl(0, 100%, 40%);">-             goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = osmo_libusb_get_ep_addrs(transp->usb_devh, cfg->usb.if_num, &transp->usb_ep.out,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      &transp->usb_ep.in, &transp->usb_ep.irq_in);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);</span><br><span style="color: hsl(0, 100%, 40%);">-            goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       // switch modem SIM port to emulated SIM on OWHW</span><br><span style="color: hsl(0, 100%, 40%);">-        if (USB_VENDOR_OPENMOKO == ifm->vendor && USB_PRODUCT_OWHW_SAM3 == ifm->product) { // we are on the OWHW</span><br><span style="color: hsl(0, 100%, 40%);">-          int modem = -1;</span><br><span style="color: hsl(0, 100%, 40%);">-         switch (ifm->interface) { // the USB interface indicates for which modem we want to emulate the SIM</span><br><span style="color: hsl(0, 100%, 40%);">-          case 0:</span><br><span style="color: hsl(0, 100%, 40%);">-                 modem = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          case 1:</span><br><span style="color: hsl(0, 100%, 40%);">-                 modem = 2;</span><br><span style="color: hsl(0, 100%, 40%);">-                      break;</span><br><span style="color: hsl(0, 100%, 40%);">-          default:</span><br><span style="color: hsl(0, 100%, 40%);">-                        fprintf(stderr, "unknown GPIO for SIMtrace interface %d\n", ifm->interface);</span><br><span style="color: hsl(0, 100%, 40%);">-                       goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               //</span><br><span style="color: hsl(0, 100%, 40%);">-              char gpio_path[PATH_MAX];</span><br><span style="color: hsl(0, 100%, 40%);">-               snprintf(gpio_path, sizeof(gpio_path), "/dev/gpio/connect_st_usim%d/value", modem);</span><br><span style="color: hsl(0, 100%, 40%);">-           int connec_st_usim = open(gpio_path, O_WRONLY);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (-1 == connec_st_usim) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     fprintf(stderr, "can't open GPIO %s to switch modem %d to emulated USIM\n", gpio_path, modem);</span><br><span style="color: hsl(0, 100%, 40%);">-                    goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (1 != write(connec_st_usim, "1", 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     fprintf(stderr, "can't write GPIO %s to switch modem %d to emulated USIM\n", gpio_path, modem);</span><br><span style="color: hsl(0, 100%, 40%);">-                   goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               printf("switched modem %d to emulated USIM\n", modem);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                snprintf(gpio_path, sizeof(gpio_path), "/dev/gpio/mdm%d_rst/value", modem);</span><br><span style="color: hsl(0, 100%, 40%);">-           int mdm_rst = open(gpio_path, O_WRONLY);</span><br><span style="color: hsl(0, 100%, 40%);">-                if (-1 == mdm_rst) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    fprintf(stderr, "can't open GPIO %s to reset modem %d\n", gpio_path, modem);</span><br><span style="color: hsl(0, 100%, 40%);">-                      goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (1 != write(mdm_rst, "1", 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    fprintf(stderr, "can't write GPIO %s to reset modem %d\n", gpio_path, modem);</span><br><span style="color: hsl(0, 100%, 40%);">-                     goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               sleep(1); // wait a bit to ensure reset is effective</span><br><span style="color: hsl(0, 100%, 40%);">-            if (1 != write(mdm_rst, "0", 1)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    fprintf(stderr, "can't write GPIO %s to reset modem %d\n", gpio_path, modem);</span><br><span style="color: hsl(0, 100%, 40%);">-                     goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               printf("modem %d reset\n", modem);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* request firmware to generate STATUS on IRQ endpoint */</span><br><span style="color: hsl(0, 100%, 40%);">-       cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      /* simulate card-insert to modem (owhw, not qmod) */</span><br><span style="color: hsl(0, 100%, 40%);">-    cardem_request_card_insert(ci, true);</span><br><span style="color: hsl(0, 100%, 40%);">-   call_script(g_client, "request-card-insert");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* select remote (forwarded) SIM */</span><br><span style="color: hsl(0, 100%, 40%);">-     st_modem_sim_select_remote(ci->slot);</span><br><span style="color: hsl(0, 100%, 40%);">-        call_script(g_client, "request-sim-remote");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* set the ATR */</span><br><span style="color: hsl(0, 100%, 40%);">-       //atr_update_csum(real_atr, sizeof(real_atr));</span><br><span style="color: hsl(0, 100%, 40%);">-  cardem_request_set_atr(ci, cfg->atr.data, cfg->atr.len);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  /* select remote (forwarded) SIM */</span><br><span style="color: hsl(0, 100%, 40%);">-     st_modem_reset_pulse(ci->slot, 300);</span><br><span style="color: hsl(0, 100%, 40%);">- call_script(g_client, "request-modem-reset");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- printf("Entering main loop\n");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       allocate_and_submit_irq(ci);</span><br><span style="color: hsl(0, 100%, 40%);">-    /* submit multiple IN URB in order to work around OS#4409 */</span><br><span style="color: hsl(0, 100%, 40%);">-    for (i = 0; i < 4; i++)</span><br><span style="color: hsl(0, 100%, 40%);">-              allocate_and_submit_in(ci);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     while (!g_leave_main) {</span><br><span style="color: hsl(0, 100%, 40%);">-         osmo_select_main(false);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       g_leave_main = false;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   libusb_release_interface(transp->usb_devh, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-close_exit:</span><br><span style="color: hsl(0, 100%, 40%);">-    if (transp->usb_devh)</span><br><span style="color: hsl(0, 100%, 40%);">-                libusb_close(transp-> usb_devh);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int main(int argc, char **argv)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct rspro_server_conn *srvc, *bankdc;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct client_config *cfg;</span><br><span style="color: hsl(0, 100%, 40%);">-      int rc;</span><br><span style="color: hsl(0, 100%, 40%);">- int ret = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    print_welcome();</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        talloc_enable_null_tracking();</span><br><span style="color: hsl(0, 100%, 40%);">-  g_tall_ctx = talloc_named_const(NULL, 0, "global");</span><br><span style="color: hsl(0, 100%, 40%);">-   talloc_asn1_ctx = talloc_named_const(g_tall_ctx, 0, "asn1");</span><br><span style="color: hsl(0, 100%, 40%);">-  msgb_talloc_ctx_init(g_tall_ctx, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    osmo_init_logging2(g_tall_ctx, &log_info);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  g_ci = talloc_zero(g_tall_ctx, struct cardem_inst);</span><br><span style="color: hsl(0, 100%, 40%);">-     g_ci->slot = &_slot;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     cfg = client_config_init(g_ci);</span><br><span style="color: hsl(0, 100%, 40%);">- handle_options(cfg, argc, argv);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        if (cfg->usb.vendor_id < 0 || cfg->usb.product_id < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-            fprintf(stderr, "You have to specify the vendor and product ID\n");</span><br><span style="color: hsl(0, 100%, 40%);">-           goto do_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       signal(SIGUSR1, handle_sig_usr1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = osmo_libusb_init(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "libusb initialization failed\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            goto do_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       g_gti = gsmtap_source_init(cfg->gsmtap_host, GSMTAP_UDP_PORT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!g_gti) {</span><br><span style="color: hsl(0, 100%, 40%);">-           perror("unable to open GSMTAP");</span><br><span style="color: hsl(0, 100%, 40%);">-              goto close_exit;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       gsmtap_source_add_sink(g_gti);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  signal(SIGINT, &signal_handler);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    // initialize remote SIM client</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- g_client = talloc_zero(g_tall_ctx, struct bankd_client);</span><br><span style="color: hsl(0, 100%, 40%);">-        g_client->cfg = cfg;</span><br><span style="color: hsl(0, 100%, 40%);">- g_client->cardem = g_ci;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (cfg->client_id != -1) {</span><br><span style="color: hsl(0, 100%, 40%);">-          g_client->srv_conn.clslot = talloc_zero(g_client, ClientSlot_t);</span><br><span style="color: hsl(0, 100%, 40%);">-             g_client->srv_conn.clslot->clientId = cfg->client_id;</span><br><span style="color: hsl(0, 100%, 40%);">-          /* default to client slot 0 */</span><br><span style="color: hsl(0, 100%, 40%);">-          if (cfg->client_slot == -1)</span><br><span style="color: hsl(0, 100%, 40%);">-                  g_client->srv_conn.clslot->slotNr = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-            else</span><br><span style="color: hsl(0, 100%, 40%);">-                    g_client->srv_conn.clslot->slotNr = cfg->client_slot;</span><br><span style="color: hsl(0, 100%, 40%);">-          g_client->bankd_conn.clslot = talloc_zero(g_client, ClientSlot_t);</span><br><span style="color: hsl(0, 100%, 40%);">-           *g_client->bankd_conn.clslot = *g_client->srv_conn.clslot;</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* create and [attempt to] establish connection to remsim-server */</span><br><span style="color: hsl(0, 100%, 40%);">-     srvc = &g_client->srv_conn;</span><br><span style="color: hsl(0, 100%, 40%);">-      srvc->server_host = cfg->server_host;</span><br><span style="color: hsl(0, 100%, 40%);">-     srvc->server_port = cfg->server_port;</span><br><span style="color: hsl(0, 100%, 40%);">-     srvc->handle_rx = srvc_handle_rx;</span><br><span style="color: hsl(0, 100%, 40%);">-    srvc->own_comp_id.type = ComponentType_remsimClient;</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_STRLCPY_ARRAY(srvc->own_comp_id.name, "simtrace2-remsim-client");</span><br><span style="color: hsl(0, 100%, 40%);">-     OSMO_STRLCPY_ARRAY(srvc->own_comp_id.software, "remsim-client");</span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_STRLCPY_ARRAY(srvc->own_comp_id.sw_version, PACKAGE_VERSION);</span><br><span style="color: hsl(0, 100%, 40%);">-   rc = server_conn_fsm_alloc(g_client, srvc);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "Unable to create Server conn FSM: %s\n", strerror(errno));</span><br><span style="color: hsl(0, 100%, 40%);">-           exit(1);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       osmo_fsm_inst_dispatch(srvc->fi, SRVC_E_ESTABLISH, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* create and not yet establish connection to remsim-bankd */</span><br><span style="color: hsl(0, 100%, 40%);">-   srvc = &g_client->srv_conn;</span><br><span style="color: hsl(0, 100%, 40%);">-      bankdc = &g_client->bankd_conn;</span><br><span style="color: hsl(0, 100%, 40%);">-  /* server_host / server_port are configured from remsim-server */</span><br><span style="color: hsl(0, 100%, 40%);">-       bankdc->handle_rx = bankd_handle_rx;</span><br><span style="color: hsl(0, 100%, 40%);">- memcpy(&bankdc->own_comp_id, &srvc->own_comp_id, sizeof(bankdc->own_comp_id));</span><br><span style="color: hsl(0, 100%, 40%);">- rc = server_conn_fsm_alloc(g_client, bankdc);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                fprintf(stderr, "Unable to create bankd conn FSM: %s\n", strerror(errno));</span><br><span style="color: hsl(0, 100%, 40%);">-            exit(1);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-       osmo_fsm_inst_update_id(bankdc->fi, "bankd");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      asn_debug = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  // connect to SIMtrace2 cardem</span><br><span style="color: hsl(0, 100%, 40%);">-  do {</span><br><span style="color: hsl(0, 100%, 40%);">-            main_body(g_ci, cfg);</span><br><span style="color: hsl(0, 100%, 40%);">-           sleep(1);</span><br><span style="color: hsl(0, 100%, 40%);">-       } while (cfg->keep_running);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-close_exit:</span><br><span style="color: hsl(0, 100%, 40%);">-      osmo_libusb_exit(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-do_exit:</span><br><span style="color: hsl(0, 100%, 40%);">- return ret;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span>diff --git a/src/client/user_ifdhandler.c b/src/client/user_ifdhandler.c</span><br><span>index 677b781..188d3a6 100644</span><br><span>--- a/src/client/user_ifdhandler.c</span><br><span>+++ b/src/client/user_ifdhandler.c</span><br><span>@@ -148,70 +148,66 @@</span><br><span> }</span><br><span> </span><br><span> /***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * Incoming RSPRO messages from bank-daemon (SIM card)</span><br><span style="color: hsl(120, 100%, 40%);">+ * frontend to remsim-client main FSM code</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_card_insert(struct bankd_client *bc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        const struct TpduCardToModem *card2modem;</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_sim_remote(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_modem_reset(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span>  struct client_thread *ct = bc->data;</span><br><span>      struct msgb *msg;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   OSMO_ASSERT(pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(data);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  card2modem = &pdu->msg.choice.tpduCardToModem;</span><br><span style="color: hsl(0, 100%, 40%);">-   DEBUGP(DMAIN, "R-APDU: %s\n", osmo_hexdump(card2modem->data.buf, card2modem->data.size));</span><br><span style="color: hsl(120, 100%, 40%);">+     DEBUGP(DMAIN, "R-APDU: %s\n", osmo_hexdump(data, len));</span><br><span>    /* enqueue towards IFD thread */</span><br><span style="color: hsl(0, 100%, 40%);">-        msg = itmsg_alloc(ITMSG_TYPE_R_APDU_IND, 0, card2modem->data.buf, card2modem->data.size);</span><br><span style="color: hsl(120, 100%, 40%);">+       msg = itmsg_alloc(ITMSG_TYPE_R_APDU_IND, 0, data, len);</span><br><span>      OSMO_ASSERT(msg);</span><br><span>    enqueue_to_ifd(ct, msg);</span><br><span> </span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len)</span><br><span> {</span><br><span>      struct client_thread *ct = bc->data;</span><br><span style="color: hsl(0, 100%, 40%);">- RsproPDU_t *resp;</span><br><span>    unsigned int atr_len;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(data);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  DEBUGP(DMAIN, "SET_ATR: %s\n", osmo_hexdump(pdu->msg.choice.setAtrReq.atr.buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                                                  pdu->msg.choice.setAtrReq.atr.size));</span><br><span style="color: hsl(120, 100%, 40%);">+ DEBUGP(DMAIN, "SET_ATR: %s\n", osmo_hexdump(data, len));</span><br><span> </span><br><span>       /* store ATR in local data structure until somebody needs it */</span><br><span style="color: hsl(0, 100%, 40%);">- atr_len = pdu->msg.choice.setAtrReq.atr.size;</span><br><span style="color: hsl(120, 100%, 40%);">+      atr_len = len;</span><br><span>       if (atr_len > sizeof(ct->atr))</span><br><span>                 atr_len = sizeof(ct->atr);</span><br><span style="color: hsl(0, 100%, 40%);">-   memcpy(ct->atr, pdu->msg.choice.setAtrReq.atr.buf, atr_len);</span><br><span style="color: hsl(120, 100%, 40%);">+    memcpy(ct->atr, data, atr_len);</span><br><span>   ct->atr_len = atr_len;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   resp = rspro_gen_SetAtrRes(ResultCode_ok);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!resp)</span><br><span style="color: hsl(0, 100%, 40%);">-              return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- server_conn_send_rspro(&bc->bankd_conn, resp);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct bankd_client *bc = bankdc2bankd_client(bankdc);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        switch (pdu->msg.present) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_tpduCardToModem:</span><br><span style="color: hsl(0, 100%, 40%);">-         bankd_handle_tpduCardToModem(bc, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_setAtrReq:</span><br><span style="color: hsl(0, 100%, 40%);">-               bankd_handle_setAtrReq(bc, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-                break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                OSMO_ASSERT(0);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -363,6 +359,7 @@</span><br><span> static void *client_pthread_main(void *arg)</span><br><span> {</span><br><span>         struct client_thread_cfg *cfg = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct client_config *ccfg;</span><br><span>  struct client_thread *ct;</span><br><span>    int rc;</span><br><span> </span><br><span>@@ -373,17 +370,20 @@</span><br><span>  ct = talloc_zero(OTC_GLOBAL, struct client_thread);</span><br><span>  OSMO_ASSERT(ct);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  ccfg = client_config_init(ct);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(ccfg);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_talloc_replace_string(ccfg, &ccfg->server_host, cfg->server_host);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (cfg->server_port >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+              ccfg->server_port = cfg->server_port;</span><br><span style="color: hsl(120, 100%, 40%);">+   ccfg->client_id = cfg->client_id;</span><br><span style="color: hsl(120, 100%, 40%);">+       ccfg->client_slot = cfg->client_slot;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        if (!talloc_asn1_ctx)</span><br><span>               talloc_asn1_ctx= talloc_named_const(ct, 0, "asn1");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        ct->bc = remsim_client_create(ct, cfg->name, "remsim_ifdhandler");</span><br><span style="color: hsl(120, 100%, 40%);">+    ct->bc = remsim_client_create(ct, cfg->name, "remsim_ifdhandler", ccfg);</span><br><span>     OSMO_ASSERT(ct->bc);</span><br><span>      ct->bc->data = ct;</span><br><span style="color: hsl(0, 100%, 40%);">-        remsim_client_set_clslot(ct->bc, cfg->client_id, cfg->client_slot);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (cfg->server_host)</span><br><span style="color: hsl(0, 100%, 40%);">-                ct->bc->srv_conn.server_host = (char *) cfg->server_host;</span><br><span style="color: hsl(0, 100%, 40%);">-      if (cfg->server_port >= 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                ct->bc->srv_conn.server_port = cfg->server_port;</span><br><span> </span><br><span>        INIT_LLIST_HEAD(&ct->it_msgq);</span><br><span>        osmo_fd_setup(&ct->it_ofd, cfg->it_sock_fd, OSMO_FD_READ, &it_sock_fd_cb, ct, 0);</span><br><span>diff --git a/src/client/user_shell.c b/src/client/user_shell.c</span><br><span>index abe1542..40bcddd 100644</span><br><span>--- a/src/client/user_shell.c</span><br><span>+++ b/src/client/user_shell.c</span><br><span>@@ -12,58 +12,54 @@</span><br><span> </span><br><span> </span><br><span> /***********************************************************************</span><br><span style="color: hsl(0, 100%, 40%);">- * Incoming RSPRO messages from bank-daemon (SIM card)</span><br><span style="color: hsl(120, 100%, 40%);">+ * stdin frontend code to remsim-client</span><br><span>  ***********************************************************************/</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_card_insert(struct bankd_client *bc)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present);</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        const struct TpduCardToModem *card2modem = &pdu->msg.choice.tpduCardToModem;</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_sim_remote(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        printf("R-APDU: %s\n", osmo_hexdump(card2modem->data.buf, card2modem->data.size));</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_modem_reset(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(data);</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("R-APDU: %s\n", osmo_hexdump(data, len));</span><br><span>   fflush(stdout);</span><br><span> </span><br><span>  return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- RsproPDU_t *resp;</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(data);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  OSMO_ASSERT(pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-       OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        printf("SET_ATR: %s\n", osmo_hexdump(pdu->msg.choice.setAtrReq.atr.buf,</span><br><span style="color: hsl(0, 100%, 40%);">-                                         pdu->msg.choice.setAtrReq.atr.size));</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("SET_ATR: %s\n", osmo_hexdump(data, len));</span><br><span>  fflush(stdout);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     resp = rspro_gen_SetAtrRes(ResultCode_ok);</span><br><span style="color: hsl(0, 100%, 40%);">-      if (!resp)</span><br><span style="color: hsl(0, 100%, 40%);">-              return -ENOMEM;</span><br><span style="color: hsl(0, 100%, 40%);">- server_conn_send_rspro(&bc->bankd_conn, resp);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-  struct bankd_client *client = bankdc2bankd_client(bankdc);</span><br><span style="color: hsl(0, 100%, 40%);">-      switch (pdu->msg.present) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_tpduCardToModem:</span><br><span style="color: hsl(0, 100%, 40%);">-         bankd_handle_tpduCardToModem(client, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-              break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case RsproPDUchoice_PR_setAtrReq:</span><br><span style="color: hsl(0, 100%, 40%);">-               bankd_handle_setAtrReq(client, pdu);</span><br><span style="color: hsl(0, 100%, 40%);">-            break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                OSMO_ASSERT(0);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /***********************************************************************</span><br><span>  * Incoming command from the user application (stdin shell in our case)</span><br><span>  ***********************************************************************/</span><br><span>diff --git a/src/client/user_simtrace2.c b/src/client/user_simtrace2.c</span><br><span>new file mode 100644</span><br><span>index 0000000..24a8d09</span><br><span>--- /dev/null</span><br><span>+++ b/src/client/user_simtrace2.c</span><br><span>@@ -0,0 +1,458 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2018-2020 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <libusb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/usb/libusb.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/simtrace2/apdu_dispatch.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/simtrace2/simtrace2_api.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/simtrace2/simtrace_prot.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "client.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "debug.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Incoming Messages from cardem firmware</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Process a STATUS message from the SIMtrace2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct cardemu_usb_msg_status *status;</span><br><span style="color: hsl(120, 100%, 40%);">+        status = (struct cardemu_usb_msg_status *) buf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("SIMtrace => STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+         status->flags, status->fi, status->di, status->wi,</span><br><span style="color: hsl(120, 100%, 40%);">+                status->waiting_time);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Process a PTS indication message from the SIMtrace2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int process_do_pts(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct cardemu_usb_msg_pts_info *pts = (struct cardemu_usb_msg_pts_info *) buf;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bankd_client *bc = ci->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct frontend_pts fpts = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .buf = pts->req,</span><br><span style="color: hsl(120, 100%, 40%);">+           .len = sizeof(pts->req),</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("SIMtrace => PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fsm_inst_dispatch(bc->main_fi, MF_E_MDM_PTS_IND, &fpts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Process a ERROR indication message from the SIMtrace2 */</span><br><span style="color: hsl(120, 100%, 40%);">+__attribute__((unused)) static int process_do_error(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct cardemu_usb_msg_error *err;</span><br><span style="color: hsl(120, 100%, 40%);">+    err = (struct cardemu_usb_msg_error *) buf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("SIMtrace => ERROR: %u/%u/%u: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              err->severity, err->subsystem, err->code,</span><br><span style="color: hsl(120, 100%, 40%);">+            err->msg_len ? (char *)err->msg : "");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_apdu_context ac; // this will hold the complete APDU (across calls)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Process a RX-DATA indication message from the SIMtrace2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int process_do_rx_da(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct cardemu_usb_msg_rx_data *data = (struct cardemu_usb_msg_rx_data *) buf;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct bankd_client *bc = ci->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct frontend_tpdu ftpdu;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("SIMtrace => DATA: flags=%x, %s: ", data->flags,</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_hexdump(data->data, data->data_len));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* parse the APDU data in the USB message */</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_apdu_segment_in(&ac, data->data, data->data_len,</span><br><span style="color: hsl(120, 100%, 40%);">+                            data->flags & CEMU_DATA_F_TPDU_HDR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rc & APDU_ACT_TX_CAPDU_TO_CARD) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* there is no pending data coming from the modem */</span><br><span style="color: hsl(120, 100%, 40%);">+          uint8_t apdu_command[sizeof(ac.hdr) + ac.lc.tot];</span><br><span style="color: hsl(120, 100%, 40%);">+             memcpy(apdu_command, &ac.hdr, sizeof(ac.hdr));</span><br><span style="color: hsl(120, 100%, 40%);">+            if (ac.lc.tot)</span><br><span style="color: hsl(120, 100%, 40%);">+                        memcpy(apdu_command + sizeof(ac.hdr), ac.dc, ac.lc.tot);</span><br><span style="color: hsl(120, 100%, 40%);">+              /* send APDU to card */</span><br><span style="color: hsl(120, 100%, 40%);">+               ftpdu.buf = apdu_command;</span><br><span style="color: hsl(120, 100%, 40%);">+             ftpdu.len = sizeof(ac.hdr) + ac.lc.tot;</span><br><span style="color: hsl(120, 100%, 40%);">+               osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_TPDU, &ftpdu);</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (ac.lc.tot > ac.lc.cur) {</span><br><span style="color: hsl(120, 100%, 40%);">+                /* there is pending data from the modem: send procedure byte to get remaining data */</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_st2_cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+ case SIMTRACE_CMD_DO_ERROR</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = process_do_error(ci, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Process an incoming message from the SIMtrace2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("SIMtrace -> %s\n", osmo_hexdump(buf, len));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    buf += sizeof(*sh);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (sh->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case SIMTRACE_MSGT_BD_CEMU_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = process_do_status(ci, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SIMTRACE_MSGT_DO_CEMU_PTS:</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = process_do_pts(ci, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SIMTRACE_MSGT_DO_CEMU_RX_DATA:</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = process_do_rx_da(ci, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case SIMTRACE_MSGT_BD_CEMU_CONFIG:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* firmware confirms configuration change; ignore */</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int process_irq_status(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bankd_client *bc = ci->priv;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct frontend_phys_status pstatus = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .flags = {</span><br><span style="color: hsl(120, 100%, 40%);">+                    .reset_active = status->flags & CEMU_STATUS_F_RESET_ACTIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+                    .vcc_present = status->flags & CEMU_STATUS_F_VCC_PRESENT,</span><br><span style="color: hsl(120, 100%, 40%);">+                      .clk_active = status->flags & CEMU_STATUS_F_CLK_ACTIVE,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .card_present = -1 /* FIXME: make this dependent on board */,</span><br><span style="color: hsl(120, 100%, 40%);">+         },</span><br><span style="color: hsl(120, 100%, 40%);">+            .voltage_mv = status->voltage_mv,</span><br><span style="color: hsl(120, 100%, 40%);">+          .fi = status->fi,</span><br><span style="color: hsl(120, 100%, 40%);">+          .di = status->di,</span><br><span style="color: hsl(120, 100%, 40%);">+          .wi = status->wi,</span><br><span style="color: hsl(120, 100%, 40%);">+          .waiting_time = status->waiting_time,</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",</span><br><span style="color: hsl(120, 100%, 40%);">+           status->flags, status->fi, status->di, status->wi,</span><br><span style="color: hsl(120, 100%, 40%);">+                status->waiting_time);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   osmo_fsm_inst_dispatch(bc->main_fi, MF_E_MDM_STATUS_IND, &pstatus);</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int process_usb_msg_irq(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("SIMtrace IRQ %s\n", osmo_hexdump(buf, len));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      buf += sizeof(*sh);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (sh->msg_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case SIMTRACE_MSGT_BD_CEMU_STATUS:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = process_irq_status(ci, buf, len);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void usb_in_xfer_cb(struct libusb_transfer *xfer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_st2_cardem_inst *ci = xfer->user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (xfer->status) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case LIBUSB_TRANSFER_COMPLETED:</span><br><span style="color: hsl(120, 100%, 40%);">+               /* hand the message up the stack */</span><br><span style="color: hsl(120, 100%, 40%);">+           process_usb_msg(ci, xfer->buffer, xfer->actual_length);</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case LIBUSB_TRANSFER_NO_DEVICE:</span><br><span style="color: hsl(120, 100%, 40%);">+               fprintf(stderr, "USB device disappeared\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "USB IN transfer failed, status=%u\n", xfer->status);</span><br><span style="color: hsl(120, 100%, 40%);">+            exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* re-submit the IN transfer */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void allocate_and_submit_in(struct osmo_st2_cardem_inst *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_st2_transport *transp = ci->slot->transp;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct libusb_transfer *xfer;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     xfer = libusb_alloc_transfer(0);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(xfer);</span><br><span style="color: hsl(120, 100%, 40%);">+    xfer->dev_handle = transp->usb_devh;</span><br><span style="color: hsl(120, 100%, 40%);">+    xfer->flags = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   xfer->type = LIBUSB_TRANSFER_TYPE_BULK;</span><br><span style="color: hsl(120, 100%, 40%);">+    xfer->endpoint = transp->usb_ep.in;</span><br><span style="color: hsl(120, 100%, 40%);">+     xfer->timeout = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer->user_data = ci;</span><br><span style="color: hsl(120, 100%, 40%);">+      xfer->length = 16*256;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(xfer->buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer->callback = usb_in_xfer_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* submit the IN transfer */</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void usb_irq_xfer_cb(struct libusb_transfer *xfer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_st2_cardem_inst *ci = xfer->user_data;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (xfer->status) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case LIBUSB_TRANSFER_COMPLETED:</span><br><span style="color: hsl(120, 100%, 40%);">+               process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case LIBUSB_TRANSFER_NO_DEVICE:</span><br><span style="color: hsl(120, 100%, 40%);">+               fprintf(stderr, "USB device disappeared\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "USB IRQ transfer failed, status=%u\n", xfer->status);</span><br><span style="color: hsl(120, 100%, 40%);">+           exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* re-submit the IN transfer */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void allocate_and_submit_irq(struct osmo_st2_cardem_inst *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_st2_transport *transp = ci->slot->transp;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct libusb_transfer *xfer;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     xfer = libusb_alloc_transfer(0);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(xfer);</span><br><span style="color: hsl(120, 100%, 40%);">+    xfer->dev_handle = transp->usb_devh;</span><br><span style="color: hsl(120, 100%, 40%);">+    xfer->flags = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;</span><br><span style="color: hsl(120, 100%, 40%);">+       xfer->endpoint = transp->usb_ep.irq_in;</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer->timeout = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer->user_data = ci;</span><br><span style="color: hsl(120, 100%, 40%);">+      xfer->length = 64;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(xfer->buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+ xfer->callback = usb_irq_xfer_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* submit the IN transfer */</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = libusb_submit_transfer(xfer);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * simtrace2 frontend code to remsim-client</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_card_insert(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_st2_cardem_inst *ci = bc->cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_st2_cardem_request_card_insert(ci, true);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_sim_remote(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct osmo_st2_cardem_inst *ci = bc->cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_st2_modem_sim_select_remote(ci->slot);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_request_modem_reset(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_st2_cardem_inst *ci = bc->cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_st2_modem_reset_pulse(ci->slot, 300);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_st2_cardem_inst *ci = bc->cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+      // save SW to our current APDU context</span><br><span style="color: hsl(120, 100%, 40%);">+        ac.sw[0] = data[len-2];</span><br><span style="color: hsl(120, 100%, 40%);">+       ac.sw[1] = data[len=1];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("SIMtrace <= SW=0x%02x%02x, len_rx=%zu\n", ac.sw[0], ac.sw[1], len-2);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (len > 2) { // send PB and data to modem</span><br><span style="color: hsl(120, 100%, 40%);">+                osmo_st2_cardem_request_pb_and_tx(ci, ac.hdr.ins, data, len-2);</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_st2_cardem_request_sw_tx(ci, ac.sw); // send SW to modem</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_st2_cardem_inst *ci = bc->cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_st2_cardem_request_set_atr(ci, data, len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we currently don't propagate bankd status to cardem */</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_st2_cardem_inst *ci = bc->cardem;</span><br><span style="color: hsl(120, 100%, 40%);">+      int i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (max_env < 4)</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     env[i++] = talloc_asprintf(env, "REMSIM_USB_PATH=%s", ci->usb_path);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* TODO: Configuration; Altsetting */</span><br><span style="color: hsl(120, 100%, 40%);">+ env[i++] = talloc_asprintf(env, "REMSIM_USB_INTERFACE=%u", bc->cfg->usb.if_num);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return i;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* FIXME: This must be cleaned up */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_st2_transport _transp;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct osmo_st2_slot _slot = {</span><br><span style="color: hsl(120, 100%, 40%);">+        .transp = &_transp,</span><br><span style="color: hsl(120, 100%, 40%);">+       .slot_nr = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int client_user_main(struct bankd_client *bc)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct usb_interface_match _ifm, *ifm = &_ifm;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_st2_transport *transp;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_st2_cardem_inst *ci;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct client_config *cfg = bc->cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc, i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_libusb_init(NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "libusb initialization failed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ci = talloc_zero(bc, struct osmo_st2_cardem_inst);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+      ci->slot = &_slot;</span><br><span style="color: hsl(120, 100%, 40%);">+     transp = ci->slot->transp;</span><br><span style="color: hsl(120, 100%, 40%);">+      ci->priv = bc;</span><br><span style="color: hsl(120, 100%, 40%);">+     bc->cardem = ci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ifm->vendor = cfg->usb.vendor_id;</span><br><span style="color: hsl(120, 100%, 40%);">+       ifm->product = cfg->usb.product_id;</span><br><span style="color: hsl(120, 100%, 40%);">+     ifm->configuration = cfg->usb.config_id;</span><br><span style="color: hsl(120, 100%, 40%);">+        ifm->interface = cfg->usb.if_num;</span><br><span style="color: hsl(120, 100%, 40%);">+       ifm->altsetting = cfg->usb.altsetting;</span><br><span style="color: hsl(120, 100%, 40%);">+  ifm->addr = cfg->usb.addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (cfg->usb.path)</span><br><span style="color: hsl(120, 100%, 40%);">+         osmo_strlcpy(ifm->path, cfg->usb.path, sizeof(ifm->path));</span><br><span style="color: hsl(120, 100%, 40%);">+   transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!transp->usb_devh) {</span><br><span style="color: hsl(120, 100%, 40%);">+           fprintf(stderr, "can't open USB device\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* (re)determine the USB path of the opened device */</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ci->usb_path);</span><br><span style="color: hsl(120, 100%, 40%);">+ ci->usb_path = osmo_libusb_dev_get_path_c(ci, libusb_get_device(transp->usb_devh));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = libusb_claim_interface(transp->usb_devh, cfg->usb.if_num);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "can't claim interface %d; rc=%d\n", cfg->usb.if_num, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+           goto close_exit;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = osmo_libusb_get_ep_addrs(transp->usb_devh, cfg->usb.if_num, &transp->usb_ep.out,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    &transp->usb_ep.in, &transp->usb_ep.irq_in);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);</span><br><span style="color: hsl(120, 100%, 40%);">+          goto close_exit;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   allocate_and_submit_irq(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* submit multiple IN URB in order to work around OS#4409 */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < 4; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            allocate_and_submit_in(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* request firmware to generate STATUS on IRQ endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_st2_cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_select_main(0);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+close_exit:</span><br><span style="color: hsl(120, 100%, 40%);">+      if (transp->usb_devh)</span><br><span style="color: hsl(120, 100%, 40%);">+              libusb_close(transp->usb_devh);</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_libusb_exit(NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/rspro_client_fsm.c b/src/rspro_client_fsm.c</span><br><span>index e55892c..36a3016 100644</span><br><span>--- a/src/rspro_client_fsm.c</span><br><span>+++ b/src/rspro_client_fsm.c</span><br><span>@@ -397,7 +397,7 @@</span><br><span>     [SRVC_ST_INIT] = {</span><br><span>           .name = "INIT",</span><br><span>            .in_event_mask = 0, /* S(SRVC_E_ESTABLISH) via allstate */</span><br><span style="color: hsl(0, 100%, 40%);">-              .out_state_mask = S(SRVC_ST_REESTABLISH),</span><br><span style="color: hsl(120, 100%, 40%);">+             .out_state_mask = S(SRVC_ST_INIT) | S(SRVC_ST_REESTABLISH),</span><br><span>          .action = srvc_st_init,</span><br><span>      },</span><br><span>   [SRVC_ST_ESTABLISHED] = {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-remsim/+/17361">change 17361</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-remsim/+/17361"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-remsim </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I44a430bc5674dea00ed72a0b28729ac8bcb4e022 </div>
<div style="display:none"> Gerrit-Change-Number: 17361 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-CC: Jenkins Builder </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>