diff --git a/host/Makefile b/host/Makefile index 4f46c8f8..09e45be1 100644 --- a/host/Makefile +++ b/host/Makefile @@ -2,10 +2,10 @@ LDFLAGS=`pkg-config --libs libusb-1.0 libosmocore` -losmocore all: simtrace2-remsim simtrace2-remsim-usb2udp -simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o +simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o $(CC) -o $@ $^ $(LDFLAGS) -losmosim -simtrace2-remsim-usb2udp: usb2udp.o +simtrace2-remsim-usb2udp: usb2udp.o simtrace2-discovery.o $(CC) -o $@ $^ $(LDFLAGS) %.o: %.c diff --git a/host/simtrace.h b/host/simtrace.h index 0611f36a..c4a20daa 100644 --- a/host/simtrace.h +++ b/host/simtrace.h @@ -4,10 +4,4 @@ #define SIMTRACE_USB_VENDOR 0x1d50 #define SIMTRACE_USB_PRODUCT 0x60e3 -/* FIXME: automatically determine those values based on the usb config / - * interface descriptors */ -#define SIMTRACE_OUT_EP 0x04 -#define SIMTRACE_IN_EP 0x85 -#define SIMTRACE_INT_EP 0x86 - #endif diff --git a/host/simtrace2-discovery.c b/host/simtrace2-discovery.c new file mode 100644 index 00000000..38868fb6 --- /dev/null +++ b/host/simtrace2-discovery.c @@ -0,0 +1,75 @@ +#include + +#include + +/*! \brief obtain the endpoint addresses for a given USB interface */ +int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num, + uint8_t *out, uint8_t *in, uint8_t *irq) +{ + libusb_device *dev = libusb_get_device(devh); + struct libusb_config_descriptor *cdesc; + const struct libusb_interface_descriptor *idesc; + const struct libusb_interface *iface; + int rc, l; + + rc = libusb_get_active_config_descriptor(dev, &cdesc); + if (rc < 0) + return rc; + + iface = &cdesc->interface[if_num]; + /* FIXME: we assume there's no altsetting */ + idesc = &iface->altsetting[0]; + + for (l = 0; l < idesc->bNumEndpoints; l++) { + const struct libusb_endpoint_descriptor *edesc = &idesc->endpoint[l]; + switch (edesc->bmAttributes & 3) { + case LIBUSB_TRANSFER_TYPE_BULK: + if (edesc->bEndpointAddress & 0x80) { + if (in) + *in = edesc->bEndpointAddress; + } else { + if (out) + *out = edesc->bEndpointAddress; + } + break; + case LIBUSB_TRANSFER_TYPE_INTERRUPT: + if (irq) + *irq = edesc->bEndpointAddress; + break; + default: + break; + } + } + return 0; +} + +#if 0 + struct libusb_device_descriptor ddesc; + int rc, i, j, k; + + rc = libusb_get_device_descriptor(devh, &ddesc); + if (rc < 0) + return; + + for (i = 0; i < ddesc.bNumConfigurations; i++) { + struct libusb_config_descriptor *cdesc; + rc = libusb_get_config_descriptor(devh, i, &cdesc); + if (rc < 0) + return; + + for (j = 0; j < cdesc->bNumInterfaces; j++) { + const struct libusb_interface *iface = cdesc->interface[j]; + for (k = 0; k < iface->num_altsetting; k++) { + const struct libusb_interface_descriptor *idesc = iface->altsetting[k]; + /* make sure this is the interface we're looking for */ + if (idesc->bInterfaceClass != 0xFF || + idesc->bInterfaceSubClass != if_class || + idsec->bInterfaceProtocol != if_proto) + continue; + /* FIXME */ + } + } + + libusb_free_config_descriptor(cdesc); + } +#endif diff --git a/host/simtrace2-discovery.h b/host/simtrace2-discovery.h new file mode 100644 index 00000000..539b4712 --- /dev/null +++ b/host/simtrace2-discovery.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +int get_usb_ep_addrs(libusb_device_handle *devh, unsigned int if_num, + uint8_t *out, uint8_t *in, uint8_t *irq); diff --git a/host/simtrace2-remsim.c b/host/simtrace2-remsim.c index f22c3410..1fd2fa7f 100644 --- a/host/simtrace2-remsim.c +++ b/host/simtrace2-remsim.c @@ -37,6 +37,7 @@ #include "simtrace.h" #include "cardemu_prot.h" #include "apdu_dispatch.h" +#include "simtrace2-discovery.h" #include #include @@ -48,6 +49,8 @@ static struct gsmtap_inst *g_gti; struct libusb_device_handle *g_devh; const struct osim_cla_ins_card_profile *g_prof; +static uint8_t g_in_ep; +static uint8_t g_out_ep; static int g_udp_fd = -1; static struct osim_chan_hdl *g_chan; @@ -99,7 +102,7 @@ static int tx_to_dev(uint8_t *buf, unsigned int len) printf("<- %s\n", osmo_hexdump(buf, len)); if (g_udp_fd < 0) { - return libusb_bulk_transfer(g_devh, SIMTRACE_OUT_EP, buf, len, + return libusb_bulk_transfer(g_devh, g_out_ep, buf, len, &xfer_len, 100000); } else { return write(g_udp_fd, buf, len); @@ -331,7 +334,7 @@ static void run_mainloop(void) while (1) { /* read data from SIMtrace2 device (local or via USB) */ if (g_udp_fd < 0) { - rc = libusb_bulk_transfer(g_devh, SIMTRACE_IN_EP, buf, sizeof(buf), &xfer_len, 100000); + rc = libusb_bulk_transfer(g_devh, g_in_ep, buf, sizeof(buf), &xfer_len, 100000); if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT) { fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc); return; @@ -362,6 +365,7 @@ int main(int argc, char **argv) int skip_atr = 0; int keep_running = 0; int remote_udp_port = 52342; + int if_num = 0; char *remote_udp_host = NULL; struct osim_reader_hdl *reader; struct osim_card_hdl *card; @@ -371,7 +375,7 @@ int main(int argc, char **argv) while (1) { int option_index = 0; - c = getopt_long(argc, argv, "r:p:hi:ak", opts, &option_index); + c = getopt_long(argc, argv, "r:p:hi:I:ak", opts, &option_index); if (c == -1) break; switch (c) { @@ -388,6 +392,9 @@ int main(int argc, char **argv) case 'i': gsmtap_host = optarg; break; + case 'I': + if_num = atoi(optarg); + break; case 'a': skip_atr = 1; break; @@ -407,7 +414,7 @@ int main(int argc, char **argv) } } else { g_udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, remote_udp_host, - remote_udp_port, OSMO_SOCK_F_CONNECT); + remote_udp_port+if_num, OSMO_SOCK_F_CONNECT); if (g_udp_fd < 0) { fprintf(stderr, "error binding UDP port\n"); goto do_exit; @@ -447,9 +454,15 @@ int main(int argc, char **argv) goto close_exit; } - rc = libusb_claim_interface(g_devh, 0); + rc = libusb_claim_interface(g_devh, if_num); if (rc < 0) { - fprintf(stderr, "can't claim interface; rc=%d\n", rc); + fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc); + goto close_exit; + } + + rc = get_usb_ep_addrs(g_devh, if_num, &g_out_ep, &g_in_ep, NULL); + if (rc < 0) { + fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc); goto close_exit; } } diff --git a/host/usb2udp.c b/host/usb2udp.c index fcf508a7..e33e3712 100644 --- a/host/usb2udp.c +++ b/host/usb2udp.c @@ -38,6 +38,7 @@ #include "simtrace.h" #include "cardemu_prot.h" #include "apdu_dispatch.h" +#include "simtrace2-discovery.h" #include #include @@ -56,6 +57,7 @@ static void print_welcome(void) static void print_help(void) { printf( "\t-h\t--help\n" + "\t-i\t--interface <0-255>\n" "\n" ); } @@ -76,8 +78,7 @@ static void usb_in_xfer_cb(struct libusb_transfer *xfer) xfer->endpoint, xfer->status, xfer->flags, xfer->type, xfer->length, xfer->actual_length); switch (xfer->status) { case LIBUSB_TRANSFER_COMPLETED: - switch (xfer->endpoint) { - case SIMTRACE_IN_EP: + if (xfer->endpoint == g_buf_in.ep) { /* process the data */ printf("read %d bytes from SIMTRACE, forwarding to UDP\n", xfer->actual_length); rc = sendto(g_udp_ofd.fd, xfer->buffer, xfer->actual_length, 0, (struct sockaddr *)&g_sa_remote, sizeof(g_sa_remote)); @@ -86,11 +87,9 @@ static void usb_in_xfer_cb(struct libusb_transfer *xfer) } /* and re-submit the URB */ libusb_submit_transfer(xfer); - break; - case SIMTRACE_OUT_EP: + } else if (xfer->endpoint == g_buf_out.ep) { /* re-enable reading from the UDP side */ g_udp_ofd.when |= BSC_FD_READ; - break; } break; default: @@ -99,9 +98,8 @@ static void usb_in_xfer_cb(struct libusb_transfer *xfer) } } -static void init_ep_buf(int ep, struct ep_buf *epb) +static void init_ep_buf(struct ep_buf *epb) { - epb->ep = ep; if (!epb->xfer) epb->xfer = libusb_alloc_transfer(0); @@ -208,6 +206,7 @@ int main(int argc, char **argv) int c, ret = 1; char *remote_host = NULL; int local_udp_port = 52342; + unsigned int if_num = 0; print_welcome(); @@ -215,17 +214,21 @@ int main(int argc, char **argv) int option_index = 0; static const struct option opts[] = { { "udp-port", 1, 0, 'u' }, + { "interface", 1, 0, 'I' }, { "help", 0, 0, 'h' }, { NULL, 0, 0, 0 } }; - c = getopt_long(argc, argv, "u:p:h", opts, &option_index); + c = getopt_long(argc, argv, "u:I:h", opts, &option_index); if (c == -1) break; switch (c) { case 'u': local_udp_port = atoi(optarg); break; + case 'I': + if_num = atoi(optarg); + break; case 'h': print_help(); exit(0); @@ -247,20 +250,25 @@ int main(int argc, char **argv) goto close_exit; } - rc = libusb_claim_interface(g_devh, 0); + rc = libusb_claim_interface(g_devh, if_num); if (rc < 0) { - fprintf(stderr, "can't claim interface; rc=%d\n", rc); + fprintf(stderr, "can't claim interface %u; rc=%d\n", if_num, rc); goto close_exit; } /* open UDP socket, register with select handling and mark it * readable */ g_udp_ofd.cb = ofd_udp_cb; - osmo_sock_init_ofd(&g_udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, local_udp_port, OSMO_SOCK_F_BIND); + osmo_sock_init_ofd(&g_udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, local_udp_port + if_num, OSMO_SOCK_F_BIND); + rc = get_usb_ep_addrs(g_devh, if_num, &g_buf_out.ep, &g_buf_in.ep, NULL); + if (rc < 0) { + fprintf(stderr, "couldn't find enpdoint addresses; rc=%d\n", rc); + goto close_exit; + } /* initialize USB buffers / transfers */ - init_ep_buf(SIMTRACE_OUT_EP, &g_buf_out); - init_ep_buf(SIMTRACE_IN_EP, &g_buf_in); + init_ep_buf(&g_buf_out); + init_ep_buf(&g_buf_in); /* submit the first transfer for the IN endpoint */ libusb_submit_transfer(g_buf_in.xfer);