client: major restructuring around new main_fsm
The remsim_client code already used FSMs for the connections to both remsim-server and remsim-bankd. However the 'main' part of the program was not yet implemented as a FSM, making it somewhat difficult to perform the right actions in every possible situation. This commit re-structures the code around a central main_fsm, which gets notified from the per-connection FSMs and which handles the common processing. It also handles the execution of external script commands, and hence further unifies the code base between the different backends (simtrace2, ifd_handler, shell) Closes: #4414 Change-Id: I44a430bc5674dea00ed72a0b28729ac8bcb4e022
This commit is contained in:
parent
5b5d6cee9b
commit
0e968cce38
|
@ -7,7 +7,7 @@ AM_CFLAGS = -Wall -I$(top_srcdir)/include -I/$(top_builddir)/include -I$(top_src
|
||||||
bin_PROGRAMS = osmo-remsim-client-st2 osmo-remsim-client-shell
|
bin_PROGRAMS = osmo-remsim-client-st2 osmo-remsim-client-shell
|
||||||
|
|
||||||
osmo_remsim_client_shell_SOURCES = user_shell.c remsim_client_main.c \
|
osmo_remsim_client_shell_SOURCES = user_shell.c remsim_client_main.c \
|
||||||
remsim_client.c ../rspro_client_fsm.c ../debug.c
|
remsim_client.c main_fsm.c ../rspro_client_fsm.c ../debug.c
|
||||||
osmo_remsim_client_shell_CFLAGS = $(AM_CFLAGS)
|
osmo_remsim_client_shell_CFLAGS = $(AM_CFLAGS)
|
||||||
osmo_remsim_client_shell_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
osmo_remsim_client_shell_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
||||||
$(top_builddir)/src/libosmo-rspro.la
|
$(top_builddir)/src/libosmo-rspro.la
|
||||||
|
@ -19,15 +19,16 @@ bundle_DATA=PkgInfo
|
||||||
bundlelinuxdir=$(bundledir)/Linux
|
bundlelinuxdir=$(bundledir)/Linux
|
||||||
bundlelinux_LTLIBRARIES = libifd_remsim_client.la
|
bundlelinux_LTLIBRARIES = libifd_remsim_client.la
|
||||||
libifd_remsim_client_la_SOURCES = user_ifdhandler.c \
|
libifd_remsim_client_la_SOURCES = user_ifdhandler.c \
|
||||||
remsim_client.c ../rspro_client_fsm.c ../debug.c
|
remsim_client.c main_fsm.c ../rspro_client_fsm.c ../debug.c
|
||||||
libifd_remsim_client_la_CFLAGS = $(AM_CFLAGS)
|
libifd_remsim_client_la_CFLAGS = $(AM_CFLAGS)
|
||||||
libifd_remsim_client_la_CPPFLAGS = $(PCSC_CFLAGS)
|
libifd_remsim_client_la_CPPFLAGS = $(PCSC_CFLAGS)
|
||||||
libifd_remsim_client_la_LDFLAGS = -no-undefined
|
libifd_remsim_client_la_LDFLAGS = -no-undefined
|
||||||
libifd_remsim_client_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
libifd_remsim_client_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
||||||
$(top_builddir)/src/libosmo-rspro.la
|
$(top_builddir)/src/libosmo-rspro.la
|
||||||
|
|
||||||
osmo_remsim_client_st2_SOURCES = simtrace2-remsim_client.c \
|
osmo_remsim_client_st2_SOURCES = user_simtrace2.c remsim_client_main.c \
|
||||||
../rspro_client_fsm.c ../debug.c
|
remsim_client.c main_fsm.c ../rspro_client_fsm.c ../debug.c
|
||||||
|
osmo_remsim_client_st2_CPPFLAGS = -DUSB_SUPPORT
|
||||||
osmo_remsim_client_st2_CFLAGS = $(AM_CFLAGS)
|
osmo_remsim_client_st2_CFLAGS = $(AM_CFLAGS)
|
||||||
osmo_remsim_client_st2_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
osmo_remsim_client_st2_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
||||||
$(OSMOUSB_LIBS) $(OSMOSIMTRACE2_LIBS) \
|
$(OSMOUSB_LIBS) $(OSMOSIMTRACE2_LIBS) \
|
||||||
|
|
|
@ -10,9 +10,49 @@
|
||||||
#include "slotmap.h"
|
#include "slotmap.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* frontend interface
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
struct bankd_client;
|
||||||
|
|
||||||
|
struct frontend_phys_status {
|
||||||
|
struct {
|
||||||
|
/* all members can be 0 (inactive), 1 (active) or -1 (not supported/known) */
|
||||||
|
int reset_active;
|
||||||
|
int vcc_present;
|
||||||
|
int clk_active;
|
||||||
|
int card_present;
|
||||||
|
} flags;
|
||||||
|
uint16_t voltage_mv;
|
||||||
|
uint8_t fi;
|
||||||
|
uint8_t di;
|
||||||
|
uint8_t wi;
|
||||||
|
uint8_t waiting_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct frontend_pts {
|
||||||
|
const uint8_t *buf;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct frontend_tpdu {
|
||||||
|
const uint8_t *buf;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* API from generic core to frontend (modem/cardem) */
|
||||||
|
int frontend_request_card_insert(struct bankd_client *bc);
|
||||||
|
int frontend_request_sim_remote(struct bankd_client *bc);
|
||||||
|
int frontend_request_modem_reset(struct bankd_client *bc);
|
||||||
|
int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len);
|
||||||
|
int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len);
|
||||||
|
int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts);
|
||||||
|
int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env);
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
|
|
||||||
struct cardem_inst;
|
struct osmo_st2_cardem_inst;
|
||||||
|
|
||||||
#define ATR_SIZE_MAX 55
|
#define ATR_SIZE_MAX 55
|
||||||
struct client_config {
|
struct client_config {
|
||||||
|
@ -48,6 +88,8 @@ struct bankd_client {
|
||||||
struct rspro_server_conn srv_conn;
|
struct rspro_server_conn srv_conn;
|
||||||
/* connection to the remsim-bankd (data) */
|
/* connection to the remsim-bankd (data) */
|
||||||
struct rspro_server_conn bankd_conn;
|
struct rspro_server_conn bankd_conn;
|
||||||
|
/* CLIENT_MAIN fsm */
|
||||||
|
struct osmo_fsm_inst *main_fi;
|
||||||
|
|
||||||
/* remote component ID */
|
/* remote component ID */
|
||||||
struct app_comp_id peer_comp_id;
|
struct app_comp_id peer_comp_id;
|
||||||
|
@ -55,17 +97,43 @@ struct bankd_client {
|
||||||
struct bank_slot bankd_slot;
|
struct bank_slot bankd_slot;
|
||||||
|
|
||||||
struct client_config *cfg;
|
struct client_config *cfg;
|
||||||
struct cardem_inst *cardem;
|
struct osmo_st2_cardem_inst *cardem;
|
||||||
|
struct frontend_phys_status last_status;
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define srvc2bankd_client(srvc) container_of(srvc, struct bankd_client, srv_conn)
|
#define srvc2bankd_client(srvc) container_of(srvc, struct bankd_client, srv_conn)
|
||||||
#define bankdc2bankd_client(bdc) container_of(bdc, struct bankd_client, bankd_conn)
|
#define bankdc2bankd_client(bdc) container_of(bdc, struct bankd_client, bankd_conn)
|
||||||
|
|
||||||
struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software);
|
struct client_config *client_config_init(void *ctx);
|
||||||
|
struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software,
|
||||||
|
struct client_config *cfg);
|
||||||
void remsim_client_set_clslot(struct bankd_client *bc, int client_id, int slot_nr);
|
void remsim_client_set_clslot(struct bankd_client *bc, int client_id, int slot_nr);
|
||||||
|
|
||||||
|
|
||||||
extern int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu);
|
|
||||||
|
|
||||||
extern int client_user_main(struct bankd_client *g_client);
|
extern int client_user_main(struct bankd_client *g_client);
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* main FSM
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
enum main_fsm_event {
|
||||||
|
MF_E_SRVC_CONNECTED, /* connection to server established (TCP + RSPRO level) */
|
||||||
|
MF_E_SRVC_LOST, /* connection to server was lost */
|
||||||
|
MF_E_SRVC_CONFIG_BANK, /* server instructs us to connect to bankd/slot */
|
||||||
|
MF_E_SRVC_RESET_REQ, /* RsproPDUchoice_PR_ResetStateReq */
|
||||||
|
|
||||||
|
MF_E_BANKD_CONNECTED, /* connection to bankd established (TCP + RSPRO level) */
|
||||||
|
MF_E_BANKD_LOST, /* connection to bankd was lost */
|
||||||
|
MF_E_BANKD_TPDU, /* RsproPDUchoice_PR_tpduCardToModem */
|
||||||
|
MF_E_BANKD_ATR, /* RsproPDUchoice_PR_setAtrReq */
|
||||||
|
MF_E_BANKD_SLOT_STATUS, /* bankSlotStatusInd */
|
||||||
|
|
||||||
|
MF_E_MDM_STATUS_IND, /* status from modem/cardem */
|
||||||
|
MF_E_MDM_PTS_IND, /* PTS indication from modem/cardem */
|
||||||
|
MF_E_MDM_TPDU, /* TPDU from modem/cardem */
|
||||||
|
};
|
||||||
|
struct osmo_fsm_inst *main_fsm_alloc(void *ctx, struct bankd_client *bc);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,377 @@
|
||||||
|
/* (C) 2020 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/talloc.h>
|
||||||
|
#include <osmocom/core/logging.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/fsm.h>
|
||||||
|
#include <osmocom/core/exec.h>
|
||||||
|
|
||||||
|
#include "rspro_util.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define S(x) (1 << (x))
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
/* build the (additional) environment for executing a script */
|
||||||
|
static char **build_script_env(struct bankd_client *bc, const char *cause)
|
||||||
|
{
|
||||||
|
char **env = talloc_zero_size(bc, 256*sizeof(char *));
|
||||||
|
int rc, i = 0;
|
||||||
|
|
||||||
|
if (!env)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_VERSION=%s", VERSION);
|
||||||
|
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_SERVER_ADDR=%s:%u",
|
||||||
|
bc->srv_conn.server_host, bc->srv_conn.server_port);
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_SERVER_STATE=%s",
|
||||||
|
osmo_fsm_inst_state_name(bc->srv_conn.fi));
|
||||||
|
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_BANKD_ADDR=%s:%u",
|
||||||
|
bc->bankd_conn.server_host, bc->bankd_conn.server_port);
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_BANKD_STATE=%s",
|
||||||
|
osmo_fsm_inst_state_name(bc->bankd_conn.fi));
|
||||||
|
|
||||||
|
|
||||||
|
if (bc->srv_conn.clslot) {
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_SLOT=%lu:%lu",
|
||||||
|
bc->srv_conn.clslot->clientId,
|
||||||
|
bc->srv_conn.clslot->slotNr);
|
||||||
|
}
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_BANKD_SLOT=%u:%u",
|
||||||
|
bc->bankd_slot.bank_id, bc->bankd_slot.slot_nr);
|
||||||
|
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_SIM_VCC=%u", bc->last_status.flags.vcc_present);
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_SIM_RST=%u", bc->last_status.flags.reset_active);
|
||||||
|
/* TODO: SIM card state CLK */
|
||||||
|
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_CAUSE=%s", cause);
|
||||||
|
|
||||||
|
/* ask frontend to append any frontend-speccific additional environment vars */
|
||||||
|
rc = frontend_append_script_env(bc, env+i, 256-i);
|
||||||
|
if (rc > 0)
|
||||||
|
i += rc;
|
||||||
|
|
||||||
|
/* terminate last entry */
|
||||||
|
env[i++] = NULL;
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int call_script(struct bankd_client *bc, const char *cause)
|
||||||
|
{
|
||||||
|
char **env, *cmd;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!bc->cfg->event_script)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
env = build_script_env(bc, cause);
|
||||||
|
if (!env)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cmd = talloc_asprintf(env, "%s %s", bc->cfg->event_script, cause);
|
||||||
|
if (!cmd) {
|
||||||
|
talloc_free(env);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = osmo_system_nowait(cmd, osmo_environment_whitelist, env);
|
||||||
|
talloc_free(env);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
enum main_fsm_state {
|
||||||
|
MF_ST_INIT,
|
||||||
|
MF_ST_UNCONFIGURED, /* waiting for configuration from server */
|
||||||
|
MF_ST_WAIT_BANKD, /* configured; waiting for bankd conn */
|
||||||
|
MF_ST_OPERATIONAL, /* fully operational (configured + bankd conn live */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct value_string main_fsm_event_names[] = {
|
||||||
|
OSMO_VALUE_STRING(MF_E_SRVC_CONNECTED),
|
||||||
|
OSMO_VALUE_STRING(MF_E_SRVC_LOST),
|
||||||
|
OSMO_VALUE_STRING(MF_E_SRVC_CONFIG_BANK),
|
||||||
|
OSMO_VALUE_STRING(MF_E_SRVC_RESET_REQ),
|
||||||
|
OSMO_VALUE_STRING(MF_E_BANKD_CONNECTED),
|
||||||
|
OSMO_VALUE_STRING(MF_E_BANKD_LOST),
|
||||||
|
OSMO_VALUE_STRING(MF_E_BANKD_TPDU),
|
||||||
|
OSMO_VALUE_STRING(MF_E_BANKD_ATR),
|
||||||
|
OSMO_VALUE_STRING(MF_E_BANKD_SLOT_STATUS),
|
||||||
|
OSMO_VALUE_STRING(MF_E_MDM_STATUS_IND),
|
||||||
|
OSMO_VALUE_STRING(MF_E_MDM_PTS_IND),
|
||||||
|
OSMO_VALUE_STRING(MF_E_MDM_TPDU),
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void main_st_operational(struct osmo_fsm_inst *fi, uint32_t event, void *data);
|
||||||
|
|
||||||
|
static void main_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||||
|
{
|
||||||
|
struct bankd_client *bc = (struct bankd_client *) fi->priv;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case MF_E_SRVC_CONNECTED:
|
||||||
|
osmo_fsm_inst_state_chg(fi, MF_ST_UNCONFIGURED, 0, 0);
|
||||||
|
call_script(bc, "event-server-connect");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_st_unconfigured_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||||
|
{
|
||||||
|
struct bankd_client *bc = (struct bankd_client *) fi->priv;
|
||||||
|
/* we might be called from a 'higher' state such as operational; clean up */
|
||||||
|
osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_DISCONNECT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case MF_E_SRVC_CONFIG_BANK:
|
||||||
|
/* same treatment as below */
|
||||||
|
main_st_operational(fi, event, data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_st_wait_bankd(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||||
|
{
|
||||||
|
struct bankd_client *bc = (struct bankd_client *) fi->priv;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case MF_E_SRVC_CONFIG_BANK:
|
||||||
|
/* same treatment as below */
|
||||||
|
main_st_operational(fi, event, data);
|
||||||
|
break;
|
||||||
|
case MF_E_BANKD_CONNECTED:
|
||||||
|
osmo_fsm_inst_state_chg(fi, MF_ST_OPERATIONAL, 0, 0);
|
||||||
|
call_script(bc, "event-bankd-connect");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_st_operational_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||||
|
{
|
||||||
|
struct bankd_client *bc = (struct bankd_client *) fi->priv;
|
||||||
|
|
||||||
|
/* Simulate card-insert to modem */
|
||||||
|
frontend_request_card_insert(bc);
|
||||||
|
call_script(bc, "request-card-insert");
|
||||||
|
|
||||||
|
/* Select remote (forwarded) SIM */
|
||||||
|
frontend_request_sim_remote(bc);
|
||||||
|
call_script(bc, "request-sim-remote");
|
||||||
|
|
||||||
|
/* Set the ATR */
|
||||||
|
frontend_handle_set_atr(bc, bc->cfg->atr.data, bc->cfg->atr.len);
|
||||||
|
|
||||||
|
/* Reset the modem */
|
||||||
|
frontend_request_modem_reset(bc);
|
||||||
|
call_script(bc, "request-modem-reset");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_st_operational(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||||
|
{
|
||||||
|
struct bankd_client *bc = (struct bankd_client *) fi->priv;
|
||||||
|
struct frontend_phys_status *pstatus = NULL;
|
||||||
|
struct frontend_pts *pts = NULL;
|
||||||
|
struct frontend_tpdu *tpdu = NULL;
|
||||||
|
RsproPDU_t *pdu_rx = NULL;
|
||||||
|
RsproPDU_t *resp;
|
||||||
|
BankSlot_t bslot;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case MF_E_BANKD_LOST:
|
||||||
|
osmo_fsm_inst_state_chg(fi, MF_ST_WAIT_BANKD, 0, 0);
|
||||||
|
break;
|
||||||
|
case MF_E_SRVC_CONFIG_BANK:
|
||||||
|
pdu_rx = data;
|
||||||
|
OSMO_ASSERT(pdu_rx);
|
||||||
|
OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_configClientBankReq);
|
||||||
|
/* store/set the bankd ip/port as instructed by the server */
|
||||||
|
osmo_talloc_replace_string(bc, &bc->bankd_conn.server_host,
|
||||||
|
rspro_IpAddr2str(&pdu_rx->msg.choice.configClientBankReq.bankd.ip));
|
||||||
|
bc->bankd_conn.server_port = pdu_rx->msg.choice.configClientBankReq.bankd.port;
|
||||||
|
rspro2bank_slot(&bc->bankd_slot, &pdu_rx->msg.choice.configClientBankReq.bankSlot);
|
||||||
|
/* bankd port 0 is a magic value to indicate "no bankd" */
|
||||||
|
if (bc->bankd_conn.server_port == 0)
|
||||||
|
osmo_fsm_inst_state_chg(fi, MF_ST_UNCONFIGURED, 0, 0);
|
||||||
|
else {
|
||||||
|
osmo_fsm_inst_state_chg(fi, MF_ST_WAIT_BANKD, 0, 0);
|
||||||
|
/* TODO: do we need to disconnect before? */
|
||||||
|
osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_ESTABLISH, NULL);
|
||||||
|
}
|
||||||
|
/* send response to server */
|
||||||
|
resp = rspro_gen_ConfigClientBankRes(ResultCode_ok);
|
||||||
|
server_conn_send_rspro(&bc->srv_conn, resp);
|
||||||
|
call_script(bc, "event-config-bankd");
|
||||||
|
break;
|
||||||
|
case MF_E_BANKD_TPDU:
|
||||||
|
pdu_rx = data;
|
||||||
|
OSMO_ASSERT(pdu_rx);
|
||||||
|
OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_tpduCardToModem);
|
||||||
|
/* forward to modem/cardem (via API) */
|
||||||
|
frontend_handle_card2modem(bc, pdu_rx->msg.choice.tpduCardToModem.data.buf,
|
||||||
|
pdu_rx->msg.choice.tpduCardToModem.data.size);
|
||||||
|
/* response happens indirectly via tpduModemToCard */
|
||||||
|
break;
|
||||||
|
case MF_E_BANKD_ATR:
|
||||||
|
pdu_rx = data;
|
||||||
|
OSMO_ASSERT(pdu_rx);
|
||||||
|
OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_setAtrReq);
|
||||||
|
/* forward to modem/cardem (via API) */
|
||||||
|
frontend_handle_set_atr(bc, pdu_rx->msg.choice.setAtrReq.atr.buf,
|
||||||
|
pdu_rx->msg.choice.setAtrReq.atr.size);
|
||||||
|
/* send response to bankd */
|
||||||
|
resp = rspro_gen_SetAtrRes(ResultCode_ok);
|
||||||
|
server_conn_send_rspro(&bc->bankd_conn, resp);
|
||||||
|
break;
|
||||||
|
case MF_E_BANKD_SLOT_STATUS:
|
||||||
|
pdu_rx = data;
|
||||||
|
OSMO_ASSERT(pdu_rx);
|
||||||
|
OSMO_ASSERT(pdu_rx->msg.present == RsproPDUchoice_PR_bankSlotStatusInd);
|
||||||
|
/* forward to modem/cardem (via API) */
|
||||||
|
frontend_handle_slot_status(bc, &pdu_rx->msg.choice.bankSlotStatusInd.slotPhysStatus);
|
||||||
|
break;
|
||||||
|
case MF_E_MDM_STATUS_IND:
|
||||||
|
pstatus = data;
|
||||||
|
OSMO_ASSERT(pstatus);
|
||||||
|
/* forward to bankd */
|
||||||
|
bank_slot2rspro(&bslot, &bc->bankd_slot);
|
||||||
|
resp = rspro_gen_ClientSlotStatusInd(bc->srv_conn.clslot, &bslot,
|
||||||
|
pstatus->flags.reset_active,
|
||||||
|
pstatus->flags.vcc_present,
|
||||||
|
pstatus->flags.clk_active,
|
||||||
|
pstatus->flags.card_present);
|
||||||
|
server_conn_send_rspro(&bc->bankd_conn, resp);
|
||||||
|
if (!memcmp(&bc->last_status.flags, &pstatus->flags, sizeof(pstatus->flags)))
|
||||||
|
call_script(bc, "event-modem-status");
|
||||||
|
bc->last_status = *pstatus;
|
||||||
|
break;
|
||||||
|
case MF_E_MDM_PTS_IND:
|
||||||
|
pts = data;
|
||||||
|
OSMO_ASSERT(pts);
|
||||||
|
/* forward to bankd? */
|
||||||
|
break;
|
||||||
|
case MF_E_MDM_TPDU:
|
||||||
|
tpdu = data;
|
||||||
|
OSMO_ASSERT(tpdu);
|
||||||
|
/* forward to bankd */
|
||||||
|
bank_slot2rspro(&bslot, &bc->bankd_slot);
|
||||||
|
resp = rspro_gen_TpduModem2Card(bc->srv_conn.clslot, &bslot, tpdu->buf, tpdu->len);
|
||||||
|
server_conn_send_rspro(&bc->bankd_conn, resp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void main_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||||
|
{
|
||||||
|
switch (event) {
|
||||||
|
case MF_E_SRVC_LOST:
|
||||||
|
/* should we do anything? The SRVC fsm will take care of reconnect, and we
|
||||||
|
* can continue to talk to the bankd without any trouble... */
|
||||||
|
break;
|
||||||
|
case MF_E_SRVC_RESET_REQ:
|
||||||
|
osmo_fsm_inst_state_chg(fi, MF_ST_UNCONFIGURED, 0, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct osmo_fsm_state main_fsm_states[] = {
|
||||||
|
[MF_ST_INIT] = {
|
||||||
|
.name = "INIT",
|
||||||
|
.in_event_mask = S(MF_E_SRVC_CONNECTED),
|
||||||
|
.out_state_mask = S(MF_ST_UNCONFIGURED),
|
||||||
|
.action = main_st_init,
|
||||||
|
},
|
||||||
|
[MF_ST_UNCONFIGURED] = {
|
||||||
|
.name = "UNCONFIGURED",
|
||||||
|
.in_event_mask = S(MF_E_SRVC_CONFIG_BANK),
|
||||||
|
.out_state_mask = S(MF_ST_INIT) | S(MF_ST_WAIT_BANKD),
|
||||||
|
.action = main_st_unconfigured,
|
||||||
|
.onenter = main_st_unconfigured_onenter,
|
||||||
|
},
|
||||||
|
[MF_ST_WAIT_BANKD] = {
|
||||||
|
.name = "WAIT_BANKD",
|
||||||
|
.in_event_mask = S(MF_E_SRVC_CONFIG_BANK) | S(MF_E_BANKD_CONNECTED),
|
||||||
|
.out_state_mask = S(MF_ST_INIT) | S(MF_ST_UNCONFIGURED) | S(MF_ST_OPERATIONAL),
|
||||||
|
.action = main_st_wait_bankd,
|
||||||
|
},
|
||||||
|
[MF_ST_OPERATIONAL] = {
|
||||||
|
.name = "OPERATIONAL",
|
||||||
|
.in_event_mask = S(MF_E_SRVC_CONFIG_BANK) |
|
||||||
|
S(MF_E_BANKD_LOST) |
|
||||||
|
S(MF_E_BANKD_TPDU) |
|
||||||
|
S(MF_E_BANKD_ATR) |
|
||||||
|
S(MF_E_BANKD_SLOT_STATUS) |
|
||||||
|
S(MF_E_MDM_STATUS_IND) |
|
||||||
|
S(MF_E_MDM_PTS_IND) |
|
||||||
|
S(MF_E_MDM_TPDU),
|
||||||
|
.out_state_mask = S(MF_ST_INIT) | S(MF_ST_UNCONFIGURED) | S(MF_ST_WAIT_BANKD),
|
||||||
|
.action = main_st_operational,
|
||||||
|
.onenter = main_st_operational_onenter,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct osmo_fsm client_main_fsm = {
|
||||||
|
.name = "CLIENT_MAIN",
|
||||||
|
.states = main_fsm_states,
|
||||||
|
.num_states = ARRAY_SIZE(main_fsm_states),
|
||||||
|
.allstate_event_mask = S(MF_E_SRVC_LOST) | S(MF_E_SRVC_RESET_REQ),
|
||||||
|
.allstate_action = main_allstate_action,
|
||||||
|
.log_subsys = DMAIN,
|
||||||
|
.event_names = main_fsm_event_names,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct osmo_fsm_inst *main_fsm_alloc(void *ctx, struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
return osmo_fsm_inst_alloc(&client_main_fsm, ctx, bc, LOGL_DEBUG, "main");
|
||||||
|
}
|
||||||
|
|
||||||
|
static __attribute((constructor)) void on_dso_load_main_fsm(void)
|
||||||
|
{
|
||||||
|
OSMO_ASSERT(osmo_fsm_register(&client_main_fsm) == 0);
|
||||||
|
}
|
|
@ -20,6 +20,10 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* This file contains code shared among all remsim client applications,
|
||||||
|
* including the ifd-handler, which is not an executable program with a main()
|
||||||
|
* function or command line parsing, but a shared library */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -33,8 +37,38 @@
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
struct client_config *client_config_init(void *ctx)
|
||||||
|
{
|
||||||
|
struct client_config *cfg = talloc_zero(ctx, struct client_config);
|
||||||
|
if (!cfg)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cfg->server_host = talloc_strdup(cfg, "127.0.0.1");
|
||||||
|
cfg->server_port = 9998;
|
||||||
|
cfg->client_id = -1;
|
||||||
|
cfg->client_slot = -1;
|
||||||
|
cfg->gsmtap_host = talloc_strdup(cfg, "127.0.0.1");
|
||||||
|
cfg->keep_running = false;
|
||||||
|
|
||||||
|
cfg->usb.vendor_id = -1;
|
||||||
|
cfg->usb.product_id = -1;
|
||||||
|
cfg->usb.config_id = -1;
|
||||||
|
cfg->usb.if_num = -1;
|
||||||
|
cfg->usb.altsetting = 0;
|
||||||
|
cfg->usb.addr = -1;
|
||||||
|
cfg->usb.path = NULL;
|
||||||
|
|
||||||
|
cfg->atr.data[0] = 0x3B;
|
||||||
|
cfg->atr.data[1] = 0x00; // the shortest simplest ATR possible
|
||||||
|
cfg->atr.len = 2;
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
};
|
||||||
|
|
||||||
static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)
|
static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)
|
||||||
{
|
{
|
||||||
|
struct bankd_client *bc = bankdc2bankd_client(bankdc);
|
||||||
|
|
||||||
switch (pdu->msg.present) {
|
switch (pdu->msg.present) {
|
||||||
case RsproPDUchoice_PR_connectClientRes:
|
case RsproPDUchoice_PR_connectClientRes:
|
||||||
/* Store 'identity' of bankd to in peer_comp_id */
|
/* Store 'identity' of bankd to in peer_comp_id */
|
||||||
|
@ -42,8 +76,11 @@ static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *p
|
||||||
osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu);
|
osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu);
|
||||||
break;
|
break;
|
||||||
case RsproPDUchoice_PR_tpduCardToModem:
|
case RsproPDUchoice_PR_tpduCardToModem:
|
||||||
|
return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_TPDU, (void *) pdu);
|
||||||
case RsproPDUchoice_PR_setAtrReq:
|
case RsproPDUchoice_PR_setAtrReq:
|
||||||
return client_user_bankd_handle_rx(bankdc, pdu);
|
return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_ATR, (void *) pdu);
|
||||||
|
case RsproPDUchoice_PR_bankSlotStatusInd:
|
||||||
|
return osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_SLOT_STATUS, (void *) pdu);
|
||||||
default:
|
default:
|
||||||
LOGPFSML(bankdc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU %s\n",
|
LOGPFSML(bankdc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU %s\n",
|
||||||
rspro_msgt_name(pdu));
|
rspro_msgt_name(pdu));
|
||||||
|
@ -78,19 +115,7 @@ static int srvc_handle_rx(struct rspro_server_conn *srvc, const RsproPDU_t *pdu)
|
||||||
server_conn_send_rspro(srvc, resp);
|
server_conn_send_rspro(srvc, resp);
|
||||||
break;
|
break;
|
||||||
case RsproPDUchoice_PR_configClientBankReq:
|
case RsproPDUchoice_PR_configClientBankReq:
|
||||||
/* store/set the bankd ip/port as instructed by the server */
|
osmo_fsm_inst_dispatch(bc->main_fi, MF_E_SRVC_CONFIG_BANK, (void *) pdu);
|
||||||
osmo_talloc_replace_string(bc, &bc->bankd_conn.server_host,
|
|
||||||
rspro_IpAddr2str(&pdu->msg.choice.configClientBankReq.bankd.ip));
|
|
||||||
rspro2bank_slot(&bc->bankd_slot, &pdu->msg.choice.configClientBankReq.bankSlot);
|
|
||||||
bc->bankd_conn.server_port = pdu->msg.choice.configClientBankReq.bankd.port;
|
|
||||||
/* bankd port 0 is a magic value to indicate "no bankd" */
|
|
||||||
if (bc->bankd_conn.server_port == 0)
|
|
||||||
osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_DISCONNECT, NULL);
|
|
||||||
else
|
|
||||||
osmo_fsm_inst_dispatch(bc->bankd_conn.fi, SRVC_E_ESTABLISH, NULL);
|
|
||||||
/* send response to server */
|
|
||||||
resp = rspro_gen_ConfigClientBankRes(ResultCode_ok);
|
|
||||||
server_conn_send_rspro(srvc, resp);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGPFSML(srvc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU type: %s\n",
|
LOGPFSML(srvc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU type: %s\n",
|
||||||
|
@ -101,7 +126,8 @@ static int srvc_handle_rx(struct rspro_server_conn *srvc, const RsproPDU_t *pdu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software)
|
struct bankd_client *remsim_client_create(void *ctx, const char *name, const char *software,
|
||||||
|
struct client_config *cfg)
|
||||||
{
|
{
|
||||||
struct bankd_client *bc = talloc_zero(ctx, struct bankd_client);
|
struct bankd_client *bc = talloc_zero(ctx, struct bankd_client);
|
||||||
struct rspro_server_conn *srvc, *bankdc;
|
struct rspro_server_conn *srvc, *bankdc;
|
||||||
|
@ -110,10 +136,20 @@ struct bankd_client *remsim_client_create(void *ctx, const char *name, const cha
|
||||||
if (!bc)
|
if (!bc)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
bc->cfg = cfg;
|
||||||
|
|
||||||
|
bc->main_fi = main_fsm_alloc(bc, bc);
|
||||||
|
if (!bc->main_fi) {
|
||||||
|
fprintf(stderr, "Unable to create main client FSM: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
remsim_client_set_clslot(bc, cfg->client_id, cfg->client_slot);
|
||||||
|
|
||||||
/* create and [attempt to] establish connection to remsim-server */
|
/* create and [attempt to] establish connection to remsim-server */
|
||||||
srvc = &bc->srv_conn;
|
srvc = &bc->srv_conn;
|
||||||
srvc->server_host = "localhost";
|
srvc->server_host = cfg->server_host;
|
||||||
srvc->server_port = 9998;
|
srvc->server_port = cfg->server_port;
|
||||||
srvc->handle_rx = srvc_handle_rx;
|
srvc->handle_rx = srvc_handle_rx;
|
||||||
srvc->own_comp_id.type = ComponentType_remsimClient;
|
srvc->own_comp_id.type = ComponentType_remsimClient;
|
||||||
OSMO_STRLCPY_ARRAY(srvc->own_comp_id.name, name);
|
OSMO_STRLCPY_ARRAY(srvc->own_comp_id.name, name);
|
||||||
|
@ -125,6 +161,9 @@ struct bankd_client *remsim_client_create(void *ctx, const char *name, const cha
|
||||||
fprintf(stderr, "Unable to create Server conn FSM: %s\n", strerror(errno));
|
fprintf(stderr, "Unable to create Server conn FSM: %s\n", strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
osmo_fsm_inst_change_parent(srvc->fi, bc->main_fi, MF_E_SRVC_LOST);
|
||||||
|
srvc->parent_conn_evt = MF_E_SRVC_CONNECTED;
|
||||||
|
srvc->parent_disc_evt = MF_E_SRVC_LOST;
|
||||||
|
|
||||||
bankdc = &bc->bankd_conn;
|
bankdc = &bc->bankd_conn;
|
||||||
/* server_host / server_port are configured from remsim-server */
|
/* server_host / server_port are configured from remsim-server */
|
||||||
|
@ -136,6 +175,9 @@ struct bankd_client *remsim_client_create(void *ctx, const char *name, const cha
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
osmo_fsm_inst_update_id(bankdc->fi, "bankd");
|
osmo_fsm_inst_update_id(bankdc->fi, "bankd");
|
||||||
|
osmo_fsm_inst_change_parent(bankdc->fi, bc->main_fi, MF_E_BANKD_LOST);
|
||||||
|
bankdc->parent_conn_evt = MF_E_BANKD_CONNECTED;
|
||||||
|
bankdc->parent_disc_evt = MF_E_BANKD_LOST;
|
||||||
|
|
||||||
return bc;
|
return bc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,27 +23,56 @@ static void printf_help()
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
" -h --help Print this help message\n"
|
" -h --help Print this help message\n"
|
||||||
|
" -v --version Print program version\n"
|
||||||
" -i --server-ip A.B.C.D remsim-server IP address\n"
|
" -i --server-ip A.B.C.D remsim-server IP address\n"
|
||||||
" -p --server-port 13245 remsim-server TCP port\n"
|
" -p --server-port 13245 remsim-server TCP port\n"
|
||||||
" -i --client-id <0-65535> RSPRO ClientId of this client\n"
|
" -c --client-id <0-65535> RSPRO ClientId of this client\n"
|
||||||
" -n --client-slot <0-65535> RSPRO SlotNr of this client\n"
|
" -n --client-slot <0-65535> RSPRO SlotNr of this client\n"
|
||||||
|
" -e --event-script <path> event script to be called by client\n"
|
||||||
|
#ifdef USB_SUPPORT
|
||||||
|
" -V --usb-vendor VENDOR_ID\n"
|
||||||
|
" -P --usb-product PRODUCT_ID\n"
|
||||||
|
" -C --usb-config CONFIG_ID\n"
|
||||||
|
" -I --usb-interface INTERFACE_ID\n"
|
||||||
|
" -S --usb-altsetting ALTSETTING_ID\n"
|
||||||
|
" -A --usb-address ADDRESS\n"
|
||||||
|
" -H --usb-path PATH\n"
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_options(struct bankd_client *bc, int argc, char **argv)
|
static void handle_options(struct client_config *cfg, int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int option_index = 0, c;
|
int option_index = 0, c;
|
||||||
static const struct option long_options[] = {
|
static const struct option long_options[] = {
|
||||||
{ "help", 0, 0, 'h' },
|
{ "help", 0, 0, 'h' },
|
||||||
|
{ "version", 0, 0, 'v' },
|
||||||
{ "server-ip", 1, 0, 'i' },
|
{ "server-ip", 1, 0, 'i' },
|
||||||
{ "server-port", 1, 0, 'p' },
|
{ "server-port", 1, 0, 'p' },
|
||||||
{ "client-id", 1, 0, 'c' },
|
{ "client-id", 1, 0, 'c' },
|
||||||
{ "client-slot", 1, 0, 'n' },
|
{ "client-slot", 1, 0, 'n' },
|
||||||
|
{ "atr", 1, 0, 'a' },
|
||||||
|
{ "event-script", 1, 0, 'e' },
|
||||||
|
#ifdef USB_SUPPORT
|
||||||
|
{ "usb-vendor", 1, 0, 'V' },
|
||||||
|
{ "usb-product", 1, 0, 'P' },
|
||||||
|
{ "usb-config", 1, 0, 'C' },
|
||||||
|
{ "usb-interface", 1, 0, 'I' },
|
||||||
|
{ "usb-altsetting", 1, 0, 'S' },
|
||||||
|
{ "usb-address", 1, 0, 'A' },
|
||||||
|
{ "usb-path", 1, 0, 'H' },
|
||||||
|
#endif
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "hi:p:c:n:",
|
c = getopt_long(argc, argv, "hvi:p:c:n:e:"
|
||||||
|
#ifdef USB_SUPPORT
|
||||||
|
"V:P:C:I:S:A:H:"
|
||||||
|
#endif
|
||||||
|
,
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -53,18 +82,55 @@ static void handle_options(struct bankd_client *bc, int argc, char **argv)
|
||||||
printf_help();
|
printf_help();
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
printf("osmo-remsim-client version %s\n", VERSION);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
bc->srv_conn.server_host = optarg;
|
osmo_talloc_replace_string(cfg, &cfg->server_host, optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
bc->srv_conn.server_port = atoi(optarg);
|
cfg->server_port = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
remsim_client_set_clslot(bc, atoi(optarg), -1);
|
cfg->client_id = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
remsim_client_set_clslot(bc, -1, atoi(optarg));
|
cfg->client_slot = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
rc = osmo_hexparse(optarg, cfg->atr.data, ARRAY_SIZE(cfg->atr.data));
|
||||||
|
if (rc < 2 || rc > ARRAY_SIZE(cfg->atr.data)) {
|
||||||
|
fprintf(stderr, "ATR malformed\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
osmo_talloc_replace_string(cfg, &cfg->event_script, optarg);
|
||||||
|
break;
|
||||||
|
#ifdef USB_SUPPORT
|
||||||
|
case 'V':
|
||||||
|
cfg->usb.vendor_id = strtol(optarg, NULL, 16);
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
cfg->usb.product_id = strtol(optarg, NULL, 16);
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
cfg->usb.config_id = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
cfg->usb.if_num = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
cfg->usb.altsetting = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
cfg->usb.addr = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
cfg->usb.path = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -74,6 +140,7 @@ static void handle_options(struct bankd_client *bc, int argc, char **argv)
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct bankd_client *g_client;
|
struct bankd_client *g_client;
|
||||||
|
struct client_config *cfg;
|
||||||
char hostname[256];
|
char hostname[256];
|
||||||
|
|
||||||
gethostname(hostname, sizeof(hostname));
|
gethostname(hostname, sizeof(hostname));
|
||||||
|
@ -84,9 +151,11 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
osmo_init_logging2(g_tall_ctx, &log_info);
|
osmo_init_logging2(g_tall_ctx, &log_info);
|
||||||
|
|
||||||
g_client = remsim_client_create(g_tall_ctx, hostname, "remsim-client");
|
cfg = client_config_init(g_tall_ctx);
|
||||||
|
OSMO_ASSERT(cfg);
|
||||||
|
handle_options(cfg, argc, argv);
|
||||||
|
|
||||||
handle_options(g_client, argc, argv);
|
g_client = remsim_client_create(g_tall_ctx, hostname, "remsim-client",cfg);
|
||||||
|
|
||||||
osmo_fsm_inst_dispatch(g_client->srv_conn.fi, SRVC_E_ESTABLISH, NULL);
|
osmo_fsm_inst_dispatch(g_client->srv_conn.fi, SRVC_E_ESTABLISH, NULL);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -148,70 +148,66 @@ static void enqueue_to_ifd(struct client_thread *ct, struct msgb *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Incoming RSPRO messages from bank-daemon (SIM card)
|
* frontend to remsim-client main FSM code
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu)
|
int frontend_request_card_insert(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_request_sim_remote(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_request_modem_reset(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
const struct TpduCardToModem *card2modem;
|
|
||||||
struct client_thread *ct = bc->data;
|
struct client_thread *ct = bc->data;
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
|
|
||||||
OSMO_ASSERT(pdu);
|
OSMO_ASSERT(data);
|
||||||
OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present);
|
|
||||||
|
|
||||||
card2modem = &pdu->msg.choice.tpduCardToModem;
|
DEBUGP(DMAIN, "R-APDU: %s\n", osmo_hexdump(data, len));
|
||||||
DEBUGP(DMAIN, "R-APDU: %s\n", osmo_hexdump(card2modem->data.buf, card2modem->data.size));
|
|
||||||
/* enqueue towards IFD thread */
|
/* enqueue towards IFD thread */
|
||||||
msg = itmsg_alloc(ITMSG_TYPE_R_APDU_IND, 0, card2modem->data.buf, card2modem->data.size);
|
msg = itmsg_alloc(ITMSG_TYPE_R_APDU_IND, 0, data, len);
|
||||||
OSMO_ASSERT(msg);
|
OSMO_ASSERT(msg);
|
||||||
enqueue_to_ifd(ct, msg);
|
enqueue_to_ifd(ct, msg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu)
|
int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
struct client_thread *ct = bc->data;
|
struct client_thread *ct = bc->data;
|
||||||
RsproPDU_t *resp;
|
|
||||||
unsigned int atr_len;
|
unsigned int atr_len;
|
||||||
|
|
||||||
OSMO_ASSERT(pdu);
|
OSMO_ASSERT(data);
|
||||||
OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present);
|
|
||||||
|
|
||||||
DEBUGP(DMAIN, "SET_ATR: %s\n", osmo_hexdump(pdu->msg.choice.setAtrReq.atr.buf,
|
DEBUGP(DMAIN, "SET_ATR: %s\n", osmo_hexdump(data, len));
|
||||||
pdu->msg.choice.setAtrReq.atr.size));
|
|
||||||
|
|
||||||
/* store ATR in local data structure until somebody needs it */
|
/* store ATR in local data structure until somebody needs it */
|
||||||
atr_len = pdu->msg.choice.setAtrReq.atr.size;
|
atr_len = len;
|
||||||
if (atr_len > sizeof(ct->atr))
|
if (atr_len > sizeof(ct->atr))
|
||||||
atr_len = sizeof(ct->atr);
|
atr_len = sizeof(ct->atr);
|
||||||
memcpy(ct->atr, pdu->msg.choice.setAtrReq.atr.buf, atr_len);
|
memcpy(ct->atr, data, atr_len);
|
||||||
ct->atr_len = atr_len;
|
ct->atr_len = atr_len;
|
||||||
|
|
||||||
resp = rspro_gen_SetAtrRes(ResultCode_ok);
|
|
||||||
if (!resp)
|
|
||||||
return -ENOMEM;
|
|
||||||
server_conn_send_rspro(&bc->bankd_conn, resp);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts)
|
||||||
int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)
|
|
||||||
{
|
{
|
||||||
struct bankd_client *bc = bankdc2bankd_client(bankdc);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (pdu->msg.present) {
|
int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env)
|
||||||
case RsproPDUchoice_PR_tpduCardToModem:
|
{
|
||||||
bankd_handle_tpduCardToModem(bc, pdu);
|
|
||||||
break;
|
|
||||||
case RsproPDUchoice_PR_setAtrReq:
|
|
||||||
bankd_handle_setAtrReq(bc, pdu);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
OSMO_ASSERT(0);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +359,7 @@ static void client_pthread_cleanup(void *arg)
|
||||||
static void *client_pthread_main(void *arg)
|
static void *client_pthread_main(void *arg)
|
||||||
{
|
{
|
||||||
struct client_thread_cfg *cfg = arg;
|
struct client_thread_cfg *cfg = arg;
|
||||||
|
struct client_config *ccfg;
|
||||||
struct client_thread *ct;
|
struct client_thread *ct;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -373,17 +370,20 @@ static void *client_pthread_main(void *arg)
|
||||||
ct = talloc_zero(OTC_GLOBAL, struct client_thread);
|
ct = talloc_zero(OTC_GLOBAL, struct client_thread);
|
||||||
OSMO_ASSERT(ct);
|
OSMO_ASSERT(ct);
|
||||||
|
|
||||||
|
ccfg = client_config_init(ct);
|
||||||
|
OSMO_ASSERT(ccfg);
|
||||||
|
osmo_talloc_replace_string(ccfg, &ccfg->server_host, cfg->server_host);
|
||||||
|
if (cfg->server_port >= 0)
|
||||||
|
ccfg->server_port = cfg->server_port;
|
||||||
|
ccfg->client_id = cfg->client_id;
|
||||||
|
ccfg->client_slot = cfg->client_slot;
|
||||||
|
|
||||||
if (!talloc_asn1_ctx)
|
if (!talloc_asn1_ctx)
|
||||||
talloc_asn1_ctx= talloc_named_const(ct, 0, "asn1");
|
talloc_asn1_ctx= talloc_named_const(ct, 0, "asn1");
|
||||||
|
|
||||||
ct->bc = remsim_client_create(ct, cfg->name, "remsim_ifdhandler");
|
ct->bc = remsim_client_create(ct, cfg->name, "remsim_ifdhandler", ccfg);
|
||||||
OSMO_ASSERT(ct->bc);
|
OSMO_ASSERT(ct->bc);
|
||||||
ct->bc->data = ct;
|
ct->bc->data = ct;
|
||||||
remsim_client_set_clslot(ct->bc, cfg->client_id, cfg->client_slot);
|
|
||||||
if (cfg->server_host)
|
|
||||||
ct->bc->srv_conn.server_host = (char *) cfg->server_host;
|
|
||||||
if (cfg->server_port >= 0)
|
|
||||||
ct->bc->srv_conn.server_port = cfg->server_port;
|
|
||||||
|
|
||||||
INIT_LLIST_HEAD(&ct->it_msgq);
|
INIT_LLIST_HEAD(&ct->it_msgq);
|
||||||
osmo_fd_setup(&ct->it_ofd, cfg->it_sock_fd, OSMO_FD_READ, &it_sock_fd_cb, ct, 0);
|
osmo_fd_setup(&ct->it_ofd, cfg->it_sock_fd, OSMO_FD_READ, &it_sock_fd_cb, ct, 0);
|
||||||
|
|
|
@ -12,58 +12,54 @@
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Incoming RSPRO messages from bank-daemon (SIM card)
|
* stdin frontend code to remsim-client
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
static int bankd_handle_tpduCardToModem(struct bankd_client *bc, const RsproPDU_t *pdu)
|
int frontend_request_card_insert(struct bankd_client *bc)
|
||||||
{
|
{
|
||||||
OSMO_ASSERT(pdu);
|
return 0;
|
||||||
OSMO_ASSERT(RsproPDUchoice_PR_tpduCardToModem == pdu->msg.present);
|
}
|
||||||
|
|
||||||
const struct TpduCardToModem *card2modem = &pdu->msg.choice.tpduCardToModem;
|
int frontend_request_sim_remote(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
printf("R-APDU: %s\n", osmo_hexdump(card2modem->data.buf, card2modem->data.size));
|
int frontend_request_modem_reset(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
OSMO_ASSERT(data);
|
||||||
|
printf("R-APDU: %s\n", osmo_hexdump(data, len));
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bankd_handle_setAtrReq(struct bankd_client *bc, const RsproPDU_t *pdu)
|
int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
RsproPDU_t *resp;
|
OSMO_ASSERT(data);
|
||||||
|
|
||||||
OSMO_ASSERT(pdu);
|
printf("SET_ATR: %s\n", osmo_hexdump(data, len));
|
||||||
OSMO_ASSERT(RsproPDUchoice_PR_setAtrReq == pdu->msg.present);
|
|
||||||
|
|
||||||
printf("SET_ATR: %s\n", osmo_hexdump(pdu->msg.choice.setAtrReq.atr.buf,
|
|
||||||
pdu->msg.choice.setAtrReq.atr.size));
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
resp = rspro_gen_SetAtrRes(ResultCode_ok);
|
|
||||||
if (!resp)
|
|
||||||
return -ENOMEM;
|
|
||||||
server_conn_send_rspro(&bc->bankd_conn, resp);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts)
|
||||||
int client_user_bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *pdu)
|
|
||||||
{
|
{
|
||||||
struct bankd_client *client = bankdc2bankd_client(bankdc);
|
|
||||||
switch (pdu->msg.present) {
|
|
||||||
case RsproPDUchoice_PR_tpduCardToModem:
|
|
||||||
bankd_handle_tpduCardToModem(client, pdu);
|
|
||||||
break;
|
|
||||||
case RsproPDUchoice_PR_setAtrReq:
|
|
||||||
bankd_handle_setAtrReq(client, pdu);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
OSMO_ASSERT(0);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Incoming command from the user application (stdin shell in our case)
|
* Incoming command from the user application (stdin shell in our case)
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
|
@ -0,0 +1,458 @@
|
||||||
|
/* (C) 2018-2020 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/fsm.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
|
||||||
|
#include <osmocom/usb/libusb.h>
|
||||||
|
|
||||||
|
#include <osmocom/simtrace2/apdu_dispatch.h>
|
||||||
|
#include <osmocom/simtrace2/simtrace2_api.h>
|
||||||
|
#include <osmocom/simtrace2/simtrace_prot.h>
|
||||||
|
|
||||||
|
#include "client.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* Incoming Messages from cardem firmware
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
/*! \brief Process a STATUS message from the SIMtrace2 */
|
||||||
|
static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct cardemu_usb_msg_status *status;
|
||||||
|
status = (struct cardemu_usb_msg_status *) buf;
|
||||||
|
|
||||||
|
printf("SIMtrace => STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
|
||||||
|
status->flags, status->fi, status->di, status->wi,
|
||||||
|
status->waiting_time);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Process a PTS indication message from the SIMtrace2 */
|
||||||
|
static int process_do_pts(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct cardemu_usb_msg_pts_info *pts = (struct cardemu_usb_msg_pts_info *) buf;
|
||||||
|
struct bankd_client *bc = ci->priv;
|
||||||
|
struct frontend_pts fpts = {
|
||||||
|
.buf = pts->req,
|
||||||
|
.len = sizeof(pts->req),
|
||||||
|
};
|
||||||
|
|
||||||
|
printf("SIMtrace => PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req)));
|
||||||
|
|
||||||
|
osmo_fsm_inst_dispatch(bc->main_fi, MF_E_MDM_PTS_IND, &fpts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Process a ERROR indication message from the SIMtrace2 */
|
||||||
|
__attribute__((unused)) static int process_do_error(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct cardemu_usb_msg_error *err;
|
||||||
|
err = (struct cardemu_usb_msg_error *) buf;
|
||||||
|
|
||||||
|
printf("SIMtrace => ERROR: %u/%u/%u: %s\n",
|
||||||
|
err->severity, err->subsystem, err->code,
|
||||||
|
err->msg_len ? (char *)err->msg : "");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct osmo_apdu_context ac; // this will hold the complete APDU (across calls)
|
||||||
|
|
||||||
|
/*! \brief Process a RX-DATA indication message from the SIMtrace2 */
|
||||||
|
static int process_do_rx_da(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct cardemu_usb_msg_rx_data *data = (struct cardemu_usb_msg_rx_data *) buf;
|
||||||
|
struct bankd_client *bc = ci->priv;
|
||||||
|
struct frontend_tpdu ftpdu;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("SIMtrace => DATA: flags=%x, %s: ", data->flags,
|
||||||
|
osmo_hexdump(data->data, data->data_len));
|
||||||
|
|
||||||
|
/* parse the APDU data in the USB message */
|
||||||
|
rc = osmo_apdu_segment_in(&ac, data->data, data->data_len,
|
||||||
|
data->flags & CEMU_DATA_F_TPDU_HDR);
|
||||||
|
|
||||||
|
if (rc & APDU_ACT_TX_CAPDU_TO_CARD) {
|
||||||
|
/* there is no pending data coming from the modem */
|
||||||
|
uint8_t apdu_command[sizeof(ac.hdr) + ac.lc.tot];
|
||||||
|
memcpy(apdu_command, &ac.hdr, sizeof(ac.hdr));
|
||||||
|
if (ac.lc.tot)
|
||||||
|
memcpy(apdu_command + sizeof(ac.hdr), ac.dc, ac.lc.tot);
|
||||||
|
/* send APDU to card */
|
||||||
|
ftpdu.buf = apdu_command;
|
||||||
|
ftpdu.len = sizeof(ac.hdr) + ac.lc.tot;
|
||||||
|
osmo_fsm_inst_dispatch(bc->main_fi, MF_E_BANKD_TPDU, &ftpdu);
|
||||||
|
} else if (ac.lc.tot > ac.lc.cur) {
|
||||||
|
/* there is pending data from the modem: send procedure byte to get remaining data */
|
||||||
|
osmo_st2_cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
case SIMTRACE_CMD_DO_ERROR
|
||||||
|
rc = process_do_error(ci, buf, len);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \brief Process an incoming message from the SIMtrace2 */
|
||||||
|
static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("SIMtrace -> %s\n", osmo_hexdump(buf, len));
|
||||||
|
|
||||||
|
buf += sizeof(*sh);
|
||||||
|
|
||||||
|
switch (sh->msg_type) {
|
||||||
|
case SIMTRACE_MSGT_BD_CEMU_STATUS:
|
||||||
|
rc = process_do_status(ci, buf, len);
|
||||||
|
break;
|
||||||
|
case SIMTRACE_MSGT_DO_CEMU_PTS:
|
||||||
|
rc = process_do_pts(ci, buf, len);
|
||||||
|
break;
|
||||||
|
case SIMTRACE_MSGT_DO_CEMU_RX_DATA:
|
||||||
|
rc = process_do_rx_da(ci, buf, len);
|
||||||
|
break;
|
||||||
|
case SIMTRACE_MSGT_BD_CEMU_CONFIG:
|
||||||
|
/* firmware confirms configuration change; ignore */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */
|
||||||
|
static int process_irq_status(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;
|
||||||
|
struct bankd_client *bc = ci->priv;
|
||||||
|
struct frontend_phys_status pstatus = {
|
||||||
|
.flags = {
|
||||||
|
.reset_active = status->flags & CEMU_STATUS_F_RESET_ACTIVE,
|
||||||
|
.vcc_present = status->flags & CEMU_STATUS_F_VCC_PRESENT,
|
||||||
|
.clk_active = status->flags & CEMU_STATUS_F_CLK_ACTIVE,
|
||||||
|
.card_present = -1 /* FIXME: make this dependent on board */,
|
||||||
|
},
|
||||||
|
.voltage_mv = status->voltage_mv,
|
||||||
|
.fi = status->fi,
|
||||||
|
.di = status->di,
|
||||||
|
.wi = status->wi,
|
||||||
|
.waiting_time = status->waiting_time,
|
||||||
|
};
|
||||||
|
|
||||||
|
printf("SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
|
||||||
|
status->flags, status->fi, status->di, status->wi,
|
||||||
|
status->waiting_time);
|
||||||
|
|
||||||
|
osmo_fsm_inst_dispatch(bc->main_fi, MF_E_MDM_STATUS_IND, &pstatus);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int process_usb_msg_irq(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("SIMtrace IRQ %s\n", osmo_hexdump(buf, len));
|
||||||
|
|
||||||
|
buf += sizeof(*sh);
|
||||||
|
|
||||||
|
switch (sh->msg_type) {
|
||||||
|
case SIMTRACE_MSGT_BD_CEMU_STATUS:
|
||||||
|
rc = process_irq_status(ci, buf, len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usb_in_xfer_cb(struct libusb_transfer *xfer)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = xfer->user_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
switch (xfer->status) {
|
||||||
|
case LIBUSB_TRANSFER_COMPLETED:
|
||||||
|
/* hand the message up the stack */
|
||||||
|
process_usb_msg(ci, xfer->buffer, xfer->actual_length);
|
||||||
|
break;
|
||||||
|
case LIBUSB_TRANSFER_NO_DEVICE:
|
||||||
|
fprintf(stderr, "USB device disappeared\n");
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "USB IN transfer failed, status=%u\n", xfer->status);
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-submit the IN transfer */
|
||||||
|
rc = libusb_submit_transfer(xfer);
|
||||||
|
OSMO_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void allocate_and_submit_in(struct osmo_st2_cardem_inst *ci)
|
||||||
|
{
|
||||||
|
struct osmo_st2_transport *transp = ci->slot->transp;
|
||||||
|
struct libusb_transfer *xfer;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
xfer = libusb_alloc_transfer(0);
|
||||||
|
OSMO_ASSERT(xfer);
|
||||||
|
xfer->dev_handle = transp->usb_devh;
|
||||||
|
xfer->flags = 0;
|
||||||
|
xfer->type = LIBUSB_TRANSFER_TYPE_BULK;
|
||||||
|
xfer->endpoint = transp->usb_ep.in;
|
||||||
|
xfer->timeout = 0;
|
||||||
|
xfer->user_data = ci;
|
||||||
|
xfer->length = 16*256;
|
||||||
|
|
||||||
|
xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
|
||||||
|
OSMO_ASSERT(xfer->buffer);
|
||||||
|
xfer->callback = usb_in_xfer_cb;
|
||||||
|
|
||||||
|
/* submit the IN transfer */
|
||||||
|
rc = libusb_submit_transfer(xfer);
|
||||||
|
OSMO_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void usb_irq_xfer_cb(struct libusb_transfer *xfer)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = xfer->user_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
switch (xfer->status) {
|
||||||
|
case LIBUSB_TRANSFER_COMPLETED:
|
||||||
|
process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length);
|
||||||
|
break;
|
||||||
|
case LIBUSB_TRANSFER_NO_DEVICE:
|
||||||
|
fprintf(stderr, "USB device disappeared\n");
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "USB IRQ transfer failed, status=%u\n", xfer->status);
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-submit the IN transfer */
|
||||||
|
rc = libusb_submit_transfer(xfer);
|
||||||
|
OSMO_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void allocate_and_submit_irq(struct osmo_st2_cardem_inst *ci)
|
||||||
|
{
|
||||||
|
struct osmo_st2_transport *transp = ci->slot->transp;
|
||||||
|
struct libusb_transfer *xfer;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
xfer = libusb_alloc_transfer(0);
|
||||||
|
OSMO_ASSERT(xfer);
|
||||||
|
xfer->dev_handle = transp->usb_devh;
|
||||||
|
xfer->flags = 0;
|
||||||
|
xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
|
||||||
|
xfer->endpoint = transp->usb_ep.irq_in;
|
||||||
|
xfer->timeout = 0;
|
||||||
|
xfer->user_data = ci;
|
||||||
|
xfer->length = 64;
|
||||||
|
|
||||||
|
xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
|
||||||
|
OSMO_ASSERT(xfer->buffer);
|
||||||
|
xfer->callback = usb_irq_xfer_cb;
|
||||||
|
|
||||||
|
/* submit the IN transfer */
|
||||||
|
rc = libusb_submit_transfer(xfer);
|
||||||
|
OSMO_ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* simtrace2 frontend code to remsim-client
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
int frontend_request_card_insert(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = bc->cardem;
|
||||||
|
return osmo_st2_cardem_request_card_insert(ci, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_request_sim_remote(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = bc->cardem;
|
||||||
|
return osmo_st2_modem_sim_select_remote(ci->slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_request_modem_reset(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = bc->cardem;
|
||||||
|
return osmo_st2_modem_reset_pulse(ci->slot, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_handle_card2modem(struct bankd_client *bc, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = bc->cardem;
|
||||||
|
// save SW to our current APDU context
|
||||||
|
ac.sw[0] = data[len-2];
|
||||||
|
ac.sw[1] = data[len=1];
|
||||||
|
|
||||||
|
printf("SIMtrace <= SW=0x%02x%02x, len_rx=%zu\n", ac.sw[0], ac.sw[1], len-2);
|
||||||
|
if (len > 2) { // send PB and data to modem
|
||||||
|
osmo_st2_cardem_request_pb_and_tx(ci, ac.hdr.ins, data, len-2);
|
||||||
|
}
|
||||||
|
osmo_st2_cardem_request_sw_tx(ci, ac.sw); // send SW to modem
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_handle_set_atr(struct bankd_client *bc, const uint8_t *data, size_t len)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = bc->cardem;
|
||||||
|
return osmo_st2_cardem_request_set_atr(ci, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_handle_slot_status(struct bankd_client *bc, const SlotPhysStatus_t *sts)
|
||||||
|
{
|
||||||
|
/* we currently don't propagate bankd status to cardem */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int frontend_append_script_env(struct bankd_client *bc, char **env, size_t max_env)
|
||||||
|
{
|
||||||
|
struct osmo_st2_cardem_inst *ci = bc->cardem;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (max_env < 4)
|
||||||
|
return -ENOSPC;
|
||||||
|
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_USB_PATH=%s", ci->usb_path);
|
||||||
|
/* TODO: Configuration; Altsetting */
|
||||||
|
env[i++] = talloc_asprintf(env, "REMSIM_USB_INTERFACE=%u", bc->cfg->usb.if_num);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: This must be cleaned up */
|
||||||
|
static struct osmo_st2_transport _transp;
|
||||||
|
static struct osmo_st2_slot _slot = {
|
||||||
|
.transp = &_transp,
|
||||||
|
.slot_nr = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
int client_user_main(struct bankd_client *bc)
|
||||||
|
{
|
||||||
|
struct usb_interface_match _ifm, *ifm = &_ifm;
|
||||||
|
struct osmo_st2_transport *transp;
|
||||||
|
struct osmo_st2_cardem_inst *ci;
|
||||||
|
struct client_config *cfg = bc->cfg;
|
||||||
|
int rc, i;
|
||||||
|
|
||||||
|
rc = osmo_libusb_init(NULL);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "libusb initialization failed\n");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ci = talloc_zero(bc, struct osmo_st2_cardem_inst);
|
||||||
|
OSMO_ASSERT(ci);
|
||||||
|
ci->slot = &_slot;
|
||||||
|
transp = ci->slot->transp;
|
||||||
|
ci->priv = bc;
|
||||||
|
bc->cardem = ci;
|
||||||
|
|
||||||
|
ifm->vendor = cfg->usb.vendor_id;
|
||||||
|
ifm->product = cfg->usb.product_id;
|
||||||
|
ifm->configuration = cfg->usb.config_id;
|
||||||
|
ifm->interface = cfg->usb.if_num;
|
||||||
|
ifm->altsetting = cfg->usb.altsetting;
|
||||||
|
ifm->addr = cfg->usb.addr;
|
||||||
|
if (cfg->usb.path)
|
||||||
|
osmo_strlcpy(ifm->path, cfg->usb.path, sizeof(ifm->path));
|
||||||
|
transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
|
||||||
|
if (!transp->usb_devh) {
|
||||||
|
fprintf(stderr, "can't open USB device\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (re)determine the USB path of the opened device */
|
||||||
|
talloc_free(ci->usb_path);
|
||||||
|
ci->usb_path = osmo_libusb_dev_get_path_c(ci, libusb_get_device(transp->usb_devh));
|
||||||
|
|
||||||
|
rc = libusb_claim_interface(transp->usb_devh, cfg->usb.if_num);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "can't claim interface %d; rc=%d\n", cfg->usb.if_num, rc);
|
||||||
|
goto close_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = osmo_libusb_get_ep_addrs(transp->usb_devh, cfg->usb.if_num, &transp->usb_ep.out,
|
||||||
|
&transp->usb_ep.in, &transp->usb_ep.irq_in);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
|
||||||
|
goto close_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocate_and_submit_irq(ci);
|
||||||
|
/* submit multiple IN URB in order to work around OS#4409 */
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
allocate_and_submit_in(ci);
|
||||||
|
|
||||||
|
/* request firmware to generate STATUS on IRQ endpoint */
|
||||||
|
osmo_st2_cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
osmo_select_main(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
close_exit:
|
||||||
|
if (transp->usb_devh)
|
||||||
|
libusb_close(transp->usb_devh);
|
||||||
|
osmo_libusb_exit(NULL);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -397,7 +397,7 @@ static const struct osmo_fsm_state server_conn_fsm_states[] = {
|
||||||
[SRVC_ST_INIT] = {
|
[SRVC_ST_INIT] = {
|
||||||
.name = "INIT",
|
.name = "INIT",
|
||||||
.in_event_mask = 0, /* S(SRVC_E_ESTABLISH) via allstate */
|
.in_event_mask = 0, /* S(SRVC_E_ESTABLISH) via allstate */
|
||||||
.out_state_mask = S(SRVC_ST_REESTABLISH),
|
.out_state_mask = S(SRVC_ST_INIT) | S(SRVC_ST_REESTABLISH),
|
||||||
.action = srvc_st_init,
|
.action = srvc_st_init,
|
||||||
},
|
},
|
||||||
[SRVC_ST_ESTABLISHED] = {
|
[SRVC_ST_ESTABLISHED] = {
|
||||||
|
|
Loading…
Reference in New Issue