bankd: Add GSMTAP functionality for SIM traffic
If a --gsmtap-host (-g) address is specified on the command line, trace SIM ATRs and APDUs to the given IP. If --gsmtap-slot (-G) is provided, limit tracing to the specified bank slot number. This feature may be useful when diagnosing issues with the remote SIM framework. Added new log category: DGSMTAP Also, cleaned up alignment in bankd --help output and removed unused -o option. Change-Id: I05b599858d8758633aa56c3f12f258c27cf42d08
This commit is contained in:
parent
7da85411e3
commit
31e8bd786b
|
@ -3,7 +3,7 @@ AM_CFLAGS = -Wall -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcd
|
|||
$(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) $(OSMOABIS_CFLAGS) \
|
||||
$(PCSC_CFLAGS)
|
||||
|
||||
noinst_HEADERS = bankd.h internal.h
|
||||
noinst_HEADERS = bankd.h internal.h gsmtap.h
|
||||
|
||||
bin_PROGRAMS = osmo-remsim-bankd
|
||||
noinst_PROGRAMS = pcsc_test
|
||||
|
@ -13,7 +13,7 @@ pcsc_test_LDADD = $(OSMOCORE_LIBS) \
|
|||
$(PCSC_LIBS) $(top_builddir)/src/libosmo-rspro.la
|
||||
|
||||
osmo_remsim_bankd_SOURCES = ../slotmap.c ../rspro_client_fsm.c ../debug.c \
|
||||
bankd_main.c bankd_pcsc.c
|
||||
bankd_main.c bankd_pcsc.c gsmtap.c
|
||||
osmo_remsim_bankd_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \
|
||||
$(PCSC_LIBS) $(CSV_LIBS) $(top_builddir)/src/libosmo-rspro.la
|
||||
|
||||
|
|
|
@ -139,6 +139,8 @@ struct bankd {
|
|||
|
||||
struct {
|
||||
bool permit_shared_pcsc;
|
||||
char *gsmtap_host;
|
||||
int gsmtap_slot;
|
||||
} cfg;
|
||||
};
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "rspro_client_fsm.h"
|
||||
#include "debug.h"
|
||||
#include "rspro_util.h"
|
||||
#include "gsmtap.h"
|
||||
|
||||
/* signal indicates to worker thread that its map has been deleted */
|
||||
#define SIGMAPDEL SIGRTMIN+1
|
||||
|
@ -100,6 +101,8 @@ static void bankd_init(struct bankd *bankd)
|
|||
INIT_LLIST_HEAD(&bankd->pcsc_slot_names);
|
||||
|
||||
bankd->cfg.permit_shared_pcsc = false;
|
||||
bankd->cfg.gsmtap_host = NULL;
|
||||
bankd->cfg.gsmtap_slot = -1;
|
||||
}
|
||||
|
||||
/* create + start a new bankd_worker thread */
|
||||
|
@ -284,18 +287,20 @@ send_resp:
|
|||
static void printf_help()
|
||||
{
|
||||
printf(
|
||||
" -h --help Print this help message\n"
|
||||
" -V --version Print the version of the program\n"
|
||||
" -d --debug option Enable debug logging (e.g. DMAIN:DST2)\n"
|
||||
" -i --server-host A.B.C.D remsim-server IP address (default: 127.0.0.1)\n"
|
||||
" -p --server-port <1-65535> remsim-server TCP port (default: 9998)\n"
|
||||
" -b --bank-id <1-1023> Bank Identifier of this SIM bank (default: 1)\n"
|
||||
" -n --num-slots <1-1023> Number of Slots in this SIM bank (default: 8)\n"
|
||||
" -I --bind-ip A.B.C.D Local IP address to bind for incoming client\n"
|
||||
" connections (default: INADDR_ANY)\n"
|
||||
" -P --bind-port <1-65535> Local TCP port to bind for incoming client\n"
|
||||
" connectionss (default: 9999)\n"
|
||||
" -s --permit-shared-pcsc Permit SHARED access to PC/SC readers (default: exclusive)\n"
|
||||
" -h --help Print this help message\n"
|
||||
" -V --version Print the version of the program\n"
|
||||
" -d --debug option Enable debug logging (e.g. DMAIN:DST2)\n"
|
||||
" -i --server-host A.B.C.D remsim-server IP address (default: 127.0.0.1)\n"
|
||||
" -p --server-port <1-65535> remsim-server TCP port (default: 9998)\n"
|
||||
" -b --bank-id <1-1023> Bank Identifier of this SIM bank (default: 1)\n"
|
||||
" -n --num-slots <1-1023> Number of Slots in this SIM bank (default: 8)\n"
|
||||
" -I --bind-ip A.B.C.D Local IP address to bind for incoming client\n"
|
||||
" connections (default: INADDR_ANY)\n"
|
||||
" -P --bind-port <1-65535> Local TCP port to bind for incoming client\n"
|
||||
" connections (default: 9999)\n"
|
||||
" -s --permit-shared-pcsc Permit SHARED access to PC/SC readers (default: exclusive)\n"
|
||||
" -g --gsmtap-ip A.B.C.D Enable GSMTAP and send APDU traces to given IP\n"
|
||||
" -G --gsmtap-slot <0-1023> Limit tracing to given bank slot, only (default: all slots)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -318,10 +323,12 @@ static void handle_options(int argc, char **argv)
|
|||
{ "bind-ip", 1, 0, 'I' },
|
||||
{ "bind-port", 1, 0, 'P' },
|
||||
{ "permit-shared-pcsc", 0, 0, 's' },
|
||||
{ "gsmtap-ip", 1, 0, 'g' },
|
||||
{ "gsmtap-slot", 1, 0, 'G' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hVd:i:p:o:b:n:N:I:P:s", long_options, &option_index);
|
||||
c = getopt_long(argc, argv, "hVd:i:p:b:n:N:I:P:sg:G:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
|
@ -361,6 +368,12 @@ static void handle_options(int argc, char **argv)
|
|||
case 's':
|
||||
g_bankd->cfg.permit_shared_pcsc = true;
|
||||
break;
|
||||
case 'g':
|
||||
g_bankd->cfg.gsmtap_host = optarg;
|
||||
break;
|
||||
case 'G':
|
||||
g_bankd->cfg.gsmtap_slot = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,6 +431,15 @@ int main(int argc, char **argv)
|
|||
}
|
||||
g_bankd->accept_fd = rc;
|
||||
|
||||
/* initialize gsmtap, if required */
|
||||
if (g_bankd->cfg.gsmtap_host) {
|
||||
rc = bankd_gsmtap_init(g_bankd->cfg.gsmtap_host);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Unable to open GSMTAP");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* create worker threads: One per reader/slot! */
|
||||
for (i = 0; i < g_bankd->srvc.bankd.num_slots; i++) {
|
||||
struct bankd_worker *w;
|
||||
|
@ -661,6 +683,14 @@ static int worker_send_atr(struct bankd_worker *worker)
|
|||
set_atr = rspro_gen_SetAtrReq(worker->client.clslot.client_id,
|
||||
worker->client.clslot.slot_nr,
|
||||
worker->card.atr, worker->card.atr_len);
|
||||
|
||||
/* trace ATR to GSMTAP, if configured */
|
||||
if (g_bankd->cfg.gsmtap_host && (g_bankd->cfg.gsmtap_slot == -1 ||
|
||||
g_bankd->cfg.gsmtap_slot == worker->slot.slot_nr)) {
|
||||
bankd_gsmtap_send_apdu(GSMTAP_SIM_ATR, worker->card.atr, worker->card.atr_len,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
if (!set_atr)
|
||||
return -1;
|
||||
return worker_send_rspro(worker, set_atr);
|
||||
|
@ -761,6 +791,12 @@ static int worker_handle_tpduModemToCard(struct bankd_worker *worker, const Rspr
|
|||
rx_buf, rx_buf_len);
|
||||
worker_send_rspro(worker, pdu_resp);
|
||||
|
||||
/* trace APDU to GSMTAP, if configured */
|
||||
if (g_bankd->cfg.gsmtap_host && (g_bankd->cfg.gsmtap_slot == -1 ||
|
||||
g_bankd->cfg.gsmtap_slot == worker->slot.slot_nr)) {
|
||||
bankd_gsmtap_send_apdu(GSMTAP_SIM_APDU, mdm2sim->data.buf, mdm2sim->data.size, rx_buf,
|
||||
rx_buf_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/* gsmtap - How to encapsulate SIM protocol traces in GSMTAP
|
||||
*
|
||||
* (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* among other things, bring in GNU-specific strerror_r() */
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <osmocom/core/gsmtap.h>
|
||||
#include <osmocom/core/gsmtap_util.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/*! global GSMTAP instance */
|
||||
static struct gsmtap_inst *g_gti;
|
||||
|
||||
/*! initialize the global GSMTAP instance for SIM traces
|
||||
*
|
||||
* \param[in] gsmtap_host Hostname to send GSMTAP packets
|
||||
*
|
||||
* \return 0 on success, non-zero on error
|
||||
*/
|
||||
int bankd_gsmtap_init(const char *gsmtap_host)
|
||||
{
|
||||
if (g_gti)
|
||||
return -EEXIST;
|
||||
|
||||
errno = 0;
|
||||
g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0);
|
||||
if (!g_gti) {
|
||||
LOGP(DGSMTAP, LOGL_ERROR, "unable to initialize GSMTAP\n");
|
||||
return -EIO;
|
||||
}
|
||||
gsmtap_source_add_sink(g_gti);
|
||||
|
||||
LOGP(DGSMTAP, LOGL_INFO, "initialized GSMTAP to %s\n", gsmtap_host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Log one APDU via the global GSMTAP instance by concatenating mdm_tpdu and sim_tpdu.
|
||||
*
|
||||
* \param[in] sub_type GSMTAP sub-type (GSMTAP_SIM_* constant)
|
||||
* \param[in] mdm_tpdu User-provided buffer with ModemToCard TPDU to log. May be NULL.
|
||||
* \param[in] mdm_tpdu_len Length of ModemToCard TPDU, in bytes.
|
||||
* \param[in] sim_tpdu User-provided buffer with CardToModem TPDU to log. May be NULL.
|
||||
* \param[in] sim_tpdu_len Length of CardToModem TPDU, in bytes.
|
||||
*
|
||||
* \return number of bytes sent on success, -1 on failure
|
||||
*/
|
||||
int bankd_gsmtap_send_apdu(uint8_t sub_type, const uint8_t *mdm_tpdu, unsigned int mdm_tpdu_len,
|
||||
const uint8_t *sim_tpdu, unsigned int sim_tpdu_len)
|
||||
{
|
||||
const struct gsmtap_hdr gh = {
|
||||
.version = GSMTAP_VERSION,
|
||||
.hdr_len = sizeof(struct gsmtap_hdr)/4,
|
||||
.type = GSMTAP_TYPE_SIM,
|
||||
.sub_type = sub_type,
|
||||
};
|
||||
|
||||
struct iovec iov[3];
|
||||
unsigned int cnt = 0;
|
||||
|
||||
iov[cnt].iov_base = (void *)&gh;
|
||||
iov[cnt].iov_len = sizeof(gh);
|
||||
cnt++;
|
||||
|
||||
if (mdm_tpdu && mdm_tpdu_len) {
|
||||
iov[cnt].iov_base = (void *)mdm_tpdu;
|
||||
iov[cnt].iov_len = mdm_tpdu_len;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (sim_tpdu && sim_tpdu_len) {
|
||||
iov[cnt].iov_base = (void *)sim_tpdu;
|
||||
iov[cnt].iov_len = sim_tpdu_len;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
LOGP(DGSMTAP, LOGL_DEBUG, "sending APDU sub_type=%u, mdm_tpdu len=%u, sim_tpdu len=%u, iov cnt=%u\n",
|
||||
sub_type, mdm_tpdu_len, sim_tpdu_len, cnt);
|
||||
|
||||
const int rc = writev(gsmtap_inst_fd(g_gti), iov, cnt);
|
||||
if (rc < 0) {
|
||||
char errtxt[128];
|
||||
LOGP(DGSMTAP, LOGL_ERROR, "writev() failed with errno=%d: %s\n", errno, strerror_r(errno,
|
||||
errtxt, sizeof(errtxt)));
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <osmocom/core/gsmtap.h>
|
||||
|
||||
int bankd_gsmtap_init(const char *gsmtap_host);
|
||||
int bankd_gsmtap_send_apdu(uint8_t sub_type, const uint8_t *mdm_tpdu, unsigned int mdm_tpdu_len,
|
||||
const uint8_t *sim_tpdu, unsigned int sim_tpdu_len);
|
|
@ -52,6 +52,11 @@ static const struct log_info_cat default_categories[] = {
|
|||
.loglevel = LOGL_INFO,
|
||||
.enabled = 1,
|
||||
},
|
||||
[DGSMTAP] = {
|
||||
.name = "DGSMTAP",
|
||||
.loglevel = LOGL_INFO,
|
||||
.enabled = 1,
|
||||
},
|
||||
};
|
||||
|
||||
const struct log_info log_info = {
|
||||
|
|
|
@ -8,6 +8,7 @@ enum {
|
|||
DREST,
|
||||
DSLOTMAP,
|
||||
DBANKDW,
|
||||
DGSMTAP,
|
||||
};
|
||||
|
||||
extern const struct log_info log_info;
|
||||
|
|
Loading…
Reference in New Issue