blob: b2ce4a005a78b8f24871bb7ee27fa3dc115a2f41 [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
Harald Welte964cda32019-11-24 22:27:10 +010040#include <osmocom/simtrace2/libusb_util.h>
41#include <osmocom/simtrace2/simtrace_usb.h>
42#include <osmocom/simtrace2/simtrace_prot.h>
Kévin Redon6e3f1122018-07-01 18:24:42 +020043
Harald Welte964cda32019-11-24 22:27:10 +010044#include <osmocom/simtrace2/gsmtap.h>
45
Kévin Redon6e3f1122018-07-01 18:24:42 +020046#include <osmocom/core/utils.h>
47#include <osmocom/core/socket.h>
48#include <osmocom/core/msgb.h>
49#include <osmocom/sim/class_tables.h>
50#include <osmocom/sim/sim.h>
51
52/* transport to a SIMtrace device */
53struct st_transport {
54 /* USB */
55 struct libusb_device_handle *usb_devh;
56 struct {
57 uint8_t in;
58 uint8_t out;
59 uint8_t irq_in;
60 } usb_ep;
61};
62
Kévin Redon31ed8022018-07-10 16:04:00 +020063const struct value_string change_flags[] = {
64 {
65 .value = SNIFF_CHANGE_FLAG_CARD_INSERT,
66 .str = "card inserted",
67 },
68 {
69 .value = SNIFF_CHANGE_FLAG_CARD_EJECT,
70 .str = "card ejected",
71 },
72 {
Kévin Redon8e84f812018-07-26 15:34:03 +020073 .value = SNIFF_CHANGE_FLAG_RESET_ASSERT,
74 .str = "reset asserted",
Kévin Redon31ed8022018-07-10 16:04:00 +020075 },
76 {
Kévin Redon8e84f812018-07-26 15:34:03 +020077 .value = SNIFF_CHANGE_FLAG_RESET_DEASSERT,
78 .str = "reset de-asserted",
Kévin Redon31ed8022018-07-10 16:04:00 +020079 },
80 {
81 .value = SNIFF_CHANGE_FLAG_TIMEOUT_WT,
82 .str = "data transfer timeout",
83 },
84 {
85 .value = 0,
86 .str = NULL,
87 },
88};
89
90const struct value_string data_flags[] = {
91 {
92 .value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE,
93 .str = "incomplete",
94 },
95 {
96 .value = SNIFF_DATA_FLAG_ERROR_MALFORMED,
97 .str = "malformed",
98 },
99 {
Kévin Redonf66af0c2018-07-11 10:27:13 +0200100 .value = SNIFF_DATA_FLAG_ERROR_CHECKSUM,
101 .str = "checksum error",
102 },
Kévin Redon69719962018-07-28 17:11:21 +0200103 {
104 .value = 0,
105 .str = NULL,
106 },
Kévin Redon31ed8022018-07-10 16:04:00 +0200107};
108
109static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) {
110 uint32_t i;
111 for (i = 0; i < nb_flags; i++) {
112 if (flags & flag_meanings[i].value) {
Oliver Smith15e943a2019-11-27 19:08:55 +0100113 printf("%s", flag_meanings[i].str);
Kévin Redon31ed8022018-07-10 16:04:00 +0200114 flags &= ~flag_meanings[i].value;
115 if (flags) {
116 printf(", ");
117 }
118 }
119 }
120}
121
Kévin Redon709a4312018-07-03 16:10:04 +0200122static int process_change(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200123{
124 /* check if there is enough data for the structure */
Kévin Redonf82f0f62018-07-08 15:10:23 +0200125 if (len < sizeof(struct sniff_change)) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200126 return -1;
127 }
128 struct sniff_change *change = (struct sniff_change *)buf;
129
Kévin Redon709a4312018-07-03 16:10:04 +0200130 printf("Card state change: ");
Kévin Redon31ed8022018-07-10 16:04:00 +0200131 if (change->flags) {
132 print_flags(change_flags, ARRAY_SIZE(change_flags), change->flags);
133 printf("\n");
134 } else {
135 printf("no changes\n");
Kévin Redon6e3f1122018-07-01 18:24:42 +0200136 }
Kévin Redon6e3f1122018-07-01 18:24:42 +0200137
138 return 0;
139}
140
141/* Table 7 of ISO 7816-3:2006 */
142static const uint16_t fi_table[] = { 372, 372, 558, 744, 1116, 1488, 1860, 0, 0, 512, 768, 1024, 1536, 2048, 0, 0, };
143
144/* Table 8 from ISO 7816-3:2006 */
145static const uint8_t di_table[] = { 0, 1, 2, 4, 8, 16, 32, 64, 12, 20, 2, 4, 8, 16, 32, 64, };
146
Kévin Redon709a4312018-07-03 16:10:04 +0200147static int process_fidi(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200148{
149 /* check if there is enough data for the structure */
150 if (len<sizeof(struct sniff_fidi)) {
151 return -1;
152 }
153 struct sniff_fidi *fidi = (struct sniff_fidi *)buf;
154
155 printf("Fi/Di switched to %u/%u\n", fi_table[fidi->fidi>>4], di_table[fidi->fidi&0x0f]);
156 return 0;
157}
158
Kévin Redonf82f0f62018-07-08 15:10:23 +0200159static int process_data(enum simtrace_msg_type_sniff type, const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200160{
161 /* check if there is enough data for the structure */
Kévin Redonf82f0f62018-07-08 15:10:23 +0200162 if (len < sizeof(struct sniff_data)) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200163 return -1;
164 }
Kévin Redonf82f0f62018-07-08 15:10:23 +0200165 struct sniff_data *data = (struct sniff_data *)buf;
Kévin Redon6e3f1122018-07-01 18:24:42 +0200166
167 /* check if the data is available */
Kévin Redonf82f0f62018-07-08 15:10:23 +0200168 if (len < sizeof(struct sniff_data) + data->length) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200169 return -2;
170 }
171
Kévin Redonf82f0f62018-07-08 15:10:23 +0200172 /* check type */
173 if (type != SIMTRACE_MSGT_SNIFF_ATR && type != SIMTRACE_MSGT_SNIFF_PPS && type != SIMTRACE_MSGT_SNIFF_TPDU) {
174 return -3;
175 }
176
177 /* Print message */
178 switch (type) {
179 case SIMTRACE_MSGT_SNIFF_ATR:
180 printf("ATR");
181 break;
182 case SIMTRACE_MSGT_SNIFF_PPS:
183 printf("PPS");
184 break;
185 case SIMTRACE_MSGT_SNIFF_TPDU:
186 printf("TPDU");
187 break;
188 default:
189 printf("???");
190 break;
191 }
192 if (data->flags) {
193 printf(" (");
Kévin Redon31ed8022018-07-10 16:04:00 +0200194 print_flags(data_flags, ARRAY_SIZE(data_flags), data->flags);
Kévin Redonf82f0f62018-07-08 15:10:23 +0200195 printf(")");
196 }
197 printf(": ");
Kévin Redon6e3f1122018-07-01 18:24:42 +0200198 uint16_t i;
Kévin Redonf82f0f62018-07-08 15:10:23 +0200199 for (i = 0; i < data->length; i++) {
200 printf("%02x ", data->data[i]);
Kévin Redon6e3f1122018-07-01 18:24:42 +0200201 }
202 printf("\n");
Kévin Redon709a4312018-07-03 16:10:04 +0200203
Kévin Redond1c65362018-07-26 14:51:15 +0200204 /* Send message as GSNTAP */
205 switch (type) {
206 case SIMTRACE_MSGT_SNIFF_ATR:
Harald Welte964cda32019-11-24 22:27:10 +0100207 osmo_st2_gsmtap_send_apdu(GSMTAP_SIM_ATR, data->data, data->length);
Kévin Redond1c65362018-07-26 14:51:15 +0200208 break;
209 case SIMTRACE_MSGT_SNIFF_TPDU:
210 /* TPDU is now considered as APDU since SIMtrace sends complete TPDU */
Harald Welte964cda32019-11-24 22:27:10 +0100211 osmo_st2_gsmtap_send_apdu(GSMTAP_SIM_APDU, data->data, data->length);
Kévin Redond1c65362018-07-26 14:51:15 +0200212 break;
213 default:
214 break;
Kévin Redonf82f0f62018-07-08 15:10:23 +0200215 }
216
Kévin Redon6e3f1122018-07-01 18:24:42 +0200217 return 0;
218}
219
220/*! \brief Process an incoming message from the SIMtrace2 */
Kévin Redon709a4312018-07-03 16:10:04 +0200221static int process_usb_msg(const uint8_t *buf, int len)
Kévin Redon6e3f1122018-07-01 18:24:42 +0200222{
223 /* check if enough data for the header is present */
Kévin Redonf82f0f62018-07-08 15:10:23 +0200224 if (len < sizeof(struct simtrace_msg_hdr)) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200225 return 0;
226 }
227
228 /* check if message is complete */
229 struct simtrace_msg_hdr *msg_hdr = (struct simtrace_msg_hdr *)buf;
Kévin Redonf82f0f62018-07-08 15:10:23 +0200230 if (len < msg_hdr->msg_len) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200231 return 0;
232 }
233 //printf("msg: %s\n", osmo_hexdump(buf, msg_hdr->msg_len));
234
235 /* check for message class */
Kévin Redonf82f0f62018-07-08 15:10:23 +0200236 if (SIMTRACE_MSGC_SNIFF != msg_hdr->msg_class) { /* we only care about sniffing messages */
Kévin Redon6e3f1122018-07-01 18:24:42 +0200237 return msg_hdr->msg_len; /* discard non-sniffing messaged */
238 }
239
240 /* process sniff message payload */
241 buf += sizeof(struct simtrace_msg_hdr);
242 len -= sizeof(struct simtrace_msg_hdr);
243 switch (msg_hdr->msg_type) {
244 case SIMTRACE_MSGT_SNIFF_CHANGE:
245 process_change(buf, len);
246 break;
247 case SIMTRACE_MSGT_SNIFF_FIDI:
248 process_fidi(buf, len);
249 break;
250 case SIMTRACE_MSGT_SNIFF_ATR:
Kévin Redon6e3f1122018-07-01 18:24:42 +0200251 case SIMTRACE_MSGT_SNIFF_PPS:
Kévin Redon6e3f1122018-07-01 18:24:42 +0200252 case SIMTRACE_MSGT_SNIFF_TPDU:
Kévin Redonf82f0f62018-07-08 15:10:23 +0200253 process_data(msg_hdr->msg_type, buf, len);
Kévin Redon6e3f1122018-07-01 18:24:42 +0200254 break;
255 default:
256 printf("unknown SIMtrace msg type 0x%02x\n", msg_hdr->msg_type);
257 break;
258 }
259
260 return msg_hdr->msg_len;
261}
262
263/*! Transport to SIMtrace device (e.g. USB handle) */
264static struct st_transport _transp;
265
266static void run_mainloop()
267{
268 int rc;
269 uint8_t buf[16*256];
270 unsigned int i, buf_i = 0;
271 int xfer_len;
272
273 printf("Entering main loop\n");
274
275 while (true) {
276 /* read data from SIMtrace2 device (via USB) */
277 rc = libusb_bulk_transfer(_transp.usb_devh, _transp.usb_ep.in,
278 &buf[buf_i], sizeof(buf)-buf_i, &xfer_len, 100000);
279 if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
280 rc != LIBUSB_ERROR_INTERRUPTED &&
281 rc != LIBUSB_ERROR_IO) {
282 fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
283 return;
284 }
285 /* dispatch any incoming data */
286 if (xfer_len > 0) {
287 //printf("URB: %s\n", osmo_hexdump(&buf[buf_i], xfer_len));
288 buf_i += xfer_len;
Kévin Redon3b7624c2018-07-10 16:03:27 +0200289 if (buf_i >= sizeof(buf)) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200290 perror("preventing USB buffer overflow");
291 return;
292 }
Kévin Redon3b7624c2018-07-10 16:03:27 +0200293 int processed;
294 while ((processed = process_usb_msg(buf, buf_i)) > 0) {
295 if (processed > buf_i) {
296 break;
297 }
Kévin Redon6e3f1122018-07-01 18:24:42 +0200298 for (i = processed; i < buf_i; i++) {
299 buf[i-processed] = buf[i];
300 }
301 buf_i -= processed;
302 }
303 }
304 }
305}
306
307static void print_welcome(void)
308{
309 printf("simtrace2-sniff - Phone-SIM card communication sniffer \n"
310 "(C) 2010-2017 by Harald Welte <laforge@gnumonks.org>\n"
311 "(C) 2018 by Kevin Redon <kredon@sysmocom.de>\n"
312 "\n"
313 );
314}
315
316static void print_help(void)
317{
318 printf(
319 "\t-h\t--help\n"
320 "\t-i\t--gsmtap-ip\tA.B.C.D\n"
321 "\t-k\t--keep-running\n"
322 "\t-V\t--usb-vendor\tVENDOR_ID\n"
323 "\t-P\t--usb-product\tPRODUCT_ID\n"
324 "\t-C\t--usb-config\tCONFIG_ID\n"
325 "\t-I\t--usb-interface\tINTERFACE_ID\n"
326 "\t-S\t--usb-altsetting ALTSETTING_ID\n"
327 "\t-A\t--usb-address\tADDRESS\n"
328 "\n"
329 );
330}
331
332static const struct option opts[] = {
333 { "help", 0, 0, 'h' },
334 { "gsmtap-ip", 1, 0, 'i' },
335 { "keep-running", 0, 0, 'k' },
336 { "usb-vendor", 1, 0, 'V' },
337 { "usb-product", 1, 0, 'P' },
338 { "usb-config", 1, 0, 'C' },
339 { "usb-interface", 1, 0, 'I' },
340 { "usb-altsetting", 1, 0, 'S' },
341 { "usb-address", 1, 0, 'A' },
342 { NULL, 0, 0, 0 }
343};
344
345/* Known USB device with SIMtrace firmware supporting sniffer */
346static const struct dev_id compatible_dev_ids[] = {
347 { USB_VENDOR_OPENMOKO, USB_PRODUCT_SIMTRACE2 },
348 { 0, 0 }
349};
350
351static void signal_handler(int signal)
352{
353 switch (signal) {
354 case SIGINT:
355 exit(0);
356 break;
357 default:
358 break;
359 }
360}
361
362int main(int argc, char **argv)
363{
364 int i, rc, ret;
365 print_welcome();
366
367 /* Parse arguments */
368 char *gsmtap_host = "127.0.0.1";
369 int keep_running = 0;
370 int vendor_id = -1, product_id = -1, addr = -1, config_id = -1, if_num = -1, altsetting = -1;
371
372 while (1) {
373 int option_index = 0;
374
375 char c = getopt_long(argc, argv, "hi:kV:P:C:I:S:A:", opts, &option_index);
376 if (c == -1)
377 break;
378 switch (c) {
379 case 'h':
380 print_help();
381 exit(0);
382 break;
383 case 'i':
384 gsmtap_host = optarg;
385 break;
386 case 'k':
387 keep_running = 1;
388 break;
389 case 'V':
390 vendor_id = strtol(optarg, NULL, 16);
391 break;
392 case 'P':
393 product_id = strtol(optarg, NULL, 16);
394 break;
395 case 'C':
396 config_id = atoi(optarg);
397 break;
398 case 'I':
399 if_num = atoi(optarg);
400 break;
401 case 'S':
402 altsetting = atoi(optarg);
403 break;
404 case 'A':
405 addr = atoi(optarg);
406 break;
407 }
408 }
409
410 /* Scan for available SIMtrace USB devices supporting sniffing */
411 rc = libusb_init(NULL);
412 if (rc < 0) {
413 fprintf(stderr, "libusb initialization failed\n");
414 goto do_exit;
415 }
416 struct usb_interface_match ifm_scan[16];
417 int num_interfaces = usb_match_interfaces(NULL, compatible_dev_ids,
418 USB_CLASS_PROPRIETARY, SIMTRACE_SNIFFER_USB_SUBCLASS, -1, ifm_scan, ARRAY_SIZE(ifm_scan));
419 if (num_interfaces <= 0) {
420 perror("No compatible USB devices found");
421 goto do_exit;
422 }
423
424 /* Only keep USB matching arguments */
425 struct usb_interface_match ifm_filtered[ARRAY_SIZE(ifm_scan)];
426 int num_filtered = 0;
427 for (i = 0; i < num_interfaces; i++) {
428 if (vendor_id>=0 && vendor_id!=ifm_scan[i].vendor) {
429 continue;
430 }
431 if (product_id>=0 && product_id!=ifm_scan[i].product) {
432 continue;
433 }
434 if (config_id>=0 && config_id!=ifm_scan[i].configuration) {
435 continue;
436 }
437 if (if_num>=0 && if_num!=ifm_scan[i].interface) {
438 continue;
439 }
440 if (altsetting>=0 && altsetting!=ifm_scan[i].altsetting) {
441 continue;
442 }
443 if (addr>=0 && addr!=ifm_scan[i].addr) {
444 continue;
445 }
446 ifm_filtered[num_filtered++] = ifm_scan[i];
447 }
448 if (1!=num_filtered) {
449 perror("No individual matching USB devices found");
450 printf("Available USB devices:\n");
451 for (i = 0; i < num_interfaces; i++) {
452 printf("\t%04x:%04x Addr=%u, Path=%s, Cfg=%u, Intf=%u, Alt=%u: %d/%d/%d ",
453 ifm_scan[i].vendor, ifm_scan[i].product, ifm_scan[i].addr, ifm_scan[i].path,
454 ifm_scan[i].configuration, ifm_scan[i].interface, ifm_scan[i].altsetting,
455 ifm_scan[i].class, ifm_scan[i].sub_class, ifm_scan[i].protocol);
456 libusb_device_handle *dev_handle;
457 rc = libusb_open(ifm_scan[i].usb_dev, &dev_handle);
458 if (rc < 0) {
459 printf("\n");
460 perror("Cannot open device");
461 continue;
462 }
463 char strbuf[256];
464 rc = libusb_get_string_descriptor_ascii(dev_handle, ifm_scan[i].string_idx,
465 (unsigned char *)strbuf, sizeof(strbuf));
466 libusb_close(dev_handle);
467 if (rc < 0) {
468 printf("\n");
469 perror("Cannot read string");
470 continue;
471 }
472 printf("(%s)\n", strbuf);
473 }
474 goto do_exit;
475 }
476 struct usb_interface_match ifm_selected = ifm_filtered[0];
477 printf("Using USB device %04x:%04x Addr=%u, Path=%s, Cfg=%u, Intf=%u, Alt=%u: %d/%d/%d ",
478 ifm_selected.vendor, ifm_selected.product, ifm_selected.addr, ifm_selected.path,
479 ifm_selected.configuration, ifm_selected.interface, ifm_selected.altsetting,
480 ifm_selected.class, ifm_selected.sub_class, ifm_selected.protocol);
481 libusb_device_handle *dev_handle;
482 rc = libusb_open(ifm_selected.usb_dev, &dev_handle);
483 if (rc < 0) {
484 printf("\n");
485 perror("Cannot open device");
486 }
487 char strbuf[256];
488 rc = libusb_get_string_descriptor_ascii(dev_handle, ifm_selected.string_idx,
489 (unsigned char *)strbuf, sizeof(strbuf));
490 libusb_close(dev_handle);
491 if (rc < 0) {
492 printf("\n");
493 perror("Cannot read string");
494 }
495 printf("(%s)\n", strbuf);
496
Harald Welte964cda32019-11-24 22:27:10 +0100497 rc = osmo_st2_gsmtap_init(gsmtap_host);
498 if (rc < 0) {
Kévin Redon6e3f1122018-07-01 18:24:42 +0200499 perror("unable to open GSMTAP");
500 goto close_exit;
501 }
Kévin Redon6e3f1122018-07-01 18:24:42 +0200502
503 signal(SIGINT, &signal_handler);
504
505 do {
506 _transp.usb_devh = usb_open_claim_interface(NULL, &ifm_selected);
507 if (!_transp.usb_devh) {
508 fprintf(stderr, "can't open USB device\n");
509 goto close_exit;
510 }
511
512 rc = libusb_claim_interface(_transp.usb_devh, ifm_selected.interface);
513 if (rc < 0) {
514 fprintf(stderr, "can't claim interface %d; rc=%d\n", ifm_selected.interface, rc);
515 goto close_exit;
516 }
517
518 rc = get_usb_ep_addrs(_transp.usb_devh, ifm_selected.interface, &_transp.usb_ep.out,
519 &_transp.usb_ep.in, &_transp.usb_ep.irq_in);
520 if (rc < 0) {
521 fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
522 goto close_exit;
523 }
524
525 run_mainloop();
526 ret = 0;
527
528 if (_transp.usb_devh)
529 libusb_release_interface(_transp.usb_devh, 0);
530close_exit:
531 if (_transp.usb_devh)
532 libusb_close(_transp.usb_devh);
533 if (keep_running)
534 sleep(1);
535 } while (keep_running);
536
537 libusb_exit(NULL);
538do_exit:
539 return ret;
540}