blob: b61b7d0e1fcc4258ead1804926b0e0f3c09881f0 [file] [log] [blame]
Kévin Redonefbcf382018-07-07 17:35:15 +02001/* simtrace2-sniff - main program for the host PC to communicate with the
2 * SIMtrace 2 firmware in sniffer mode
3 *
4 * (C) 2016 by Harald Welte <hwelte@hmw-consulting.de>
5 * (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
6 *
7 * This program is free software; you can redistribute it and/or
Kévin Redon6e3f1122018-07-01 18:24:42 +02008 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Kévin Redon6e3f1122018-07-01 18:24:42 +020020 */
21#include <errno.h>
22#include <unistd.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdint.h>
27#include <signal.h>
28#include <time.h>
29#define _GNU_SOURCE
30#include <getopt.h>
31
32#include <sys/time.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37
38#include <libusb.h>
39
40#include "libusb_util.h"
41#include "simtrace.h"
42#include "simtrace_usb.h"
43#include "simtrace_prot.h"
44#include "simtrace2-discovery.h"
45
46#include <osmocom/core/gsmtap.h>
47#include <osmocom/core/gsmtap_util.h>
48#include <osmocom/core/utils.h>
49#include <osmocom/core/socket.h>
50#include <osmocom/core/msgb.h>
51#include <osmocom/sim/class_tables.h>
52#include <osmocom/sim/sim.h>
53
54/* transport to a SIMtrace device */
55struct st_transport {
56 /* USB */
57 struct libusb_device_handle *usb_devh;
58 struct {
59 uint8_t in;
60 uint8_t out;
61 uint8_t irq_in;
62 } usb_ep;
63};
64
65/* global GSMTAP instance */
66static struct gsmtap_inst *g_gti;
67
68static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len)
69{
70 struct gsmtap_hdr *gh;
71 unsigned int gross_len = len + sizeof(*gh);
72 uint8_t *buf = malloc(gross_len);
73 int rc;
74
75 if (!buf)
76 return -ENOMEM;
77
78 memset(buf, 0, sizeof(*gh));
79 gh = (struct gsmtap_hdr *) buf;
80 gh->version = GSMTAP_VERSION;
81 gh->hdr_len = sizeof(*gh)/4;
82 gh->type = GSMTAP_TYPE_SIM;
83
84 memcpy(buf + sizeof(*gh), apdu, len);
85
86 rc = write(gsmtap_inst_fd(g_gti), buf, gross_len);
87 if (rc < 0) {
88 perror("write gsmtap");
89 free(buf);
90 return rc;
91 }
92
93 free(buf);
94 return 0;
95}
96
Kévin Redon709a4312018-07-03 16:10:04 +020097static int process_change(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +020098{
99 /* check if there is enough data for the structure */
100 if (len<sizeof(struct sniff_change)) {
101 return -1;
102 }
103 struct sniff_change *change = (struct sniff_change *)buf;
104
Kévin Redon709a4312018-07-03 16:10:04 +0200105 printf("Card state change: ");
Kévin Redon6e3f1122018-07-01 18:24:42 +0200106 if (change->flags&SNIFF_CHANGE_FLAG_CARD_INSERT) {
107 printf("card inserted ");
108 }
109 if (change->flags&SNIFF_CHANGE_FLAG_CARD_EJECT) {
110 printf("card ejected ");
111 }
112 if (change->flags&SNIFF_CHANGE_FLAG_RESET_HOLD) {
113 printf("reset hold ");
114 }
115 if (change->flags&SNIFF_CHANGE_FLAG_RESET_RELEASE) {
116 printf("reset release ");
117 }
118 if (change->flags&SNIFF_CHANGE_FLAG_TIMEOUT_WT) {
Kévin Redon709a4312018-07-03 16:10:04 +0200119 printf("data transfer timeout ");
Kévin Redon6e3f1122018-07-01 18:24:42 +0200120 }
Kévin Redon709a4312018-07-03 16:10:04 +0200121 printf("\n");
Kévin Redon6e3f1122018-07-01 18:24:42 +0200122
123 return 0;
124}
125
126/* Table 7 of ISO 7816-3:2006 */
127static const uint16_t fi_table[] = { 372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768, 1024, 1536, 2048, 0, 0, };
128
129/* Table 8 from ISO 7816-3:2006 */
130static const uint8_t di_table[] = { 0, 1, 2, 4, 8, 16, 32, 64, 12, 20, 2, 4, 8, 16, 32, 64, };
131
Kévin Redon709a4312018-07-03 16:10:04 +0200132static int process_fidi(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200133{
134 /* check if there is enough data for the structure */
135 if (len<sizeof(struct sniff_fidi)) {
136 return -1;
137 }
138 struct sniff_fidi *fidi = (struct sniff_fidi *)buf;
139
140 printf("Fi/Di switched to %u/%u\n", fi_table[fidi->fidi>>4], di_table[fidi->fidi&0x0f]);
141 return 0;
142}
143
Kévin Redon709a4312018-07-03 16:10:04 +0200144static int process_atr(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200145{
146 /* check if there is enough data for the structure */
147 if (len<sizeof(struct sniff_data)) {
148 return -1;
149 }
150 struct sniff_data *atr = (struct sniff_data *)buf;
151
152 /* check if the data is available */
153 if (len<sizeof(struct sniff_data)+atr->length) {
154 return -2;
155 }
156
157 printf("ATR%s: ", atr->complete ? "" : " (incomplete)");
158 uint16_t i;
159 for (i = 0; i < atr->length; i++) {
160 printf("%02x ", atr->data[i]);
161 }
162 printf("\n");
163 return 0;
164}
165
Kévin Redon709a4312018-07-03 16:10:04 +0200166static int process_pps(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200167{
168 /* check if there is enough data for the structure */
169 if (len<sizeof(struct sniff_data)) {
170 return -1;
171 }
172 struct sniff_data *pps = (struct sniff_data *)buf;
173
174 /* check if the data is available */
175 if (len<sizeof(struct sniff_data)+pps->length) {
176 return -2;
177 }
178
179 printf("PPS%s: ", pps->complete ? "" : " (incomplete) ");
180 uint16_t i;
181 for (i = 0; i < pps->length; i++) {
182 printf("%02x ", pps->data[i]);
183 }
184 printf("\n");
185 return 0;
186}
187
Kévin Redon709a4312018-07-03 16:10:04 +0200188static int process_tpdu(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200189{
190 /* check if there is enough data for the structure */
191 if (len<sizeof(struct sniff_data)) {
192 return -1;
193 }
194 struct sniff_data *tpdu = (struct sniff_data *)buf;
195
196 /* check if the data is available */
197 if (len<sizeof(struct sniff_data)+tpdu->length) {
198 return -2;
199 }
200
Kévin Redon709a4312018-07-03 16:10:04 +0200201 /* print TPDU */
Kévin Redon6e3f1122018-07-01 18:24:42 +0200202 printf("TPDU%s: ", tpdu->complete ? "" : " (incomplete)");
203 uint16_t i;
204 for (i = 0; i < tpdu->length; i++) {
205 printf("%02x ", tpdu->data[i]);
206 }
207 printf("\n");
Kévin Redon709a4312018-07-03 16:10:04 +0200208
209 /* send TPDU (now considered as APDU) to GSMTAP */
210 gsmtap_send_sim(tpdu->data, tpdu->length);
Kévin Redon6e3f1122018-07-01 18:24:42 +0200211 return 0;
212}
213
214/*! \brief Process an incoming message from the SIMtrace2 */
Kévin Redon709a4312018-07-03 16:10:04 +0200215static int process_usb_msg(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200216{
217 /* check if enough data for the header is present */
218 if (len<sizeof(struct simtrace_msg_hdr)) {
219 return 0;
220 }
221
222 /* check if message is complete */
223 struct simtrace_msg_hdr *msg_hdr = (struct simtrace_msg_hdr *)buf;
224 if (len<msg_hdr->msg_len) {
225 return 0;
226 }
227 //printf("msg: %s\n", osmo_hexdump(buf, msg_hdr->msg_len));
228
229 /* check for message class */
230 if (SIMTRACE_MSGC_SNIFF!=msg_hdr->msg_class) { /* we only care about sniffing messages */
231 return msg_hdr->msg_len; /* discard non-sniffing messaged */
232 }
233
234 /* process sniff message payload */
235 buf += sizeof(struct simtrace_msg_hdr);
236 len -= sizeof(struct simtrace_msg_hdr);
237 switch (msg_hdr->msg_type) {
238 case SIMTRACE_MSGT_SNIFF_CHANGE:
239 process_change(buf, len);
240 break;
241 case SIMTRACE_MSGT_SNIFF_FIDI:
242 process_fidi(buf, len);
243 break;
244 case SIMTRACE_MSGT_SNIFF_ATR:
245 process_atr(buf, len);
246 break;
247 case SIMTRACE_MSGT_SNIFF_PPS:
248 process_pps(buf, len);
249 break;
250 case SIMTRACE_MSGT_SNIFF_TPDU:
251 process_tpdu(buf, len);
252 break;
253 default:
254 printf("unknown SIMtrace msg type 0x%02x\n", msg_hdr->msg_type);
255 break;
256 }
257
258 return msg_hdr->msg_len;
259}
260
261/*! Transport to SIMtrace device (e.g. USB handle) */
262static struct st_transport _transp;
263
264static void run_mainloop()
265{
266 int rc;
267 uint8_t buf[16*256];
268 unsigned int i, buf_i = 0;
269 int xfer_len;
270
271 printf("Entering main loop\n");
272
273 while (true) {
274 /* read data from SIMtrace2 device (via USB) */
275 rc = libusb_bulk_transfer(_transp.usb_devh, _transp.usb_ep.in,
276 &buf[buf_i], sizeof(buf)-buf_i, &xfer_len, 100000);
277 if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
278 rc != LIBUSB_ERROR_INTERRUPTED &&
279 rc != LIBUSB_ERROR_IO) {
280 fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
281 return;
282 }
283 /* dispatch any incoming data */
284 if (xfer_len > 0) {
285 //printf("URB: %s\n", osmo_hexdump(&buf[buf_i], xfer_len));
286 buf_i += xfer_len;
287 if (buf_i>=sizeof(buf)) {
288 perror("preventing USB buffer overflow");
289 return;
290 }
291 int processed = process_usb_msg(buf, buf_i);
292 if (processed > 0 && processed <= buf_i) {
293 for (i = processed; i < buf_i; i++) {
294 buf[i-processed] = buf[i];
295 }
296 buf_i -= processed;
297 }
298 }
299 }
300}
301
302static void print_welcome(void)
303{
304 printf("simtrace2-sniff - Phone-SIM card communication sniffer \n"
305 "(C) 2010-2017 by Harald Welte <laforge@gnumonks.org>\n"
306 "(C) 2018 by Kevin Redon <kredon@sysmocom.de>\n"
307 "\n"
308 );
309}
310
311static void print_help(void)
312{
313 printf(
314 "\t-h\t--help\n"
315 "\t-i\t--gsmtap-ip\tA.B.C.D\n"
316 "\t-k\t--keep-running\n"
317 "\t-V\t--usb-vendor\tVENDOR_ID\n"
318 "\t-P\t--usb-product\tPRODUCT_ID\n"
319 "\t-C\t--usb-config\tCONFIG_ID\n"
320 "\t-I\t--usb-interface\tINTERFACE_ID\n"
321 "\t-S\t--usb-altsetting ALTSETTING_ID\n"
322 "\t-A\t--usb-address\tADDRESS\n"
323 "\n"
324 );
325}
326
327static const struct option opts[] = {
328 { "help", 0, 0, 'h' },
329 { "gsmtap-ip", 1, 0, 'i' },
330 { "keep-running", 0, 0, 'k' },
331 { "usb-vendor", 1, 0, 'V' },
332 { "usb-product", 1, 0, 'P' },
333 { "usb-config", 1, 0, 'C' },
334 { "usb-interface", 1, 0, 'I' },
335 { "usb-altsetting", 1, 0, 'S' },
336 { "usb-address", 1, 0, 'A' },
337 { NULL, 0, 0, 0 }
338};
339
340/* Known USB device with SIMtrace firmware supporting sniffer */
341static const struct dev_id compatible_dev_ids[] = {
342 { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
343 { 0, 0 }
344};
345
346static void signal_handler(int signal)
347{
348 switch (signal) {
349 case SIGINT:
350 exit(0);
351 break;
352 default:
353 break;
354 }
355}
356
357int main(int argc, char **argv)
358{
359 int i, rc, ret;
360 print_welcome();
361
362 /* Parse arguments */
363 char *gsmtap_host = "127.0.0.1";
364 int keep_running = 0;
365 int vendor_id = -1, product_id = -1, addr = -1, config_id = -1, if_num = -1, altsetting = -1;
366
367 while (1) {
368 int option_index = 0;
369
370 char c = getopt_long(argc, argv, "hi:kV:P:C:I:S:A:", opts, &option_index);
371 if (c == -1)
372 break;
373 switch (c) {
374 case 'h':
375 print_help();
376 exit(0);
377 break;
378 case 'i':
379 gsmtap_host = optarg;
380 break;
381 case 'k':
382 keep_running = 1;
383 break;
384 case 'V':
385 vendor_id = strtol(optarg, NULL, 16);
386 break;
387 case 'P':
388 product_id = strtol(optarg, NULL, 16);
389 break;
390 case 'C':
391 config_id = atoi(optarg);
392 break;
393 case 'I':
394 if_num = atoi(optarg);
395 break;
396 case 'S':
397 altsetting = atoi(optarg);
398 break;
399 case 'A':
400 addr = atoi(optarg);
401 break;
402 }
403 }
404
405 /* Scan for available SIMtrace USB devices supporting sniffing */
406 rc = libusb_init(NULL);
407 if (rc < 0) {
408 fprintf(stderr, "libusb initialization failed\n");
409 goto do_exit;
410 }
411 struct usb_interface_match ifm_scan[16];
412 int num_interfaces = usb_match_interfaces(NULL, compatible_dev_ids,
413 USB_CLASS_PROPRIETARY, SIMTRACE_SNIFFER_USB_SUBCLASS, -1, ifm_scan, ARRAY_SIZE(ifm_scan));
414 if (num_interfaces <= 0) {
415 perror("No compatible USB devices found");
416 goto do_exit;
417 }
418
419 /* Only keep USB matching arguments */
420 struct usb_interface_match ifm_filtered[ARRAY_SIZE(ifm_scan)];
421 int num_filtered = 0;
422 for (i = 0; i < num_interfaces; i++) {
423 if (vendor_id>=0 && vendor_id!=ifm_scan[i].vendor) {
424 continue;
425 }
426 if (product_id>=0 && product_id!=ifm_scan[i].product) {
427 continue;
428 }
429 if (config_id>=0 && config_id!=ifm_scan[i].configuration) {
430 continue;
431 }
432 if (if_num>=0 && if_num!=ifm_scan[i].interface) {
433 continue;
434 }
435 if (altsetting>=0 && altsetting!=ifm_scan[i].altsetting) {
436 continue;
437 }
438 if (addr>=0 && addr!=ifm_scan[i].addr) {
439 continue;
440 }
441 ifm_filtered[num_filtered++] = ifm_scan[i];
442 }
443 if (1!=num_filtered) {
444 perror("No individual matching USB devices found");
445 printf("Available USB devices:\n");
446 for (i = 0; i < num_interfaces; i++) {
447 printf("\t%04x:%04x Addr=%u, Path=%s, Cfg=%u, Intf=%u, Alt=%u: %d/%d/%d ",
448 ifm_scan[i].vendor, ifm_scan[i].product, ifm_scan[i].addr, ifm_scan[i].path,
449 ifm_scan[i].configuration, ifm_scan[i].interface, ifm_scan[i].altsetting,
450 ifm_scan[i].class, ifm_scan[i].sub_class, ifm_scan[i].protocol);
451 libusb_device_handle *dev_handle;
452 rc = libusb_open(ifm_scan[i].usb_dev, &dev_handle);
453 if (rc < 0) {
454 printf("\n");
455 perror("Cannot open device");
456 continue;
457 }
458 char strbuf[256];
459 rc = libusb_get_string_descriptor_ascii(dev_handle, ifm_scan[i].string_idx,
460 (unsigned char *)strbuf, sizeof(strbuf));
461 libusb_close(dev_handle);
462 if (rc < 0) {
463 printf("\n");
464 perror("Cannot read string");
465 continue;
466 }
467 printf("(%s)\n", strbuf);
468 }
469 goto do_exit;
470 }
471 struct usb_interface_match ifm_selected = ifm_filtered[0];
472 printf("Using USB device %04x:%04x Addr=%u, Path=%s, Cfg=%u, Intf=%u, Alt=%u: %d/%d/%d ",
473 ifm_selected.vendor, ifm_selected.product, ifm_selected.addr, ifm_selected.path,
474 ifm_selected.configuration, ifm_selected.interface, ifm_selected.altsetting,
475 ifm_selected.class, ifm_selected.sub_class, ifm_selected.protocol);
476 libusb_device_handle *dev_handle;
477 rc = libusb_open(ifm_selected.usb_dev, &dev_handle);
478 if (rc < 0) {
479 printf("\n");
480 perror("Cannot open device");
481 }
482 char strbuf[256];
483 rc = libusb_get_string_descriptor_ascii(dev_handle, ifm_selected.string_idx,
484 (unsigned char *)strbuf, sizeof(strbuf));
485 libusb_close(dev_handle);
486 if (rc < 0) {
487 printf("\n");
488 perror("Cannot read string");
489 }
490 printf("(%s)\n", strbuf);
491
492 g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0);
493 if (!g_gti) {
494 perror("unable to open GSMTAP");
495 goto close_exit;
496 }
497 gsmtap_source_add_sink(g_gti);
498
499 signal(SIGINT, &signal_handler);
500
501 do {
502 _transp.usb_devh = usb_open_claim_interface(NULL, &ifm_selected);
503 if (!_transp.usb_devh) {
504 fprintf(stderr, "can't open USB device\n");
505 goto close_exit;
506 }
507
508 rc = libusb_claim_interface(_transp.usb_devh, ifm_selected.interface);
509 if (rc < 0) {
510 fprintf(stderr, "can't claim interface %d; rc=%d\n", ifm_selected.interface, rc);
511 goto close_exit;
512 }
513
514 rc = get_usb_ep_addrs(_transp.usb_devh, ifm_selected.interface, &_transp.usb_ep.out,
515 &_transp.usb_ep.in, &_transp.usb_ep.irq_in);
516 if (rc < 0) {
517 fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
518 goto close_exit;
519 }
520
521 run_mainloop();
522 ret = 0;
523
524 if (_transp.usb_devh)
525 libusb_release_interface(_transp.usb_devh, 0);
526close_exit:
527 if (_transp.usb_devh)
528 libusb_close(_transp.usb_devh);
529 if (keep_running)
530 sleep(1);
531 } while (keep_running);
532
533 libusb_exit(NULL);
534do_exit:
535 return ret;
536}