blob: 201ff71860cf5d50ca2acfc8af70eab36a58e02a [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
Harald Welte7f7de1e2019-12-15 20:17:44 +010041#include <osmocom/usb/libusb.h>
Harald Welte964cda32019-11-24 22:27:10 +010042#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"
Eric Wild1fad9222020-01-29 14:44:32 +0100185 "\t-n\t--pcsc-reader-num\n"
Harald Welte964cda32019-11-24 22:27:10 +0100186 "\t-V\t--usb-vendor\tVENDOR_ID\n"
187 "\t-P\t--usb-product\tPRODUCT_ID\n"
188 "\t-C\t--usb-config\tCONFIG_ID\n"
189 "\t-I\t--usb-interface\tINTERFACE_ID\n"
190 "\t-S\t--usb-altsetting ALTSETTING_ID\n"
191 "\t-A\t--usb-address\tADDRESS\n"
192 "\t-H\t--usb-path\tPATH\n"
193 "\n"
194 );
195}
196
197static const struct option opts[] = {
198 { "remote-udp-host", 1, 0, 'r' },
199 { "remote-udp-port", 1, 0, 'p' },
200 { "gsmtap-ip", 1, 0, 'i' },
201 { "skip-atr", 0, 0, 'a' },
202 { "help", 0, 0, 'h' },
203 { "keep-running", 0, 0, 'k' },
Eric Wild1fad9222020-01-29 14:44:32 +0100204 { "pcsc-reader-num", 1, 0, 'n' },
Harald Welte964cda32019-11-24 22:27:10 +0100205 { "usb-vendor", 1, 0, 'V' },
206 { "usb-product", 1, 0, 'P' },
207 { "usb-config", 1, 0, 'C' },
208 { "usb-interface", 1, 0, 'I' },
209 { "usb-altsetting", 1, 0, 'S' },
210 { "usb-address", 1, 0, 'A' },
211 { "usb-path", 1, 0, 'H' },
212 { NULL, 0, 0, 0 }
213};
214
Harald Welte208890a2019-11-24 22:46:51 +0100215static void run_mainloop(struct osmo_st2_cardem_inst *ci)
Harald Welte964cda32019-11-24 22:27:10 +0100216{
Harald Welte208890a2019-11-24 22:46:51 +0100217 struct osmo_st2_transport *transp = ci->slot->transp;
Harald Welte964cda32019-11-24 22:27:10 +0100218 unsigned int msg_count, byte_count = 0;
219 uint8_t buf[16*265];
220 int xfer_len;
221 int rc;
222
223 printf("Entering main loop\n");
224
225 while (1) {
226 /* read data from SIMtrace2 device (local or via USB) */
227 if (transp->udp_fd < 0) {
228 rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
229 buf, sizeof(buf), &xfer_len, 100);
230 if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
231 rc != LIBUSB_ERROR_INTERRUPTED &&
232 rc != LIBUSB_ERROR_IO) {
233 fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
234 return;
235 }
236 } else {
237 rc = read(transp->udp_fd, buf, sizeof(buf));
238 if (rc <= 0) {
239 fprintf(stderr, "shor read from UDP\n");
240 return;
241 }
242 xfer_len = rc;
243 }
244 /* dispatch any incoming data */
245 if (xfer_len > 0) {
246 printf("URB: %s\n", osmo_hexdump(buf, xfer_len));
247 process_usb_msg(ci, buf, xfer_len);
248 msg_count++;
249 byte_count += xfer_len;
250 }
251 }
252}
253
Harald Welte208890a2019-11-24 22:46:51 +0100254static struct osmo_st2_transport _transp;
Harald Welte964cda32019-11-24 22:27:10 +0100255
Harald Welte208890a2019-11-24 22:46:51 +0100256static struct osmo_st2_slot _slot = {
Harald Welte964cda32019-11-24 22:27:10 +0100257 .transp = &_transp,
258 .slot_nr = 0,
259};
260
Harald Welte208890a2019-11-24 22:46:51 +0100261struct osmo_st2_cardem_inst _ci = {
Harald Welte964cda32019-11-24 22:27:10 +0100262 .slot = &_slot,
263};
264
Harald Welte208890a2019-11-24 22:46:51 +0100265struct osmo_st2_cardem_inst *ci = &_ci;
Harald Welte964cda32019-11-24 22:27:10 +0100266
267static void signal_handler(int signal)
268{
269 switch (signal) {
270 case SIGINT:
Harald Welte208890a2019-11-24 22:46:51 +0100271 osmo_st2_cardem_request_card_insert(ci, false);
Harald Welte964cda32019-11-24 22:27:10 +0100272 exit(0);
273 break;
274 default:
275 break;
276 }
277}
278
279int main(int argc, char **argv)
280{
Harald Welte208890a2019-11-24 22:46:51 +0100281 struct osmo_st2_transport *transp = ci->slot->transp;
Harald Welte964cda32019-11-24 22:27:10 +0100282 char *gsmtap_host = "127.0.0.1";
283 int rc;
284 int c, ret = 1;
285 int skip_atr = 0;
286 int keep_running = 0;
287 int remote_udp_port = 52342;
288 int if_num = 0, vendor_id = -1, product_id = -1;
289 int config_id = -1, altsetting = 0, addr = -1;
Eric Wild1fad9222020-01-29 14:44:32 +0100290 int reader_num = 0;
Harald Welte964cda32019-11-24 22:27:10 +0100291 char *remote_udp_host = NULL;
292 char *path = NULL;
293 struct osim_reader_hdl *reader;
294 struct osim_card_hdl *card;
295
296 print_welcome();
297
298 while (1) {
299 int option_index = 0;
300
Eric Wild1fad9222020-01-29 14:44:32 +0100301 c = getopt_long(argc, argv, "r:p:hi:V:P:C:I:S:A:H:akn:", opts, &option_index);
Harald Welte964cda32019-11-24 22:27:10 +0100302 if (c == -1)
303 break;
304 switch (c) {
305 case 'r':
306 remote_udp_host = optarg;
307 break;
308 case 'p':
309 remote_udp_port = atoi(optarg);
310 break;
311 case 'h':
312 print_help();
313 exit(0);
314 break;
315 case 'i':
316 gsmtap_host = optarg;
317 break;
318 case 'a':
319 skip_atr = 1;
320 break;
321 case 'k':
322 keep_running = 1;
323 break;
Eric Wild1fad9222020-01-29 14:44:32 +0100324 case 'n':
325 reader_num = atoi(optarg);
326 break;
Harald Welte964cda32019-11-24 22:27:10 +0100327 case 'V':
328 vendor_id = strtol(optarg, NULL, 16);
329 break;
330 case 'P':
331 product_id = strtol(optarg, NULL, 16);
332 break;
333 case 'C':
334 config_id = atoi(optarg);
335 break;
336 case 'I':
337 if_num = atoi(optarg);
338 break;
339 case 'S':
340 altsetting = atoi(optarg);
341 break;
342 case 'A':
343 addr = atoi(optarg);
344 break;
345 case 'H':
346 path = optarg;
347 break;
348 }
349 }
350
351 if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) {
352 fprintf(stderr, "You have to specify the vendor and product ID\n");
353 goto do_exit;
354 }
355
356 transp->udp_fd = -1;
357
358 ci->card_prof = &osim_uicc_sim_cic_profile;
359
360 if (!remote_udp_host) {
361 rc = libusb_init(NULL);
362 if (rc < 0) {
363 fprintf(stderr, "libusb initialization failed\n");
364 goto do_exit;
365 }
366 } else {
367 transp->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
368 remote_udp_host, remote_udp_port+if_num,
369 OSMO_SOCK_F_CONNECT);
370 if (transp->udp_fd < 0) {
371 fprintf(stderr, "error binding UDP port\n");
372 goto do_exit;
373 }
374 }
375
376 rc = osmo_st2_gsmtap_init(gsmtap_host);
377 if (rc < 0) {
378 perror("unable to open GSMTAP");
379 goto close_exit;
380 }
381
Eric Wild1fad9222020-01-29 14:44:32 +0100382 reader = osim_reader_open(OSIM_READER_DRV_PCSC, reader_num, "", NULL);
Harald Welte964cda32019-11-24 22:27:10 +0100383 if (!reader) {
384 perror("unable to open PC/SC reader");
385 goto close_exit;
386 }
387
388 card = osim_card_open(reader, OSIM_PROTO_T0);
389 if (!card) {
390 perror("unable to open SIM card");
391 goto close_exit;
392 }
393
394 ci->chan = llist_entry(card->channels.next, struct osim_chan_hdl, list);
395 if (!ci->chan) {
396 perror("SIM card has no channel?!?");
397 goto close_exit;
398 }
399
400 signal(SIGINT, &signal_handler);
401
402 do {
403 if (transp->udp_fd < 0) {
404 struct usb_interface_match _ifm, *ifm = &_ifm;
405 ifm->vendor = vendor_id;
406 ifm->product = product_id;
407 ifm->configuration = config_id;
408 ifm->interface = if_num;
409 ifm->altsetting = altsetting;
410 ifm->addr = addr;
411 if (path)
412 osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
Harald Welte7f7de1e2019-12-15 20:17:44 +0100413 transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
Harald Welte964cda32019-11-24 22:27:10 +0100414 if (!transp->usb_devh) {
415 fprintf(stderr, "can't open USB device\n");
416 goto close_exit;
417 }
418
419 rc = libusb_claim_interface(transp->usb_devh, if_num);
420 if (rc < 0) {
421 fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
422 goto close_exit;
423 }
424
Harald Welte7f7de1e2019-12-15 20:17:44 +0100425 rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
Harald Welte964cda32019-11-24 22:27:10 +0100426 &transp->usb_ep.in, &transp->usb_ep.irq_in);
427 if (rc < 0) {
428 fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
429 goto close_exit;
430 }
431 }
432
433 /* simulate card-insert to modem (owhw, not qmod) */
Harald Welte208890a2019-11-24 22:46:51 +0100434 osmo_st2_cardem_request_card_insert(ci, true);
Harald Welte964cda32019-11-24 22:27:10 +0100435
436 /* select remote (forwarded) SIM */
Harald Welte208890a2019-11-24 22:46:51 +0100437 osmo_st2_modem_sim_select_remote(ci->slot);
Harald Welte964cda32019-11-24 22:27:10 +0100438
439 if (!skip_atr) {
440 /* set the ATR */
Kévin Redon24c6fe22019-12-02 19:35:45 +0100441 uint8_t real_atr[] = { 0x3B, 0x00 }; // the simplest ATR
Harald Welte964cda32019-11-24 22:27:10 +0100442 atr_update_csum(real_atr, sizeof(real_atr));
Harald Welte208890a2019-11-24 22:46:51 +0100443 osmo_st2_cardem_request_set_atr(ci, real_atr, sizeof(real_atr));
Harald Welte964cda32019-11-24 22:27:10 +0100444 }
445
446 /* select remote (forwarded) SIM */
Harald Welte208890a2019-11-24 22:46:51 +0100447 osmo_st2_modem_reset_pulse(ci->slot, 300);
Harald Welte964cda32019-11-24 22:27:10 +0100448
449 run_mainloop(ci);
450 ret = 0;
451
452 if (transp->udp_fd < 0)
453 libusb_release_interface(transp->usb_devh, 0);
454close_exit:
455 if (transp->usb_devh)
456 libusb_close(transp->usb_devh);
457 if (keep_running)
458 sleep(1);
459 } while (keep_running);
460
461 if (transp->udp_fd < 0)
462 libusb_exit(NULL);
463do_exit:
464 return ret;
465}