mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-16 21:28:33 +03:00
host: use autotools and split shared code to libosmo-simtrace2
Change-Id: I57e77f927ee9e169cc794c5dc6b128a2d590201b
This commit is contained in:
19
host/lib/Makefile.am
Normal file
19
host/lib/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
# This is _NOT_ the library release version, it's an API version.
|
||||
# Please read chapter "Library interface versions" of the libtool documentation
|
||||
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
|
||||
ST2_LIBVERSION=0:0:0
|
||||
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS= -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOSIM_CFLAGS) $(LIBUSB_CFLAGS) $(COVERAGE_CFLAGS)
|
||||
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
COMMONLIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOSIM_LIBS) $(LIBUSB_LIBS)
|
||||
|
||||
lib_LTLIBRARIES = libosmo-simtrace2.la
|
||||
|
||||
libosmo_simtrace2_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(ST2_LIBVERSION)
|
||||
libosmo_simtrace2_la_LIBADD = $(COMMONLIBS)
|
||||
libosmo_simtrace2_la_SOURCES = \
|
||||
apdu_dispatch.c \
|
||||
gsmtap.c \
|
||||
libusb_util.c \
|
||||
simtrace2_api.c
|
||||
173
host/lib/apdu_dispatch.c
Normal file
173
host/lib/apdu_dispatch.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
|
||||
*
|
||||
* (C) 2016 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.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/sim/sim.h>
|
||||
#include <osmocom/sim/class_tables.h>
|
||||
|
||||
#include <osmocom/simtrace2/apdu_dispatch.h>
|
||||
|
||||
/*! \brief Has the command-data phase been completed yet? */
|
||||
static inline bool is_dc_complete(struct apdu_context *ac)
|
||||
{
|
||||
return (ac->lc.tot == ac->lc.cur);
|
||||
}
|
||||
|
||||
/*! \brief Has the expected-data phase been completed yet? */
|
||||
static inline bool is_de_complete(struct apdu_context *ac)
|
||||
{
|
||||
return (ac->le.tot == ac->le.cur);
|
||||
}
|
||||
|
||||
static const char *dump_apdu_hdr(const struct osim_apdu_cmd_hdr *h)
|
||||
{
|
||||
static char buf[256];
|
||||
sprintf(buf, "CLA=%02x INS=%02x P1=%02x P2=%02x P3=%02x",
|
||||
h->cla, h->ins, h->p1, h->p2, h->p3);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void dump_apdu_ctx(const struct apdu_context *ac)
|
||||
{
|
||||
printf("%s; case=%d, lc=%d(%d), le=%d(%d)\n",
|
||||
dump_apdu_hdr(&ac->hdr), ac->apdu_case,
|
||||
ac->lc.tot, ac->lc.cur,
|
||||
ac->le.tot, ac->le.cur);
|
||||
}
|
||||
|
||||
/*! \brief input function for APDU segmentation
|
||||
* \param ac APDU context accross successive calls
|
||||
* \param[in] apdu_buf APDU inpud data buffer
|
||||
* \param[in] apdu_len Length of apdu_buf
|
||||
* \param[in] new_apdu Is this the beginning of a new APDU?
|
||||
*
|
||||
* The function returns APDU_ACT_TX_CAPDU_TO_CARD once there is
|
||||
* sufficient data of the APDU received to transmit the command-APDU to
|
||||
* the actual card.
|
||||
*
|
||||
* The function retunrs APDU_ACT_RX_MORE_CAPDU_FROM_READER when there
|
||||
* is more data to be received from the card reader (GSM Phone).
|
||||
*/
|
||||
int apdu_segment_in(struct apdu_context *ac, const uint8_t *apdu_buf,
|
||||
unsigned int apdu_len, bool new_apdu)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (new_apdu) {
|
||||
/* initialize the apdu context structure */
|
||||
memset(ac, 0, sizeof(*ac));
|
||||
/* copy APDU header over */
|
||||
memcpy(&ac->hdr, apdu_buf, sizeof(ac->hdr));
|
||||
ac->apdu_case = osim_determine_apdu_case(&osim_uicc_sim_cic_profile, apdu_buf);
|
||||
switch (ac->apdu_case) {
|
||||
case 1: /* P3 == 0, No Lc/Le */
|
||||
ac->le.tot = ac->lc.tot = 0;
|
||||
break;
|
||||
case 2: /* P3 == Le */
|
||||
ac->le.tot = ac->hdr.p3;
|
||||
break;
|
||||
case 3: /* P3 = Lc */
|
||||
ac->lc.tot = ac->hdr.p3;
|
||||
/* copy Dc */
|
||||
ac->lc.cur = apdu_len - sizeof(ac->hdr);
|
||||
memcpy(ac->dc, apdu_buf + sizeof(ac->hdr),
|
||||
ac->lc.cur);
|
||||
break;
|
||||
case 4: /* P3 = Lc; SW with Le */
|
||||
ac->lc.tot = ac->hdr.p3;
|
||||
/* copy Dc */
|
||||
ac->lc.cur = apdu_len - sizeof(ac->hdr);
|
||||
memcpy(ac->dc, apdu_buf + sizeof(ac->hdr),
|
||||
ac->lc.cur);
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* copy more data, if available */
|
||||
int cpy_len;
|
||||
switch (ac->apdu_case) {
|
||||
case 1:
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
cpy_len = ac->lc.tot - ac->lc.cur;
|
||||
if (cpy_len > apdu_len)
|
||||
cpy_len = apdu_len;
|
||||
memcpy(ac->dc+ac->lc.cur, apdu_buf, cpy_len);
|
||||
ac->lc.cur += cpy_len;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* take some decisions... */
|
||||
switch (ac->apdu_case) {
|
||||
case 1: /* P3 == 0, No Lc/Le */
|
||||
/* send C-APDU to card */
|
||||
/* receive SW from card, forward to reader */
|
||||
rc |= APDU_ACT_TX_CAPDU_TO_CARD;
|
||||
break;
|
||||
case 2: /* P3 == Le */
|
||||
/* send C-APDU to card */
|
||||
/* receive Le bytes + SW from card, forward to reader */
|
||||
rc |= APDU_ACT_TX_CAPDU_TO_CARD;
|
||||
break;
|
||||
case 3: /* P3 = Lc */
|
||||
if (!is_dc_complete(ac)) {
|
||||
/* send PB + read further Lc bytes from reader */
|
||||
rc |= APDU_ACT_RX_MORE_CAPDU_FROM_READER;
|
||||
} else {
|
||||
/* send C-APDU to card */
|
||||
/* receive SW from card, forward to reader */
|
||||
rc |= APDU_ACT_TX_CAPDU_TO_CARD;
|
||||
}
|
||||
break;
|
||||
case 4: /* P3 = Lc; SW with Le */
|
||||
if (!is_dc_complete(ac)) {
|
||||
/* send PB + read further Lc bytes from reader */
|
||||
rc |= APDU_ACT_RX_MORE_CAPDU_FROM_READER;
|
||||
} else {
|
||||
/* send C-APDU to card */
|
||||
/* receive SW from card, forward to reader */
|
||||
rc |= APDU_ACT_TX_CAPDU_TO_CARD;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
fprintf(stderr, "Unknown APDU case %d\n", ac->apdu_case);
|
||||
break;
|
||||
}
|
||||
|
||||
dump_apdu_ctx(ac);
|
||||
|
||||
return rc;
|
||||
}
|
||||
57
host/lib/gsmtap.c
Normal file
57
host/lib/gsmtap.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <osmocom/simtrace2/gsmtap.h>
|
||||
|
||||
#include <osmocom/core/gsmtap.h>
|
||||
#include <osmocom/core/gsmtap_util.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* global GSMTAP instance */
|
||||
static struct gsmtap_inst *g_gti;
|
||||
|
||||
int osmo_st2_gsmtap_init(const char *gsmtap_host)
|
||||
{
|
||||
if (g_gti)
|
||||
return -EEXIST;
|
||||
|
||||
g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0);
|
||||
if (!g_gti) {
|
||||
perror("unable to open GSMTAP");
|
||||
return -EIO;
|
||||
}
|
||||
gsmtap_source_add_sink(g_gti);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osmo_st2_gsmtap_send_apdu(uint8_t sub_type, const uint8_t *apdu, unsigned int len)
|
||||
{
|
||||
struct gsmtap_hdr *gh;
|
||||
unsigned int gross_len = len + sizeof(*gh);
|
||||
uint8_t *buf = malloc(gross_len);
|
||||
int rc;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(buf, 0, sizeof(*gh));
|
||||
gh = (struct gsmtap_hdr *) buf;
|
||||
gh->version = GSMTAP_VERSION;
|
||||
gh->hdr_len = sizeof(*gh)/4;
|
||||
gh->type = GSMTAP_TYPE_SIM;
|
||||
gh->sub_type = sub_type;
|
||||
|
||||
memcpy(buf + sizeof(*gh), apdu, len);
|
||||
|
||||
rc = write(gsmtap_inst_fd(g_gti), buf, gross_len);
|
||||
if (rc < 0) {
|
||||
perror("write gsmtap");
|
||||
free(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
297
host/lib/libusb_util.c
Normal file
297
host/lib/libusb_util.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/* libusb utilities
|
||||
*
|
||||
* (C) 2010-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.
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include <osmocom/simtrace2/libusb_util.h>
|
||||
|
||||
static char path_buf[USB_MAX_PATH_LEN];
|
||||
|
||||
static char *get_path(libusb_device *dev)
|
||||
{
|
||||
#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102)
|
||||
uint8_t path[8];
|
||||
int r,j;
|
||||
r = libusb_get_port_numbers(dev, path, sizeof(path));
|
||||
if (r > 0) {
|
||||
sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]);
|
||||
for (j = 1; j < r; j++){
|
||||
sprintf(path_buf+strlen(path_buf),".%d",path[j]);
|
||||
};
|
||||
}
|
||||
return path_buf;
|
||||
#else
|
||||
# warning "libusb too old - building without USB path support!"
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id)
|
||||
{
|
||||
if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids)
|
||||
{
|
||||
const struct dev_id *id;
|
||||
|
||||
for (id = ids; id->vendor_id || id->product_id; id++) {
|
||||
if (match_dev_id(desc, id))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids)
|
||||
{
|
||||
libusb_device **list;
|
||||
libusb_device **out = calloc(256, sizeof(libusb_device *));
|
||||
libusb_device **cur = out;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
rc = libusb_get_device_list(NULL, &list);
|
||||
if (rc <= 0) {
|
||||
perror("No USB devices found");
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; list[i] != NULL; i++) {
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
libusb_device *dev = list[i];
|
||||
|
||||
rc = libusb_get_device_descriptor(dev, &dev_desc);
|
||||
if (rc < 0) {
|
||||
perror("Couldn't get device descriptor\n");
|
||||
libusb_unref_device(dev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (match_dev_ids(&dev_desc, dev_ids)) {
|
||||
*cur = dev;
|
||||
cur++;
|
||||
/* FIXME: overflow check */
|
||||
} else
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
if (cur == out) {
|
||||
libusb_free_device_list(list, 1);
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
libusb_free_device_list(list, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
|
||||
struct usb_interface_match *out, unsigned int out_len)
|
||||
{
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
int rc, i, out_idx = 0;
|
||||
uint8_t addr;
|
||||
char *path;
|
||||
|
||||
rc = libusb_get_device_descriptor(dev, &dev_desc);
|
||||
if (rc < 0) {
|
||||
perror("Couldn't get device descriptor\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
addr = libusb_get_device_address(dev);
|
||||
path = get_path(dev);
|
||||
|
||||
/* iterate over all configurations */
|
||||
for (i = 0; i < dev_desc.bNumConfigurations; i++) {
|
||||
struct libusb_config_descriptor *conf_desc;
|
||||
int j;
|
||||
|
||||
rc = libusb_get_config_descriptor(dev, i, &conf_desc);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Couldn't get config descriptor %u\n", i);
|
||||
continue;
|
||||
}
|
||||
/* iterate over all interfaces */
|
||||
for (j = 0; j < conf_desc->bNumInterfaces; j++) {
|
||||
const struct libusb_interface *intf = &conf_desc->interface[j];
|
||||
int k;
|
||||
/* iterate over all alternate settings */
|
||||
for (k = 0; k < intf->num_altsetting; k++) {
|
||||
const struct libusb_interface_descriptor *if_desc;
|
||||
if_desc = &intf->altsetting[k];
|
||||
if (class >= 0 && if_desc->bInterfaceClass != class)
|
||||
continue;
|
||||
if (sub_class >= 0 && if_desc->bInterfaceSubClass != sub_class)
|
||||
continue;
|
||||
if (protocol >= 0 && if_desc->bInterfaceProtocol != protocol)
|
||||
continue;
|
||||
/* MATCH! */
|
||||
out[out_idx].usb_dev = dev;
|
||||
out[out_idx].vendor = dev_desc.idVendor;
|
||||
out[out_idx].product = dev_desc.idProduct;
|
||||
out[out_idx].addr = addr;
|
||||
strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1);
|
||||
out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
|
||||
out[out_idx].configuration = conf_desc->bConfigurationValue;
|
||||
out[out_idx].interface = if_desc->bInterfaceNumber;
|
||||
out[out_idx].altsetting = if_desc->bAlternateSetting;
|
||||
out[out_idx].class = if_desc->bInterfaceClass;
|
||||
out[out_idx].sub_class = if_desc->bInterfaceSubClass;
|
||||
out[out_idx].protocol = if_desc->bInterfaceProtocol;
|
||||
out[out_idx].string_idx = if_desc->iInterface;
|
||||
out_idx++;
|
||||
if (out_idx >= out_len)
|
||||
return out_idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out_idx;
|
||||
}
|
||||
|
||||
int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
|
||||
int class, int sub_class, int protocol,
|
||||
struct usb_interface_match *out, unsigned int out_len)
|
||||
{
|
||||
struct usb_interface_match *out_cur = out;
|
||||
unsigned int out_len_remain = out_len;
|
||||
libusb_device **list;
|
||||
libusb_device **dev;
|
||||
|
||||
list = find_matching_usb_devs(dev_ids);
|
||||
if (!list)
|
||||
return 0;
|
||||
|
||||
for (dev = list; *dev; dev++) {
|
||||
int rc;
|
||||
|
||||
#if 0
|
||||
struct libusb_device_descriptor dev_desc;
|
||||
uint8_t ports[8];
|
||||
uint8_t addr;
|
||||
rc = libusb_get_device_descriptor(*dev, &dev_desc);
|
||||
if (rc < 0) {
|
||||
perror("Cannot get device descriptor");
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = libusb_get_device_address(*dev);
|
||||
|
||||
rc = libusb_get_port_numbers(*dev, ports, sizeof(ports));
|
||||
if (rc < 0) {
|
||||
perror("Cannot get device path");
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Found USB Device %04x:%04x at address %d\n",
|
||||
dev_desc.idVendor, dev_desc.idProduct, addr);
|
||||
#endif
|
||||
|
||||
rc = dev_find_matching_interfaces(*dev, class, sub_class, protocol, out_cur, out_len_remain);
|
||||
if (rc < 0)
|
||||
continue;
|
||||
out_cur += rc;
|
||||
out_len_remain -= rc;
|
||||
|
||||
}
|
||||
return out_len - out_len_remain;
|
||||
}
|
||||
|
||||
libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
|
||||
const struct usb_interface_match *ifm)
|
||||
{
|
||||
int rc, config;
|
||||
struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } };
|
||||
libusb_device **list;
|
||||
libusb_device **dev;
|
||||
libusb_device_handle *usb_devh = NULL;
|
||||
|
||||
list = find_matching_usb_devs(dev_ids);
|
||||
if (!list) {
|
||||
perror("No USB device with matching VID/PID");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (dev = list; *dev; dev++) {
|
||||
int addr;
|
||||
char *path;
|
||||
|
||||
addr = libusb_get_device_address(*dev);
|
||||
path = get_path(*dev);
|
||||
if ((ifm->addr && addr == ifm->addr) ||
|
||||
(strlen(ifm->path) && !strcmp(path, ifm->path))) {
|
||||
rc = libusb_open(*dev, &usb_devh);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc));
|
||||
usb_devh = NULL;
|
||||
break;
|
||||
}
|
||||
rc = libusb_get_configuration(usb_devh, &config);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc));
|
||||
libusb_close(usb_devh);
|
||||
usb_devh = NULL;
|
||||
break;
|
||||
}
|
||||
if (config != ifm->configuration) {
|
||||
rc = libusb_set_configuration(usb_devh, ifm->configuration);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc));
|
||||
libusb_close(usb_devh);
|
||||
usb_devh = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = libusb_claim_interface(usb_devh, ifm->interface);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc));
|
||||
libusb_close(usb_devh);
|
||||
usb_devh = NULL;
|
||||
break;
|
||||
}
|
||||
rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc));
|
||||
libusb_release_interface(usb_devh, ifm->interface);
|
||||
libusb_close(usb_devh);
|
||||
usb_devh = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* unref / free list */
|
||||
for (dev = list; *dev; dev++)
|
||||
libusb_unref_device(*dev);
|
||||
free(list);
|
||||
|
||||
return usb_devh;
|
||||
}
|
||||
281
host/lib/simtrace2_api.c
Normal file
281
host/lib/simtrace2_api.c
Normal file
@@ -0,0 +1,281 @@
|
||||
|
||||
/* simtrace2-protocol - USB protocol library code for SIMtrace2
|
||||
*
|
||||
* (C) 2016-2019 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.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.
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
//#include <osmocom/simtrace2/libusb_util.h>
|
||||
#include <osmocom/simtrace2/simtrace_prot.h>
|
||||
#include <osmocom/simtrace2/simtrace2_api.h>
|
||||
//#include "apdu_dispatch.h"
|
||||
//#include "simtrace2-discovery.h"
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/sim/class_tables.h>
|
||||
#include <osmocom/sim/sim.h>
|
||||
|
||||
/***********************************************************************
|
||||
* SIMTRACE core protocol
|
||||
***********************************************************************/
|
||||
|
||||
/*! \brief allocate a message buffer for simtrace use */
|
||||
static struct msgb *st_msgb_alloc(void)
|
||||
{
|
||||
return msgb_alloc_headroom(1024+32, 32, "SIMtrace");
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void apdu_out_cb(uint8_t *buf, unsigned int len, void *user_data)
|
||||
{
|
||||
printf("APDU: %s\n", osmo_hexdump(buf, len));
|
||||
gsmtap_send_sim(buf, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief Transmit a given command to the SIMtrace2 device */
|
||||
int st_transp_tx_msg(struct st_transport *transp, struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
printf("<- %s\n", msgb_hexdump(msg));
|
||||
|
||||
if (transp->udp_fd < 0) {
|
||||
int xfer_len;
|
||||
|
||||
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.out,
|
||||
msgb_data(msg), msgb_length(msg),
|
||||
&xfer_len, 100000);
|
||||
} else {
|
||||
rc = write(transp->udp_fd, msgb_data(msg), msgb_length(msg));
|
||||
}
|
||||
|
||||
msgb_free(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct simtrace_msg_hdr *st_push_hdr(struct msgb *msg, uint8_t msg_class, uint8_t msg_type,
|
||||
uint8_t slot_nr)
|
||||
{
|
||||
struct simtrace_msg_hdr *sh;
|
||||
|
||||
sh = (struct simtrace_msg_hdr *) msgb_push(msg, sizeof(*sh));
|
||||
memset(sh, 0, sizeof(*sh));
|
||||
sh->msg_class = msg_class;
|
||||
sh->msg_type = msg_type;
|
||||
sh->slot_nr = slot_nr;
|
||||
sh->msg_len = msgb_length(msg);
|
||||
|
||||
return sh;
|
||||
}
|
||||
|
||||
/* transmit a given message to a specified slot. Expects all headers
|
||||
* present before calling the function */
|
||||
int st_slot_tx_msg(struct st_slot *slot, struct msgb *msg,
|
||||
uint8_t msg_class, uint8_t msg_type)
|
||||
{
|
||||
st_push_hdr(msg, msg_class, msg_type, slot->slot_nr);
|
||||
|
||||
return st_transp_tx_msg(slot->transp, msg);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Card Emulation protocol
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
/*! \brief Request the SIMtrace2 to generate a card-insert signal */
|
||||
int cardem_request_card_insert(struct cardem_inst *ci, bool inserted)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct cardemu_usb_msg_cardinsert *cins;
|
||||
|
||||
cins = (struct cardemu_usb_msg_cardinsert *) msgb_put(msg, sizeof(*cins));
|
||||
memset(cins, 0, sizeof(*cins));
|
||||
if (inserted)
|
||||
cins->card_insert = 1;
|
||||
|
||||
return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_CARDINSERT);
|
||||
}
|
||||
|
||||
/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Rx */
|
||||
int cardem_request_pb_and_rx(struct cardem_inst *ci, uint8_t pb, uint8_t le)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct cardemu_usb_msg_tx_data *txd;
|
||||
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
||||
|
||||
printf("<= %s(%02x, %d)\n", __func__, pb, le);
|
||||
|
||||
memset(txd, 0, sizeof(*txd));
|
||||
txd->data_len = 1;
|
||||
txd->flags = CEMU_DATA_F_PB_AND_RX;
|
||||
/* one data byte */
|
||||
msgb_put_u8(msg, pb);
|
||||
|
||||
return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA);
|
||||
}
|
||||
|
||||
/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */
|
||||
int cardem_request_pb_and_tx(struct cardem_inst *ci, uint8_t pb,
|
||||
const uint8_t *data, uint16_t data_len_in)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct cardemu_usb_msg_tx_data *txd;
|
||||
uint8_t *cur;
|
||||
|
||||
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
||||
|
||||
printf("<= %s(%02x, %s, %d)\n", __func__, pb,
|
||||
osmo_hexdump(data, data_len_in), data_len_in);
|
||||
|
||||
memset(txd, 0, sizeof(*txd));
|
||||
txd->data_len = 1 + data_len_in;
|
||||
txd->flags = CEMU_DATA_F_PB_AND_TX;
|
||||
/* procedure byte */
|
||||
msgb_put_u8(msg, pb);
|
||||
/* data */
|
||||
cur = msgb_put(msg, data_len_in);
|
||||
memcpy(cur, data, data_len_in);
|
||||
|
||||
return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA);
|
||||
}
|
||||
|
||||
/*! \brief Request the SIMtrace2 to send a Status Word */
|
||||
int cardem_request_sw_tx(struct cardem_inst *ci, const uint8_t *sw)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct cardemu_usb_msg_tx_data *txd;
|
||||
uint8_t *cur;
|
||||
|
||||
txd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*txd));
|
||||
|
||||
printf("<= %s(%02x %02x)\n", __func__, sw[0], sw[1]);
|
||||
|
||||
memset(txd, 0, sizeof(*txd));
|
||||
txd->data_len = 2;
|
||||
txd->flags = CEMU_DATA_F_PB_AND_TX | CEMU_DATA_F_FINAL;
|
||||
cur = msgb_put(msg, 2);
|
||||
cur[0] = sw[0];
|
||||
cur[1] = sw[1];
|
||||
|
||||
return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_TX_DATA);
|
||||
}
|
||||
|
||||
int cardem_request_set_atr(struct cardem_inst *ci, const uint8_t *atr, unsigned int atr_len)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct cardemu_usb_msg_set_atr *satr;
|
||||
uint8_t *cur;
|
||||
|
||||
satr = (struct cardemu_usb_msg_set_atr *) msgb_put(msg, sizeof(*satr));
|
||||
|
||||
printf("<= %s(%s)\n", __func__, osmo_hexdump(atr, atr_len));
|
||||
|
||||
memset(satr, 0, sizeof(*satr));
|
||||
satr->atr_len = atr_len;
|
||||
cur = msgb_put(msg, atr_len);
|
||||
memcpy(cur, atr, atr_len);
|
||||
|
||||
return st_slot_tx_msg(ci->slot, msg, SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGT_DT_CEMU_SET_ATR);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Modem Control protocol
|
||||
***********************************************************************/
|
||||
|
||||
static int _modem_reset(struct st_slot *slot, uint8_t asserted, uint16_t pulse_ms)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct st_modem_reset *sr ;
|
||||
|
||||
sr = (struct st_modem_reset *) msgb_put(msg, sizeof(*sr));
|
||||
sr->asserted = asserted;
|
||||
sr->pulse_duration_msec = pulse_ms;
|
||||
|
||||
return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_RESET);
|
||||
}
|
||||
|
||||
/*! \brief pulse the RESET line of the modem for \a duration_ms milli-seconds*/
|
||||
int st_modem_reset_pulse(struct st_slot *slot, uint16_t duration_ms)
|
||||
{
|
||||
return _modem_reset(slot, 2, duration_ms);
|
||||
}
|
||||
|
||||
/*! \brief assert the RESET line of the modem */
|
||||
int st_modem_reset_active(struct st_slot *slot)
|
||||
{
|
||||
return _modem_reset(slot, 1, 0);
|
||||
}
|
||||
|
||||
/*! \brief de-assert the RESET line of the modem */
|
||||
int st_modem_reset_inactive(struct st_slot *slot)
|
||||
{
|
||||
return _modem_reset(slot, 0, 0);
|
||||
}
|
||||
|
||||
static int _modem_sim_select(struct st_slot *slot, uint8_t remote_sim)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
struct st_modem_sim_select *ss;
|
||||
|
||||
ss = (struct st_modem_sim_select *) msgb_put(msg, sizeof(*ss));
|
||||
ss->remote_sim = remote_sim;
|
||||
|
||||
return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_DT_MODEM_SIM_SELECT);
|
||||
}
|
||||
|
||||
/*! \brief select local (physical) SIM for given slot */
|
||||
int st_modem_sim_select_local(struct st_slot *slot)
|
||||
{
|
||||
return _modem_sim_select(slot, 0);
|
||||
}
|
||||
|
||||
/*! \brief select remote (emulated/forwarded) SIM for given slot */
|
||||
int st_modem_sim_select_remote(struct st_slot *slot)
|
||||
{
|
||||
return _modem_sim_select(slot, 1);
|
||||
}
|
||||
|
||||
/*! \brief Request slot to send us status information about the modem */
|
||||
int st_modem_get_status(struct st_slot *slot)
|
||||
{
|
||||
struct msgb *msg = st_msgb_alloc();
|
||||
|
||||
return st_slot_tx_msg(slot, msg, SIMTRACE_MSGC_MODEM, SIMTRACE_MSGT_BD_MODEM_STATUS);
|
||||
}
|
||||
Reference in New Issue
Block a user