blob: d51f0812bf03b39aab87c80c2123f0a2050c39d9 [file] [log] [blame]
Harald Welte964cda32019-11-24 22:27:10 +01001/* simtrace2-remsim - main program for the host PC to provide a remote SIM
2 * using the SIMtrace 2 firmware in card emulation mode
3 *
4 * (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
5 * (C) 2018, 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
8 * 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.
20 */
21
22#include <errno.h>
23#include <unistd.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdint.h>
28#include <signal.h>
29#include <time.h>
30#define _GNU_SOURCE
31#include <getopt.h>
32
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38
39#include <libusb.h>
40
41#include <osmocom/simtrace2/libusb_util.h>
42#include <osmocom/simtrace2/simtrace2_api.h>
43#include <osmocom/simtrace2/simtrace_prot.h>
44#include <osmocom/simtrace2/apdu_dispatch.h>
45#include <osmocom/simtrace2/gsmtap.h>
46
Harald Welte964cda32019-11-24 22:27:10 +010047#include <osmocom/core/utils.h>
48#include <osmocom/core/socket.h>
49#include <osmocom/core/msgb.h>
50#include <osmocom/sim/class_tables.h>
51#include <osmocom/sim/sim.h>
52
53static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
54{
55 uint8_t csum = 0;
56 int i;
57
58 for (i = 1; i < atr_len - 1; i++)
59 csum = csum ^ atr[i];
60
61 atr[atr_len-1] = csum;
62}
63
64/***********************************************************************
65 * Incoming Messages
66 ***********************************************************************/
67
68/*! \brief Process a STATUS message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +010069static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +010070{
71 struct cardemu_usb_msg_status *status;
72 status = (struct cardemu_usb_msg_status *) buf;
73
74 printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
75 status->flags, status->fi, status->di, status->wi,
76 status->waiting_time);
77
78 return 0;
79}
80
81/*! \brief Process a PTS indication message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +010082static int process_do_pts(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +010083{
84 struct cardemu_usb_msg_pts_info *pts;
85 pts = (struct cardemu_usb_msg_pts_info *) buf;
86
87 printf("=> PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req)));
88
89 return 0;
90}
91
92/*! \brief Process a RX-DATA indication message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +010093static int process_do_rx_da(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +010094{
Harald Welte208890a2019-11-24 22:46:51 +010095 static struct osmo_apdu_context ac;
Harald Welte964cda32019-11-24 22:27:10 +010096 struct cardemu_usb_msg_rx_data *data;
97 int rc;
98
99 data = (struct cardemu_usb_msg_rx_data *) buf;
100
101 printf("=> DATA: flags=%x, %s: ", data->flags,
102 osmo_hexdump(data->data, data->data_len));
103
Harald Welte208890a2019-11-24 22:46:51 +0100104 rc = osmo_apdu_segment_in(&ac, data->data, data->data_len,
105 data->flags & CEMU_DATA_F_TPDU_HDR);
Harald Welte964cda32019-11-24 22:27:10 +0100106
107 if (rc & APDU_ACT_TX_CAPDU_TO_CARD) {
108 struct msgb *tmsg = msgb_alloc(1024, "TPDU");
109 struct osim_reader_hdl *rh = ci->chan->card->reader;
110 uint8_t *cur;
111
112 /* Copy TPDU header */
113 cur = msgb_put(tmsg, sizeof(ac.hdr));
114 memcpy(cur, &ac.hdr, sizeof(ac.hdr));
115 /* Copy D(c), if any */
116 if (ac.lc.tot) {
117 cur = msgb_put(tmsg, ac.lc.tot);
118 memcpy(cur, ac.dc, ac.lc.tot);
119 }
120 /* send to actual card */
121 tmsg->l3h = tmsg->tail;
122 rc = rh->ops->transceive(rh, tmsg);
123 if (rc < 0) {
124 fprintf(stderr, "error during transceive: %d\n", rc);
125 msgb_free(tmsg);
126 return rc;
127 }
128 msgb_apdu_sw(tmsg) = msgb_get_u16(tmsg);
129 ac.sw[0] = msgb_apdu_sw(tmsg) >> 8;
130 ac.sw[1] = msgb_apdu_sw(tmsg) & 0xff;
131 printf("SW=0x%04x, len_rx=%d\n", msgb_apdu_sw(tmsg), msgb_l3len(tmsg));
132 if (msgb_l3len(tmsg))
Harald Welte208890a2019-11-24 22:46:51 +0100133 osmo_st2_cardem_request_pb_and_tx(ci, ac.hdr.ins, tmsg->l3h, msgb_l3len(tmsg));
134 osmo_st2_cardem_request_sw_tx(ci, ac.sw);
Harald Welte964cda32019-11-24 22:27:10 +0100135 } else if (ac.lc.tot > ac.lc.cur) {
Harald Welte208890a2019-11-24 22:46:51 +0100136 osmo_st2_cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur);
Harald Welte964cda32019-11-24 22:27:10 +0100137 }
138 return 0;
139}
140
141/*! \brief Process an incoming message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +0100142static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +0100143{
144 struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
145 int rc;
146
147 printf("-> %s\n", osmo_hexdump(buf, len));
148
149 buf += sizeof(*sh);
150
151 switch (sh->msg_type) {
152 case SIMTRACE_MSGT_BD_CEMU_STATUS:
153 rc = process_do_status(ci, buf, len);
154 break;
155 case SIMTRACE_MSGT_DO_CEMU_PTS:
156 rc = process_do_pts(ci, buf, len);
157 break;
158 case SIMTRACE_MSGT_DO_CEMU_RX_DATA:
159 rc = process_do_rx_da(ci, buf, len);
160 break;
161 default:
162 printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
163 rc = -1;
164 break;
165 }
166
167 return rc;
168}
169
170static void print_welcome(void)
171{
172 printf("simtrace2-remsim - Remote SIM card forwarding\n"
173 "(C) 2010-2017, Harald Welte <laforge@gnumonks.org>\n"
174 "(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n");
175}
176
177static void print_help(void)
178{
179 printf( "\t-r\t--remote-udp-host HOST\n"
180 "\t-p\t--remote-udp-port PORT\n"
181 "\t-h\t--help\n"
182 "\t-i\t--gsmtap-ip\tA.B.C.D\n"
183 "\t-a\t--skip-atr\n"
184 "\t-k\t--keep-running\n"
185 "\t-V\t--usb-vendor\tVENDOR_ID\n"
186 "\t-P\t--usb-product\tPRODUCT_ID\n"
187 "\t-C\t--usb-config\tCONFIG_ID\n"
188 "\t-I\t--usb-interface\tINTERFACE_ID\n"
189 "\t-S\t--usb-altsetting ALTSETTING_ID\n"
190 "\t-A\t--usb-address\tADDRESS\n"
191 "\t-H\t--usb-path\tPATH\n"
192 "\n"
193 );
194}
195
196static const struct option opts[] = {
197 { "remote-udp-host", 1, 0, 'r' },
198 { "remote-udp-port", 1, 0, 'p' },
199 { "gsmtap-ip", 1, 0, 'i' },
200 { "skip-atr", 0, 0, 'a' },
201 { "help", 0, 0, 'h' },
202 { "keep-running", 0, 0, 'k' },
203 { "usb-vendor", 1, 0, 'V' },
204 { "usb-product", 1, 0, 'P' },
205 { "usb-config", 1, 0, 'C' },
206 { "usb-interface", 1, 0, 'I' },
207 { "usb-altsetting", 1, 0, 'S' },
208 { "usb-address", 1, 0, 'A' },
209 { "usb-path", 1, 0, 'H' },
210 { NULL, 0, 0, 0 }
211};
212
Harald Welte208890a2019-11-24 22:46:51 +0100213static void run_mainloop(struct osmo_st2_cardem_inst *ci)
Harald Welte964cda32019-11-24 22:27:10 +0100214{
Harald Welte208890a2019-11-24 22:46:51 +0100215 struct osmo_st2_transport *transp = ci->slot->transp;
Harald Welte964cda32019-11-24 22:27:10 +0100216 unsigned int msg_count, byte_count = 0;
217 uint8_t buf[16*265];
218 int xfer_len;
219 int rc;
220
221 printf("Entering main loop\n");
222
223 while (1) {
224 /* read data from SIMtrace2 device (local or via USB) */
225 if (transp->udp_fd < 0) {
226 rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
227 buf, sizeof(buf), &xfer_len, 100);
228 if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
229 rc != LIBUSB_ERROR_INTERRUPTED &&
230 rc != LIBUSB_ERROR_IO) {
231 fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
232 return;
233 }
234 } else {
235 rc = read(transp->udp_fd, buf, sizeof(buf));
236 if (rc <= 0) {
237 fprintf(stderr, "shor read from UDP\n");
238 return;
239 }
240 xfer_len = rc;
241 }
242 /* dispatch any incoming data */
243 if (xfer_len > 0) {
244 printf("URB: %s\n", osmo_hexdump(buf, xfer_len));
245 process_usb_msg(ci, buf, xfer_len);
246 msg_count++;
247 byte_count += xfer_len;
248 }
249 }
250}
251
Harald Welte208890a2019-11-24 22:46:51 +0100252static struct osmo_st2_transport _transp;
Harald Welte964cda32019-11-24 22:27:10 +0100253
Harald Welte208890a2019-11-24 22:46:51 +0100254static struct osmo_st2_slot _slot = {
Harald Welte964cda32019-11-24 22:27:10 +0100255 .transp = &_transp,
256 .slot_nr = 0,
257};
258
Harald Welte208890a2019-11-24 22:46:51 +0100259struct osmo_st2_cardem_inst _ci = {
Harald Welte964cda32019-11-24 22:27:10 +0100260 .slot = &_slot,
261};
262
Harald Welte208890a2019-11-24 22:46:51 +0100263struct osmo_st2_cardem_inst *ci = &_ci;
Harald Welte964cda32019-11-24 22:27:10 +0100264
265static void signal_handler(int signal)
266{
267 switch (signal) {
268 case SIGINT:
Harald Welte208890a2019-11-24 22:46:51 +0100269 osmo_st2_cardem_request_card_insert(ci, false);
Harald Welte964cda32019-11-24 22:27:10 +0100270 exit(0);
271 break;
272 default:
273 break;
274 }
275}
276
277int main(int argc, char **argv)
278{
Harald Welte208890a2019-11-24 22:46:51 +0100279 struct osmo_st2_transport *transp = ci->slot->transp;
Harald Welte964cda32019-11-24 22:27:10 +0100280 char *gsmtap_host = "127.0.0.1";
281 int rc;
282 int c, ret = 1;
283 int skip_atr = 0;
284 int keep_running = 0;
285 int remote_udp_port = 52342;
286 int if_num = 0, vendor_id = -1, product_id = -1;
287 int config_id = -1, altsetting = 0, addr = -1;
288 char *remote_udp_host = NULL;
289 char *path = NULL;
290 struct osim_reader_hdl *reader;
291 struct osim_card_hdl *card;
292
293 print_welcome();
294
295 while (1) {
296 int option_index = 0;
297
298 c = getopt_long(argc, argv, "r:p:hi:V:P:C:I:S:A:H:ak", opts, &option_index);
299 if (c == -1)
300 break;
301 switch (c) {
302 case 'r':
303 remote_udp_host = optarg;
304 break;
305 case 'p':
306 remote_udp_port = atoi(optarg);
307 break;
308 case 'h':
309 print_help();
310 exit(0);
311 break;
312 case 'i':
313 gsmtap_host = optarg;
314 break;
315 case 'a':
316 skip_atr = 1;
317 break;
318 case 'k':
319 keep_running = 1;
320 break;
321 case 'V':
322 vendor_id = strtol(optarg, NULL, 16);
323 break;
324 case 'P':
325 product_id = strtol(optarg, NULL, 16);
326 break;
327 case 'C':
328 config_id = atoi(optarg);
329 break;
330 case 'I':
331 if_num = atoi(optarg);
332 break;
333 case 'S':
334 altsetting = atoi(optarg);
335 break;
336 case 'A':
337 addr = atoi(optarg);
338 break;
339 case 'H':
340 path = optarg;
341 break;
342 }
343 }
344
345 if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) {
346 fprintf(stderr, "You have to specify the vendor and product ID\n");
347 goto do_exit;
348 }
349
350 transp->udp_fd = -1;
351
352 ci->card_prof = &osim_uicc_sim_cic_profile;
353
354 if (!remote_udp_host) {
355 rc = libusb_init(NULL);
356 if (rc < 0) {
357 fprintf(stderr, "libusb initialization failed\n");
358 goto do_exit;
359 }
360 } else {
361 transp->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
362 remote_udp_host, remote_udp_port+if_num,
363 OSMO_SOCK_F_CONNECT);
364 if (transp->udp_fd < 0) {
365 fprintf(stderr, "error binding UDP port\n");
366 goto do_exit;
367 }
368 }
369
370 rc = osmo_st2_gsmtap_init(gsmtap_host);
371 if (rc < 0) {
372 perror("unable to open GSMTAP");
373 goto close_exit;
374 }
375
376 reader = osim_reader_open(OSIM_READER_DRV_PCSC, 0, "", NULL);
377 if (!reader) {
378 perror("unable to open PC/SC reader");
379 goto close_exit;
380 }
381
382 card = osim_card_open(reader, OSIM_PROTO_T0);
383 if (!card) {
384 perror("unable to open SIM card");
385 goto close_exit;
386 }
387
388 ci->chan = llist_entry(card->channels.next, struct osim_chan_hdl, list);
389 if (!ci->chan) {
390 perror("SIM card has no channel?!?");
391 goto close_exit;
392 }
393
394 signal(SIGINT, &signal_handler);
395
396 do {
397 if (transp->udp_fd < 0) {
398 struct usb_interface_match _ifm, *ifm = &_ifm;
399 ifm->vendor = vendor_id;
400 ifm->product = product_id;
401 ifm->configuration = config_id;
402 ifm->interface = if_num;
403 ifm->altsetting = altsetting;
404 ifm->addr = addr;
405 if (path)
406 osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
407 transp->usb_devh = usb_open_claim_interface(NULL, ifm);
408 if (!transp->usb_devh) {
409 fprintf(stderr, "can't open USB device\n");
410 goto close_exit;
411 }
412
413 rc = libusb_claim_interface(transp->usb_devh, if_num);
414 if (rc < 0) {
415 fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
416 goto close_exit;
417 }
418
419 rc = get_usb_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
420 &transp->usb_ep.in, &transp->usb_ep.irq_in);
421 if (rc < 0) {
422 fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
423 goto close_exit;
424 }
425 }
426
427 /* simulate card-insert to modem (owhw, not qmod) */
Harald Welte208890a2019-11-24 22:46:51 +0100428 osmo_st2_cardem_request_card_insert(ci, true);
Harald Welte964cda32019-11-24 22:27:10 +0100429
430 /* select remote (forwarded) SIM */
Harald Welte208890a2019-11-24 22:46:51 +0100431 osmo_st2_modem_sim_select_remote(ci->slot);
Harald Welte964cda32019-11-24 22:27:10 +0100432
433 if (!skip_atr) {
434 /* set the ATR */
Kévin Redon24c6fe22019-12-02 19:35:45 +0100435 uint8_t real_atr[] = { 0x3B, 0x00 }; // the simplest ATR
Harald Welte964cda32019-11-24 22:27:10 +0100436 atr_update_csum(real_atr, sizeof(real_atr));
Harald Welte208890a2019-11-24 22:46:51 +0100437 osmo_st2_cardem_request_set_atr(ci, real_atr, sizeof(real_atr));
Harald Welte964cda32019-11-24 22:27:10 +0100438 }
439
440 /* select remote (forwarded) SIM */
Harald Welte208890a2019-11-24 22:46:51 +0100441 osmo_st2_modem_reset_pulse(ci->slot, 300);
Harald Welte964cda32019-11-24 22:27:10 +0100442
443 run_mainloop(ci);
444 ret = 0;
445
446 if (transp->udp_fd < 0)
447 libusb_release_interface(transp->usb_devh, 0);
448close_exit:
449 if (transp->usb_devh)
450 libusb_close(transp->usb_devh);
451 if (keep_running)
452 sleep(1);
453 } while (keep_running);
454
455 if (transp->udp_fd < 0)
456 libusb_exit(NULL);
457do_exit:
458 return ret;
459}