diff --git a/doc/manuals/chapters/remsim-client.adoc b/doc/manuals/chapters/remsim-client.adoc index 8f90a1a..7416b05 100644 --- a/doc/manuals/chapters/remsim-client.adoc +++ b/doc/manuals/chapters/remsim-client.adoc @@ -82,6 +82,10 @@ osmo-remsim-client-st2 currently has the following command-line options: Specify the initial ATR to be communicated to the modem/phone. Can and will later be overridden by the ATR as specified by `osmo-remsim-bankd` once a card has been mapped to this client. +*-e, --event-script COMMAND*:: + Specify the shell command to be execute when the client wants to call its + helper script + ==== Examples .remsim-server is on 10.2.3.4, sysmoQMOD on usb bus, all 4 modems: @@ -97,3 +101,55 @@ osmo-remsim-client-st2 -s 10.2.3.4 -V 1d50 -P 4004 -C 1 -I 1 -H 2-1.4 -c 0 -n 3 `osmo-remsim-client` currently logs to stdout only, and the logging verbosity is not yet configurable. However, as the libosmocore logging framework is used, extending this is an easy modification. + +=== Helper Script + +`osmo-remsim-client` can call an external shell command / script / program at specific +instances of time. This serves two purposes: + +* To keep external system integration posted about the overall status of remsim-client, + such as whether or not it is connected to a server and/or bankd. +* To request the external system to perform specific actions, such as triggering the reset + of the modem - in case the hardware doesn't allow the simtrace2 firmware to do that itself. + +==== Script Environment Variables + +The environment passed to the helper script contains a number of variables to provide inormation +to the external script: + +.Environment Variables +[options="header",cols="27%,18%,55%"] +|=== +| Name | Example Value | Description +| REMSIM_CLIENT_VERSION | 0.2.2.37-5406a | Compile version of the software +| REMSIM_SERVER_ADDR | 1.2.3.4:1234 | Address and port of the remsim-server +| REMSIM_SERVER_STATE | CONNECTED | FSM state of the connection to remsim-server +| REMSIM_BANKD_ADDR | 1.2.3.4:1234 | Address and port of the remsim-bankd +| REMSIM_BANKD_STATE | CONNECTED | FSM state of the connection to remsim-bankd +| REMSIM_CLIENT_SLOT | 23:42 | Client ID and Client Slot Number +| REMSIM_BANKD_SLOT | 55:33 | Bank ID and Bank Slot Number +| REMSIM_USB_PATH | 2-1.1 | USB path of the USB device with simtrace2 cardem firmware +| REMSIM_USB_INTERFACE | 1 | Interface number of the USB device with simtrace2 cardem firmware +| REMSIM_SIM_VCC | 1 | Whether or not the modem currently applies SIM VCC (0/1) +| REMSIM_SIM_RST | 1 | Whether or not the modem currently asserts SIM RST (0=inactive, 1=active) +| REMSIM_CAUSE | request-card-insert | The cause why this script has been called +|=== + +==== REMSIM_CAUSE values + +The REMSIM_CAUSE environment variable (as well as the first argument) passed to the helper +script indicated why the script has been called. + +[options="header",cols="25%,75%"] +|=== +| Name | Description +| event-modem-status | The SIM card interface status has changed (e.g. VCC/RST change) +| event-bankd-connect | A logical RSPRO connection to a bankd has been established +| event-server-connect | A logical RSPRO connection to a server has been established +| event-config-bankd | The server has instructed the client of the bankd address +| request-card-insert | The client asks the system to simulate SIM card insertion to the modem +| request-card-remove | The client asks the system to simulate SIM card removal from the modem +| request-sim-remote | The client asks the system to switch to remote SIM +| request-sim-local | The client asks the system to switch to local SIM +| request-modem-reset | The client asks the system to perform a modem reset +|=== diff --git a/src/client/simtrace2-remsim_client.c b/src/client/simtrace2-remsim_client.c index 846ce85..ce8ea1d 100644 --- a/src/client/simtrace2-remsim_client.c +++ b/src/client/simtrace2-remsim_client.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -130,6 +131,77 @@ __attribute__((unused)) static int gsmtap_send_sim(const uint8_t *apdu, unsigned return 0; } +/* build the (additional) environment for executing a script */ +static char **build_script_env(struct bankd_client *clnt, const char *cause) +{ + struct cardem_inst *ci = clnt->cardem; + char **env = talloc_zero_size(clnt, 256*sizeof(char *)); + int 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", + clnt->srv_conn.server_host, clnt->srv_conn.server_port); + env[i++] = talloc_asprintf(env, "REMSIM_SERVER_STATE=%s", + osmo_fsm_inst_state_name(clnt->srv_conn.fi)); + + env[i++] = talloc_asprintf(env, "REMSIM_BANKD_ADDR=%s:%u", + clnt->bankd_conn.server_host, clnt->bankd_conn.server_port); + env[i++] = talloc_asprintf(env, "REMSIM_BANKD_STATE=%s", + osmo_fsm_inst_state_name(clnt->bankd_conn.fi)); + + + if (clnt->srv_conn.clslot) { + env[i++] = talloc_asprintf(env, "REMSIM_CLIENT_SLOT=%lu:%lu", + g_client->srv_conn.clslot->clientId, + g_client->srv_conn.clslot->slotNr); + } + env[i++] = talloc_asprintf(env, "REMSIM_BANKD_SLOT=%u:%u", + clnt->bankd_slot.bank_id, clnt->bankd_slot.slot_nr); + + env[i++] = talloc_asprintf(env, "REMSIM_USB_PATH=%s", ci->usb_path); + env[i++] = talloc_asprintf(env, "REMSIM_USB_INTERFACE=%u", clnt->cfg->usb.if_num); + + /* TODO: SIM card state VCC/CLK/RST */ + env[i++] = talloc_asprintf(env, "REMSIM_SIM_VCC=%u", + !!(ci->last_status.flags & CEMU_STATUS_F_VCC_PRESENT)); + env[i++] = talloc_asprintf(env, "REMSIM_SIM_RST=%u", + !!(ci->last_status.flags & CEMU_STATUS_F_RESET_ACTIVE)); + + env[i++] = talloc_asprintf(env, "REMSIM_CAUSE=%s", cause); + + /* terminate last entry */ + env[i++] = NULL; + return env; +} + +static int call_script(struct bankd_client *clnt, const char *cause) +{ + char **env, *cmd; + int rc; + + if (!clnt->cfg->event_script) + return 0; + + env = build_script_env(clnt, cause); + if (!env) + return -ENOMEM; + + cmd = talloc_asprintf(env, "%s %s", clnt->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; +} + /*********************************************************************** * SIMTRACE core protocol ***********************************************************************/ @@ -548,6 +620,7 @@ static int process_irq_status(struct cardem_inst *ci, const uint8_t *buf, int le if (ci->last_status.flags != status->flags) { ci->last_status = *status; + call_script(g_client, "event-modem-status"); } else ci->last_status = *status; @@ -754,6 +827,7 @@ static int bankd_handle_rx(struct rspro_server_conn *bankdc, const RsproPDU_t *p /* Store 'identity' of bankd to in peer_comp_id */ rspro_comp_id_retrieve(&bankdc->peer_comp_id, &pdu->msg.choice.connectClientRes.identity); osmo_fsm_inst_dispatch(bankdc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu); + call_script(g_client, "event-bankd-connect"); break; case RsproPDUchoice_PR_tpduCardToModem: // APDU response from card received bankd_handle_tpduCardToModem(g_client, pdu); @@ -780,6 +854,7 @@ static int srvc_handle_rx(struct rspro_server_conn *srvc, const RsproPDU_t *pdu) /* Store 'identity' of server in srvc->peer_comp_id */ rspro_comp_id_retrieve(&srvc->peer_comp_id, &pdu->msg.choice.connectClientRes.identity); osmo_fsm_inst_dispatch(srvc->fi, SRVC_E_CLIENT_CONN_RES, (void *) pdu); + call_script(g_client, "event-server-connect"); break; case RsproPDUchoice_PR_configClientIdReq: /* store/set the clientID as instructed by the server */ @@ -804,6 +879,7 @@ static int srvc_handle_rx(struct rspro_server_conn *srvc, const RsproPDU_t *pdu) /* send response to server */ resp = rspro_gen_ConfigClientBankRes(ResultCode_ok); server_conn_send_rspro(srvc, resp); + call_script(g_client, "event-config-bankd"); break; default: LOGPFSML(srvc->fi, LOGL_ERROR, "Unknown/Unsupported RSPRO PDU type: %s\n", @@ -847,6 +923,7 @@ static void print_help(void) "\t-A\t--usb-address\tADDRESS\n" "\t-H\t--usb-path\tPATH\n" "\t-a\t--atr\tATR\n" + "\t-e\t--event-script\tPATH\n" "\n" ); } @@ -898,6 +975,7 @@ static void handle_options(struct client_config *cfg, int argc, char **argv) { "usb-address", 1, 0, 'A' }, { "usb-path", 1, 0, 'H' }, { "atr", 1, 0, 'a' }, + { "event-script", 1, 0, 'e' }, { NULL, 0, 0, 0 } }; int c, rc; @@ -905,7 +983,7 @@ static void handle_options(struct client_config *cfg, int argc, char **argv) while (1) { int option_index = 0; - c = getopt_long(argc, argv, "s:p:c:n:hvi:kV:P:C:I:S:A:H:a:", opts, &option_index); + c = getopt_long(argc, argv, "s:p:c:n:hvi:kV:P:C:I:S:A:H:a:e:", opts, &option_index); if (c == -1) break; switch (c) { @@ -964,6 +1042,9 @@ static void handle_options(struct client_config *cfg, int argc, char **argv) } cfg->atr.len = rc; break; + case 'e': + osmo_talloc_replace_string(cfg, &cfg->event_script, optarg); + break; } } @@ -1062,9 +1143,11 @@ static void main_body(struct cardem_inst *ci, struct client_config *cfg) /* simulate card-insert to modem (owhw, not qmod) */ cardem_request_card_insert(ci, true); + call_script(g_client, "request-card-insert"); /* select remote (forwarded) SIM */ st_modem_sim_select_remote(ci->slot); + call_script(g_client, "request-sim-remote"); /* set the ATR */ //atr_update_csum(real_atr, sizeof(real_atr)); @@ -1072,6 +1155,7 @@ static void main_body(struct cardem_inst *ci, struct client_config *cfg) /* select remote (forwarded) SIM */ st_modem_reset_pulse(ci->slot, 300); + call_script(g_client, "request-modem-reset"); printf("Entering main loop\n");