blob: ebb3407ff57d0323f18ef67f3a23456a26c9233a [file] [log] [blame]
Harald Welteb1a56e02020-10-27 15:44:54 +01001/* simtrace2-cardem-pcsc - main program for the host PC to provide a remote SIM
Harald Welte964cda32019-11-24 22:27:10 +01002 * using the SIMtrace 2 firmware in card emulation mode
3 *
Harald Welteb1a56e02020-10-27 15:44:54 +01004 * (C) 2016-2020 by Harald Welte <hwelte@hmw-consulting.de>
Harald Welte964cda32019-11-24 22:27:10 +01005 * (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>
Harald Weltecb0772c2021-04-05 20:30:21 +020050#include <osmocom/core/select.h>
Harald Welte964cda32019-11-24 22:27:10 +010051#include <osmocom/sim/class_tables.h>
52#include <osmocom/sim/sim.h>
53
Leonard Hübner1372aca2020-10-27 10:16:41 +010054#define ATR_MAX_LEN 33
55
Harald Weltecb0772c2021-04-05 20:30:21 +020056#define LOGCI(ci, lvl, fmt, args ...) printf(fmt, ## args)
Eric Wild0b1a3b42020-04-03 21:21:27 +020057
58/* reasonable ATR offering all protocols and voltages
59 * smartphones might not care, but other readers do
60 *
61 * TS = 0x3B Direct Convention
62 * T0 = 0x80 Y(1): b1000, K: 0 (historical bytes)
63 * TD(1) = 0x80 Y(i+1) = b1000, Protocol T=0
64 * ----
65 * TD(2) = 0x81 Y(i+1) = b1000, Protocol T=1
66 * ----
67 * TD(3) = 0x1F Y(i+1) = b0001, Protocol T=15
68 * ----
69 * TA(4) = 0xC7 Clock stop: no preference - Class accepted by the card: (3G) A 5V B 3V C 1.8V
70 * ----
71 * Historical bytes
72 * TCK = 0x59 correct checksum
73 */
74#define DEFAULT_ATR_STR "3B8080811FC759"
75
76
Harald Welte964cda32019-11-24 22:27:10 +010077static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
78{
79 uint8_t csum = 0;
80 int i;
81
82 for (i = 1; i < atr_len - 1; i++)
83 csum = csum ^ atr[i];
84
85 atr[atr_len-1] = csum;
86}
87
88/***********************************************************************
89 * Incoming Messages
90 ***********************************************************************/
91
92/*! \brief Process a STATUS message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +010093static int process_do_status(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +010094{
95 struct cardemu_usb_msg_status *status;
96 status = (struct cardemu_usb_msg_status *) buf;
97
98 printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
99 status->flags, status->fi, status->di, status->wi,
100 status->waiting_time);
101
102 return 0;
103}
104
105/*! \brief Process a PTS indication message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +0100106static int process_do_pts(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +0100107{
108 struct cardemu_usb_msg_pts_info *pts;
109 pts = (struct cardemu_usb_msg_pts_info *) buf;
110
111 printf("=> PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req)));
112
113 return 0;
114}
115
116/*! \brief Process a RX-DATA indication message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +0100117static int process_do_rx_da(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +0100118{
Harald Welte208890a2019-11-24 22:46:51 +0100119 static struct osmo_apdu_context ac;
Harald Welte964cda32019-11-24 22:27:10 +0100120 struct cardemu_usb_msg_rx_data *data;
121 int rc;
122
123 data = (struct cardemu_usb_msg_rx_data *) buf;
124
125 printf("=> DATA: flags=%x, %s: ", data->flags,
126 osmo_hexdump(data->data, data->data_len));
127
Harald Welte208890a2019-11-24 22:46:51 +0100128 rc = osmo_apdu_segment_in(&ac, data->data, data->data_len,
129 data->flags & CEMU_DATA_F_TPDU_HDR);
Harald Welte964cda32019-11-24 22:27:10 +0100130
131 if (rc & APDU_ACT_TX_CAPDU_TO_CARD) {
132 struct msgb *tmsg = msgb_alloc(1024, "TPDU");
133 struct osim_reader_hdl *rh = ci->chan->card->reader;
134 uint8_t *cur;
135
136 /* Copy TPDU header */
137 cur = msgb_put(tmsg, sizeof(ac.hdr));
138 memcpy(cur, &ac.hdr, sizeof(ac.hdr));
139 /* Copy D(c), if any */
140 if (ac.lc.tot) {
141 cur = msgb_put(tmsg, ac.lc.tot);
142 memcpy(cur, ac.dc, ac.lc.tot);
143 }
144 /* send to actual card */
145 tmsg->l3h = tmsg->tail;
146 rc = rh->ops->transceive(rh, tmsg);
147 if (rc < 0) {
148 fprintf(stderr, "error during transceive: %d\n", rc);
149 msgb_free(tmsg);
150 return rc;
151 }
152 msgb_apdu_sw(tmsg) = msgb_get_u16(tmsg);
153 ac.sw[0] = msgb_apdu_sw(tmsg) >> 8;
154 ac.sw[1] = msgb_apdu_sw(tmsg) & 0xff;
155 printf("SW=0x%04x, len_rx=%d\n", msgb_apdu_sw(tmsg), msgb_l3len(tmsg));
156 if (msgb_l3len(tmsg))
Harald Welte208890a2019-11-24 22:46:51 +0100157 osmo_st2_cardem_request_pb_and_tx(ci, ac.hdr.ins, tmsg->l3h, msgb_l3len(tmsg));
158 osmo_st2_cardem_request_sw_tx(ci, ac.sw);
Harald Welte964cda32019-11-24 22:27:10 +0100159 } else if (ac.lc.tot > ac.lc.cur) {
Harald Welte208890a2019-11-24 22:46:51 +0100160 osmo_st2_cardem_request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur);
Harald Welte964cda32019-11-24 22:27:10 +0100161 }
162 return 0;
163}
164
165/*! \brief Process an incoming message from the SIMtrace2 */
Harald Welte208890a2019-11-24 22:46:51 +0100166static int process_usb_msg(struct osmo_st2_cardem_inst *ci, uint8_t *buf, int len)
Harald Welte964cda32019-11-24 22:27:10 +0100167{
168 struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
169 int rc;
170
171 printf("-> %s\n", osmo_hexdump(buf, len));
172
173 buf += sizeof(*sh);
174
175 switch (sh->msg_type) {
176 case SIMTRACE_MSGT_BD_CEMU_STATUS:
177 rc = process_do_status(ci, buf, len);
178 break;
179 case SIMTRACE_MSGT_DO_CEMU_PTS:
180 rc = process_do_pts(ci, buf, len);
181 break;
182 case SIMTRACE_MSGT_DO_CEMU_RX_DATA:
183 rc = process_do_rx_da(ci, buf, len);
184 break;
Harald Weltecb0772c2021-04-05 20:30:21 +0200185 case SIMTRACE_MSGT_BD_CEMU_CONFIG:
186 /* firmware confirms configuration change; ignore */
187 break;
Harald Welte964cda32019-11-24 22:27:10 +0100188 default:
189 printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
190 rc = -1;
191 break;
192 }
193
194 return rc;
195}
196
Harald Weltecb0772c2021-04-05 20:30:21 +0200197/*! \brief Process a STATUS message on IRQ endpoint from the SIMtrace2 */
198static int process_irq_status(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, int len)
199{
200 const struct cardemu_usb_msg_status *status = (struct cardemu_usb_msg_status *) buf;
201
202 LOGCI(ci, LOGL_INFO, "SIMtrace IRQ STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
203 status->flags, status->F_index, status->D_index, status->wi,
204 status->waiting_time);
205
206 return 0;
207}
208
209static int process_usb_msg_irq(struct osmo_st2_cardem_inst *ci, const uint8_t *buf, unsigned int len)
210{
211 struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *)buf;
212 int rc;
213
214 LOGCI(ci, LOGL_INFO, "SIMtrace IRQ %s\n", osmo_hexdump(buf, len));
215
216 buf += sizeof(*sh);
217
218 switch (sh->msg_type) {
219 case SIMTRACE_MSGT_BD_CEMU_STATUS:
220 rc = process_irq_status(ci, buf, len);
221 break;
222 default:
223 LOGCI(ci, LOGL_ERROR, "unknown simtrace msg type 0x%02x\n", sh->msg_type);
224 rc = -1;
225 break;
226 }
227
228 return rc;
229}
230
231static void usb_in_xfer_cb(struct libusb_transfer *xfer)
232{
233 struct osmo_st2_cardem_inst *ci = xfer->user_data;
234 int rc;
235
236 switch (xfer->status) {
237 case LIBUSB_TRANSFER_COMPLETED:
238 /* hand the message up the stack */
239 process_usb_msg(ci, xfer->buffer, xfer->actual_length);
240 break;
241 case LIBUSB_TRANSFER_NO_DEVICE:
242 LOGCI(ci, LOGL_FATAL, "USB device disappeared\n");
243 exit(1);
244 break;
245 default:
246 LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status);
247 exit(1);
248 break;
249 }
250
251 /* re-submit the IN transfer */
252 rc = libusb_submit_transfer(xfer);
253 OSMO_ASSERT(rc == 0);
254}
255
256
257static void allocate_and_submit_in(struct osmo_st2_cardem_inst *ci)
258{
259 struct osmo_st2_transport *transp = ci->slot->transp;
260 struct libusb_transfer *xfer;
261 int rc;
262
263 xfer = libusb_alloc_transfer(0);
264 OSMO_ASSERT(xfer);
265 xfer->dev_handle = transp->usb_devh;
266 xfer->flags = 0;
267 xfer->type = LIBUSB_TRANSFER_TYPE_BULK;
268 xfer->endpoint = transp->usb_ep.in;
269 xfer->timeout = 0;
270 xfer->user_data = ci;
271 xfer->length = 16*256;
272
273 xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
274 OSMO_ASSERT(xfer->buffer);
275 xfer->callback = usb_in_xfer_cb;
276
277 /* submit the IN transfer */
278 rc = libusb_submit_transfer(xfer);
279 OSMO_ASSERT(rc == 0);
280}
281
282
283static void usb_irq_xfer_cb(struct libusb_transfer *xfer)
284{
285 struct osmo_st2_cardem_inst *ci = xfer->user_data;
286 int rc;
287
288 switch (xfer->status) {
289 case LIBUSB_TRANSFER_COMPLETED:
290 process_usb_msg_irq(ci, xfer->buffer, xfer->actual_length);
291 break;
292 case LIBUSB_TRANSFER_NO_DEVICE:
293 LOGCI(ci, LOGL_FATAL, "USB device disappeared\n");
294 exit(1);
295 break;
296 default:
297 LOGCI(ci, LOGL_FATAL, "USB IN transfer failed, status=%u\n", xfer->status);
298 exit(1);
299 break;
300 }
301
302 /* re-submit the IN transfer */
303 rc = libusb_submit_transfer(xfer);
304 OSMO_ASSERT(rc == 0);
305}
306
307
308static void allocate_and_submit_irq(struct osmo_st2_cardem_inst *ci)
309{
310 struct osmo_st2_transport *transp = ci->slot->transp;
311 struct libusb_transfer *xfer;
312 int rc;
313
314 xfer = libusb_alloc_transfer(0);
315 OSMO_ASSERT(xfer);
316 xfer->dev_handle = transp->usb_devh;
317 xfer->flags = 0;
318 xfer->type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
319 xfer->endpoint = transp->usb_ep.irq_in;
320 xfer->timeout = 0;
321 xfer->user_data = ci;
322 xfer->length = 64;
323
324 xfer->buffer = libusb_dev_mem_alloc(xfer->dev_handle, xfer->length);
325 OSMO_ASSERT(xfer->buffer);
326 xfer->callback = usb_irq_xfer_cb;
327
328 /* submit the IN transfer */
329 rc = libusb_submit_transfer(xfer);
330 OSMO_ASSERT(rc == 0);
331}
332
333
334
Harald Welte964cda32019-11-24 22:27:10 +0100335static void print_welcome(void)
336{
Harald Welteb1a56e02020-10-27 15:44:54 +0100337 printf("simtrace2-cardem-pcsc - Using PC/SC reader as SIM\n"
338 "(C) 2010-2020, Harald Welte <laforge@gnumonks.org>\n"
Harald Welte964cda32019-11-24 22:27:10 +0100339 "(C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>\n\n");
340}
341
342static void print_help(void)
343{
Harald Welte80b88772020-10-27 15:40:39 +0100344 printf( "\t-h\t--help\n"
Harald Welte964cda32019-11-24 22:27:10 +0100345 "\t-i\t--gsmtap-ip\tA.B.C.D\n"
346 "\t-a\t--skip-atr\n"
Leonard Hübner1372aca2020-10-27 10:16:41 +0100347 "\t-t\t--set-atr\tATR-STRING in HEX\n"
Harald Welte964cda32019-11-24 22:27:10 +0100348 "\t-k\t--keep-running\n"
Eric Wild1fad9222020-01-29 14:44:32 +0100349 "\t-n\t--pcsc-reader-num\n"
Harald Welte964cda32019-11-24 22:27:10 +0100350 "\t-V\t--usb-vendor\tVENDOR_ID\n"
351 "\t-P\t--usb-product\tPRODUCT_ID\n"
352 "\t-C\t--usb-config\tCONFIG_ID\n"
353 "\t-I\t--usb-interface\tINTERFACE_ID\n"
354 "\t-S\t--usb-altsetting ALTSETTING_ID\n"
355 "\t-A\t--usb-address\tADDRESS\n"
356 "\t-H\t--usb-path\tPATH\n"
357 "\n"
358 );
359}
360
361static const struct option opts[] = {
Harald Welte964cda32019-11-24 22:27:10 +0100362 { "gsmtap-ip", 1, 0, 'i' },
363 { "skip-atr", 0, 0, 'a' },
Leonard Hübner1372aca2020-10-27 10:16:41 +0100364 { "set-atr", 1, 0, 't' },
Harald Welte964cda32019-11-24 22:27:10 +0100365 { "help", 0, 0, 'h' },
366 { "keep-running", 0, 0, 'k' },
Eric Wild1fad9222020-01-29 14:44:32 +0100367 { "pcsc-reader-num", 1, 0, 'n' },
Harald Welte964cda32019-11-24 22:27:10 +0100368 { "usb-vendor", 1, 0, 'V' },
369 { "usb-product", 1, 0, 'P' },
370 { "usb-config", 1, 0, 'C' },
371 { "usb-interface", 1, 0, 'I' },
372 { "usb-altsetting", 1, 0, 'S' },
373 { "usb-address", 1, 0, 'A' },
374 { "usb-path", 1, 0, 'H' },
375 { NULL, 0, 0, 0 }
376};
377
Harald Welte208890a2019-11-24 22:46:51 +0100378static void run_mainloop(struct osmo_st2_cardem_inst *ci)
Harald Welte964cda32019-11-24 22:27:10 +0100379{
Harald Welte964cda32019-11-24 22:27:10 +0100380 printf("Entering main loop\n");
Harald Welte964cda32019-11-24 22:27:10 +0100381 while (1) {
Harald Weltecb0772c2021-04-05 20:30:21 +0200382 osmo_select_main(0);
Harald Welte964cda32019-11-24 22:27:10 +0100383 }
384}
385
Harald Welte208890a2019-11-24 22:46:51 +0100386static struct osmo_st2_transport _transp;
Harald Welte964cda32019-11-24 22:27:10 +0100387
Harald Welte208890a2019-11-24 22:46:51 +0100388static struct osmo_st2_slot _slot = {
Harald Welte964cda32019-11-24 22:27:10 +0100389 .transp = &_transp,
390 .slot_nr = 0,
391};
392
Harald Welte208890a2019-11-24 22:46:51 +0100393struct osmo_st2_cardem_inst _ci = {
Harald Welte964cda32019-11-24 22:27:10 +0100394 .slot = &_slot,
395};
396
Harald Welte208890a2019-11-24 22:46:51 +0100397struct osmo_st2_cardem_inst *ci = &_ci;
Harald Welte964cda32019-11-24 22:27:10 +0100398
399static void signal_handler(int signal)
400{
401 switch (signal) {
402 case SIGINT:
Harald Welte208890a2019-11-24 22:46:51 +0100403 osmo_st2_cardem_request_card_insert(ci, false);
Harald Welte964cda32019-11-24 22:27:10 +0100404 exit(0);
405 break;
406 default:
407 break;
408 }
409}
410
411int main(int argc, char **argv)
412{
Harald Welte208890a2019-11-24 22:46:51 +0100413 struct osmo_st2_transport *transp = ci->slot->transp;
Harald Welte964cda32019-11-24 22:27:10 +0100414 char *gsmtap_host = "127.0.0.1";
415 int rc;
416 int c, ret = 1;
417 int skip_atr = 0;
Eric Wild0b1a3b42020-04-03 21:21:27 +0200418 char *atr = DEFAULT_ATR_STR;
Leonard Hübner1372aca2020-10-27 10:16:41 +0100419 uint8_t real_atr[ATR_MAX_LEN];
420 int atr_len;
Harald Welte964cda32019-11-24 22:27:10 +0100421 int keep_running = 0;
Harald Welte964cda32019-11-24 22:27:10 +0100422 int if_num = 0, vendor_id = -1, product_id = -1;
423 int config_id = -1, altsetting = 0, addr = -1;
Eric Wild1fad9222020-01-29 14:44:32 +0100424 int reader_num = 0;
Harald Welte964cda32019-11-24 22:27:10 +0100425 char *path = NULL;
426 struct osim_reader_hdl *reader;
427 struct osim_card_hdl *card;
428
429 print_welcome();
430
Harald Weltecb0772c2021-04-05 20:30:21 +0200431 rc = osmo_libusb_init(NULL);
432 if (rc < 0) {
433 fprintf(stderr, "libusb initialization failed\n");
434 return rc;
435 }
436
Harald Welte964cda32019-11-24 22:27:10 +0100437 while (1) {
438 int option_index = 0;
439
Harald Welte80b88772020-10-27 15:40:39 +0100440 c = getopt_long(argc, argv, "hi:V:P:C:I:S:A:H:akn:t:", opts, &option_index);
Harald Welte964cda32019-11-24 22:27:10 +0100441 if (c == -1)
442 break;
443 switch (c) {
Harald Welte964cda32019-11-24 22:27:10 +0100444 case 'h':
445 print_help();
446 exit(0);
447 break;
448 case 'i':
449 gsmtap_host = optarg;
450 break;
451 case 'a':
452 skip_atr = 1;
453 break;
Leonard Hübner1372aca2020-10-27 10:16:41 +0100454 case 't':
455 atr = optarg;
456 break;
Harald Welte964cda32019-11-24 22:27:10 +0100457 case 'k':
458 keep_running = 1;
459 break;
Eric Wild1fad9222020-01-29 14:44:32 +0100460 case 'n':
461 reader_num = atoi(optarg);
462 break;
Harald Welte964cda32019-11-24 22:27:10 +0100463 case 'V':
464 vendor_id = strtol(optarg, NULL, 16);
465 break;
466 case 'P':
467 product_id = strtol(optarg, NULL, 16);
468 break;
469 case 'C':
470 config_id = atoi(optarg);
471 break;
472 case 'I':
473 if_num = atoi(optarg);
474 break;
475 case 'S':
476 altsetting = atoi(optarg);
477 break;
478 case 'A':
479 addr = atoi(optarg);
480 break;
481 case 'H':
482 path = optarg;
483 break;
484 }
485 }
486
Leonard Hübner1372aca2020-10-27 10:16:41 +0100487 atr_len = osmo_hexparse(atr,real_atr,ATR_MAX_LEN);
488 if (atr_len < 2) {
489 fprintf(stderr, "Invalid ATR - please omit a leading 0x and only use valid hex "
490 "digits and whitespace. ATRs need to be between 2 and 33 bytes long.\n");
491 goto do_exit;
492 }
493
Harald Welte80b88772020-10-27 15:40:39 +0100494 if (vendor_id < 0 || product_id < 0) {
Harald Welte964cda32019-11-24 22:27:10 +0100495 fprintf(stderr, "You have to specify the vendor and product ID\n");
496 goto do_exit;
497 }
498
Harald Welte964cda32019-11-24 22:27:10 +0100499 ci->card_prof = &osim_uicc_sim_cic_profile;
500
Harald Welte80b88772020-10-27 15:40:39 +0100501 rc = libusb_init(NULL);
502 if (rc < 0) {
503 fprintf(stderr, "libusb initialization failed\n");
504 goto do_exit;
Harald Welte964cda32019-11-24 22:27:10 +0100505 }
506
507 rc = osmo_st2_gsmtap_init(gsmtap_host);
508 if (rc < 0) {
509 perror("unable to open GSMTAP");
510 goto close_exit;
511 }
512
Eric Wild1fad9222020-01-29 14:44:32 +0100513 reader = osim_reader_open(OSIM_READER_DRV_PCSC, reader_num, "", NULL);
Harald Welte964cda32019-11-24 22:27:10 +0100514 if (!reader) {
515 perror("unable to open PC/SC reader");
516 goto close_exit;
517 }
518
519 card = osim_card_open(reader, OSIM_PROTO_T0);
520 if (!card) {
521 perror("unable to open SIM card");
522 goto close_exit;
523 }
524
525 ci->chan = llist_entry(card->channels.next, struct osim_chan_hdl, list);
526 if (!ci->chan) {
527 perror("SIM card has no channel?!?");
528 goto close_exit;
529 }
530
531 signal(SIGINT, &signal_handler);
532
533 do {
Harald Welte80b88772020-10-27 15:40:39 +0100534 struct usb_interface_match _ifm, *ifm = &_ifm;
535 ifm->vendor = vendor_id;
536 ifm->product = product_id;
537 ifm->configuration = config_id;
538 ifm->interface = if_num;
539 ifm->altsetting = altsetting;
540 ifm->addr = addr;
541 if (path)
542 osmo_strlcpy(ifm->path, path, sizeof(ifm->path));
Harald Weltecb0772c2021-04-05 20:30:21 +0200543 transp->udp_fd = -1;
544 transp->usb_async = true;
Harald Welte80b88772020-10-27 15:40:39 +0100545 transp->usb_devh = osmo_libusb_open_claim_interface(NULL, NULL, ifm);
546 if (!transp->usb_devh) {
547 fprintf(stderr, "can't open USB device\n");
548 goto close_exit;
549 }
Harald Welte964cda32019-11-24 22:27:10 +0100550
Harald Welte80b88772020-10-27 15:40:39 +0100551 rc = libusb_claim_interface(transp->usb_devh, if_num);
552 if (rc < 0) {
553 fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
554 goto close_exit;
555 }
Harald Welte964cda32019-11-24 22:27:10 +0100556
Harald Welte80b88772020-10-27 15:40:39 +0100557 rc = osmo_libusb_get_ep_addrs(transp->usb_devh, if_num, &transp->usb_ep.out,
558 &transp->usb_ep.in, &transp->usb_ep.irq_in);
559 if (rc < 0) {
560 fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
561 goto close_exit;
Harald Welte964cda32019-11-24 22:27:10 +0100562 }
563
Harald Weltecb0772c2021-04-05 20:30:21 +0200564 allocate_and_submit_irq(ci);
565 for (int i = 0; i < 4; i++)
566 allocate_and_submit_in(ci);
567
568 /* request firmware to generate STATUS on IRQ endpoint */
569 osmo_st2_cardem_request_config(ci, CEMU_FEAT_F_STATUS_IRQ);
570
Harald Welte964cda32019-11-24 22:27:10 +0100571 /* simulate card-insert to modem (owhw, not qmod) */
Harald Welte208890a2019-11-24 22:46:51 +0100572 osmo_st2_cardem_request_card_insert(ci, true);
Harald Welte964cda32019-11-24 22:27:10 +0100573
574 /* select remote (forwarded) SIM */
Harald Welte208890a2019-11-24 22:46:51 +0100575 osmo_st2_modem_sim_select_remote(ci->slot);
Harald Welte964cda32019-11-24 22:27:10 +0100576
577 if (!skip_atr) {
578 /* set the ATR */
Leonard Hübner1372aca2020-10-27 10:16:41 +0100579 atr_update_csum(real_atr, atr_len);
580 osmo_st2_cardem_request_set_atr(ci, real_atr, atr_len);
Harald Welte964cda32019-11-24 22:27:10 +0100581 }
582
583 /* select remote (forwarded) SIM */
Harald Welte208890a2019-11-24 22:46:51 +0100584 osmo_st2_modem_reset_pulse(ci->slot, 300);
Harald Welte964cda32019-11-24 22:27:10 +0100585
586 run_mainloop(ci);
587 ret = 0;
588
Harald Welte80b88772020-10-27 15:40:39 +0100589 libusb_release_interface(transp->usb_devh, 0);
Harald Welte964cda32019-11-24 22:27:10 +0100590close_exit:
591 if (transp->usb_devh)
592 libusb_close(transp->usb_devh);
593 if (keep_running)
594 sleep(1);
595 } while (keep_running);
596
Harald Welte80b88772020-10-27 15:40:39 +0100597 libusb_exit(NULL);
Harald Welte964cda32019-11-24 22:27:10 +0100598do_exit:
599 return ret;
600}