blob: 6b35e8354227ea077bf5d5fad37397e2efd21f9e [file] [log] [blame]
Harald Welte095ac6c2016-03-19 13:39:33 +01001/* simtrace2-remsim - main program for the host PC
2 *
Harald Welte2ba03bb2017-03-06 18:51:39 +01003 * (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
Harald Welte095ac6c2016-03-19 13:39:33 +01004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include <errno.h>
20#include <unistd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdint.h>
Harald Welte1871c252016-03-20 15:30:46 +010025#include <signal.h>
Harald Welte095ac6c2016-03-19 13:39:33 +010026#include <time.h>
27#define _GNU_SOURCE
28#include <getopt.h>
29
30#include <sys/time.h>
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34#include <arpa/inet.h>
35
36#include <libusb.h>
37
Harald Welte822d66e2017-03-06 20:58:03 +010038#include "libusb_util.h"
Harald Welte095ac6c2016-03-19 13:39:33 +010039#include "simtrace.h"
40#include "cardemu_prot.h"
41#include "apdu_dispatch.h"
Harald Welte236caf62016-03-19 21:28:09 +010042#include "simtrace2-discovery.h"
Harald Welte095ac6c2016-03-19 13:39:33 +010043
44#include <osmocom/core/gsmtap.h>
45#include <osmocom/core/gsmtap_util.h>
46#include <osmocom/core/utils.h>
47#include <osmocom/core/socket.h>
48#include <osmocom/sim/class_tables.h>
49#include <osmocom/sim/sim.h>
50
51static struct gsmtap_inst *g_gti;
Harald Welte2ba03bb2017-03-06 18:51:39 +010052
53struct cardem_inst {
54 struct libusb_device_handle *usb_devh;
55 struct {
56 uint8_t in;
57 uint8_t out;
58 uint8_t irq_in;
59 } usb_ep;
60 const struct osim_cla_ins_card_profile *card_prof;
61
62 int udp_fd;
63 struct osim_chan_hdl *chan;
64};
Harald Welte095ac6c2016-03-19 13:39:33 +010065
66static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len)
67{
68 struct gsmtap_hdr *gh;
69 unsigned int gross_len = len + sizeof(*gh);
70 uint8_t *buf = malloc(gross_len);
71 int rc;
72
73 if (!buf)
74 return -ENOMEM;
75
76 memset(buf, 0, sizeof(*gh));
77 gh = (struct gsmtap_hdr *) buf;
78 gh->version = GSMTAP_VERSION;
79 gh->hdr_len = sizeof(*gh)/4;
80 gh->type = GSMTAP_TYPE_SIM;
81
82 memcpy(buf + sizeof(*gh), apdu, len);
83
84 rc = write(gsmtap_inst_fd(g_gti), buf, gross_len);
85 if (rc < 0) {
86 perror("write gsmtap");
87 free(buf);
88 return rc;
89 }
90
91 free(buf);
92 return 0;
93}
94
95#if 0
96static void apdu_out_cb(uint8_t *buf, unsigned int len, void *user_data)
97{
98 printf("APDU: %s\n", osmo_hexdump(buf, len));
99 gsmtap_send_sim(buf, len);
100}
101#endif
102
103/*! \brief Transmit a given command to the SIMtrace2 device */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100104static int tx_to_dev(struct cardem_inst *ci, uint8_t *buf, unsigned int len)
Harald Welte095ac6c2016-03-19 13:39:33 +0100105{
106 struct cardemu_usb_msg_hdr *mh = (struct cardemu_usb_msg_hdr *) buf;
107 int xfer_len;
108
109 mh->msg_len = len;
110
111 printf("<- %s\n", osmo_hexdump(buf, len));
112
Harald Welte2ba03bb2017-03-06 18:51:39 +0100113 if (ci->udp_fd < 0) {
114 return libusb_bulk_transfer(ci->usb_devh, ci->usb_ep.out, buf, len,
Harald Welte095ac6c2016-03-19 13:39:33 +0100115 &xfer_len, 100000);
116 } else {
Harald Welte2ba03bb2017-03-06 18:51:39 +0100117 return write(ci->udp_fd, buf, len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100118 }
119}
120
121/*! \brief Request the SIMtrace2 to generate a card-insert signal */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100122static int request_card_insert(struct cardem_inst *ci, bool inserted)
Harald Welte095ac6c2016-03-19 13:39:33 +0100123{
124 struct cardemu_usb_msg_cardinsert cins;
125
126 memset(&cins, 0, sizeof(cins));
127 cins.hdr.msg_type = CEMU_USB_MSGT_DT_CARDINSERT;
128 if (inserted)
129 cins.card_insert = 1;
130
Harald Welte2ba03bb2017-03-06 18:51:39 +0100131 return tx_to_dev(ci, (uint8_t *)&cins, sizeof(cins));
Harald Welte095ac6c2016-03-19 13:39:33 +0100132}
133
134/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Rx */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100135static int request_pb_and_rx(struct cardem_inst *ci, uint8_t pb, uint8_t le)
Harald Welte095ac6c2016-03-19 13:39:33 +0100136{
137 struct cardemu_usb_msg_tx_data *txd;
138 uint8_t buf[sizeof(*txd) + 1];
139 txd = (struct cardemu_usb_msg_tx_data *) buf;
140
141 printf("<= request_pb_and_rx(%02x, %d)\n", pb, le);
142
143 memset(txd, 0, sizeof(*txd));
144 txd->data_len = 1;
145 txd->hdr.msg_type = CEMU_USB_MSGT_DT_TX_DATA;
146 txd->flags = CEMU_DATA_F_PB_AND_RX;
147 txd->data[0] = pb;
148
Harald Welte2ba03bb2017-03-06 18:51:39 +0100149 return tx_to_dev(ci, (uint8_t *)txd, sizeof(*txd)+txd->data_len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100150}
151
152/*! \brief Request the SIMtrace2 to transmit a Procedure Byte, then Tx */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100153static int request_pb_and_tx(struct cardem_inst *ci, uint8_t pb, const uint8_t *data, uint8_t data_len_in)
Harald Welte095ac6c2016-03-19 13:39:33 +0100154{
Harald Welte095ac6c2016-03-19 13:39:33 +0100155 struct cardemu_usb_msg_tx_data *txd;
156 uint8_t buf[sizeof(*txd) + 1 + data_len_in];
157 txd = (struct cardemu_usb_msg_tx_data *) buf;
158
159 printf("<= request_pb_and_tx(%02x, %s, %d)\n", pb, osmo_hexdump(data, data_len_in), data_len_in);
160
161 memset(txd, 0, sizeof(*txd));
162 txd->hdr.msg_type = CEMU_USB_MSGT_DT_TX_DATA;
163 txd->data_len = 1 + data_len_in;
164 txd->flags = CEMU_DATA_F_PB_AND_TX;
165 txd->data[0] = pb;
166 memcpy(txd->data+1, data, data_len_in);
167
Harald Welte2ba03bb2017-03-06 18:51:39 +0100168 return tx_to_dev(ci, buf, sizeof(*txd)+txd->data_len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100169}
170
171/*! \brief Request the SIMtrace2 to send a Status Word */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100172static int request_sw_tx(struct cardem_inst *ci, const uint8_t *sw)
Harald Welte095ac6c2016-03-19 13:39:33 +0100173{
174 struct cardemu_usb_msg_tx_data *txd;
175 uint8_t buf[sizeof(*txd) + 2];
176 txd = (struct cardemu_usb_msg_tx_data *) buf;
177
178 printf("<= request_sw_tx(%02x %02x)\n", sw[0], sw[1]);
179
180 memset(txd, 0, sizeof(*txd));
181 txd->hdr.msg_type = CEMU_USB_MSGT_DT_TX_DATA;
182 txd->data_len = 2;
183 txd->flags = CEMU_DATA_F_PB_AND_TX | CEMU_DATA_F_FINAL;
184 txd->data[0] = sw[0];
185 txd->data[1] = sw[1];
186
Harald Welte2ba03bb2017-03-06 18:51:39 +0100187 return tx_to_dev(ci, (uint8_t *)txd, sizeof(*txd)+txd->data_len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100188}
189
Harald Welte9daaa792016-03-20 15:01:20 +0100190static void atr_update_csum(uint8_t *atr, unsigned int atr_len)
191{
192 uint8_t csum = 0;
193 int i;
194
195 for (i = 1; i < atr_len - 1; i++)
196 csum = csum ^ atr[i];
197
198 atr[atr_len-1] = csum;
199}
200
Harald Welte2ba03bb2017-03-06 18:51:39 +0100201static int request_set_atr(struct cardem_inst *ci, const uint8_t *atr, unsigned int atr_len)
Harald Welte9daaa792016-03-20 15:01:20 +0100202{
203 struct cardemu_usb_msg_set_atr *satr;
204 uint8_t buf[sizeof(*satr) + atr_len];
205 satr = (struct cardemu_usb_msg_set_atr *) buf;
206
207 printf("<= request_set_atr(%s)\n", osmo_hexdump(atr, atr_len));
208
209 memset(satr, 0, sizeof(*satr));
210 satr->hdr.msg_type = CEMU_USB_MSGT_DT_SET_ATR;
211 satr->atr_len = atr_len;
212 memcpy(satr->atr, atr, atr_len);
213
Harald Welte2ba03bb2017-03-06 18:51:39 +0100214 return tx_to_dev(ci, (uint8_t *)satr, sizeof(buf));
Harald Welte9daaa792016-03-20 15:01:20 +0100215}
216
Harald Welte095ac6c2016-03-19 13:39:33 +0100217/*! \brief Process a STATUS message from the SIMtrace2 */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100218static int process_do_status(struct cardem_inst *ci, uint8_t *buf, int len)
Harald Welte095ac6c2016-03-19 13:39:33 +0100219{
220 struct cardemu_usb_msg_status *status;
221 status = (struct cardemu_usb_msg_status *) buf;
222
223 printf("=> STATUS: flags=0x%x, fi=%u, di=%u, wi=%u wtime=%u\n",
224 status->flags, status->fi, status->di, status->wi,
225 status->waiting_time);
226
227 return 0;
228}
229
230/*! \brief Process a PTS indication message from the SIMtrace2 */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100231static int process_do_pts(struct cardem_inst *ci, uint8_t *buf, int len)
Harald Welte095ac6c2016-03-19 13:39:33 +0100232{
233 struct cardemu_usb_msg_pts_info *pts;
234 pts = (struct cardemu_usb_msg_pts_info *) buf;
235
236 printf("=> PTS req: %s\n", osmo_hexdump(pts->req, sizeof(pts->req)));
237
238 return 0;
239}
240
241/*! \brief Process a ERROR indication message from the SIMtrace2 */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100242static int process_do_error(struct cardem_inst *ci, uint8_t *buf, int len)
Harald Welte095ac6c2016-03-19 13:39:33 +0100243{
244 struct cardemu_usb_msg_error *err;
245 err = (struct cardemu_usb_msg_error *) buf;
246
247 printf("=> ERROR: %u/%u/%u: %s\n",
248 err->severity, err->subsystem, err->code,
Harald Welteb170ea92017-03-06 18:59:41 +0100249 err->msg_len ? (char *)err->msg : "");
Harald Welte095ac6c2016-03-19 13:39:33 +0100250
251 return 0;
252}
253
254/*! \brief Process a RX-DATA indication message from the SIMtrace2 */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100255static int process_do_rx_da(struct cardem_inst *ci, uint8_t *buf, int len)
Harald Welte095ac6c2016-03-19 13:39:33 +0100256{
257 static struct apdu_context ac;
258 struct cardemu_usb_msg_rx_data *data;
Harald Welte095ac6c2016-03-19 13:39:33 +0100259 int rc;
260
261 data = (struct cardemu_usb_msg_rx_data *) buf;
262
263 printf("=> DATA: flags=%x, %s: ", data->flags,
264 osmo_hexdump(data->data, data->data_len));
265
266 rc = apdu_segment_in(&ac, data->data, data->data_len,
267 data->flags & CEMU_DATA_F_TPDU_HDR);
268
269 if (rc & APDU_ACT_TX_CAPDU_TO_CARD) {
270 struct msgb *tmsg = msgb_alloc(1024, "TPDU");
Harald Welte2ba03bb2017-03-06 18:51:39 +0100271 struct osim_reader_hdl *rh = ci->chan->card->reader;
Harald Welte095ac6c2016-03-19 13:39:33 +0100272 uint8_t *cur;
273
274 /* Copy TPDU header */
275 cur = msgb_put(tmsg, sizeof(ac.hdr));
276 memcpy(cur, &ac.hdr, sizeof(ac.hdr));
277 /* Copy D(c), if any */
278 if (ac.lc.tot) {
279 cur = msgb_put(tmsg, ac.lc.tot);
280 memcpy(cur, ac.dc, ac.lc.tot);
281 }
282 /* send to actual card */
283 tmsg->l3h = tmsg->tail;
284 rc = rh->ops->transceive(rh, tmsg);
285 if (rc < 0) {
286 fprintf(stderr, "error during transceive: %d\n", rc);
287 msgb_free(tmsg);
288 return rc;
289 }
290 msgb_apdu_sw(tmsg) = msgb_get_u16(tmsg);
291 ac.sw[0] = msgb_apdu_sw(tmsg) >> 8;
292 ac.sw[1] = msgb_apdu_sw(tmsg) & 0xff;
293 printf("SW=0x%04x, len_rx=%d\n", msgb_apdu_sw(tmsg), msgb_l3len(tmsg));
294 if (msgb_l3len(tmsg))
Harald Welte2ba03bb2017-03-06 18:51:39 +0100295 request_pb_and_tx(ci, ac.hdr.ins, tmsg->l3h, msgb_l3len(tmsg));
296 request_sw_tx(ci, ac.sw);
Harald Welte095ac6c2016-03-19 13:39:33 +0100297 } else if (ac.lc.tot > ac.lc.cur) {
Harald Welte2ba03bb2017-03-06 18:51:39 +0100298 request_pb_and_rx(ci, ac.hdr.ins, ac.lc.tot - ac.lc.cur);
Harald Welte095ac6c2016-03-19 13:39:33 +0100299 }
300 return 0;
301}
302
303/*! \brief Process an incoming message from the SIMtrace2 */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100304static int process_usb_msg(struct cardem_inst *ci, uint8_t *buf, int len)
Harald Welte095ac6c2016-03-19 13:39:33 +0100305{
306 struct cardemu_usb_msg_hdr *sh = (struct cardemu_usb_msg_hdr *)buf;
Harald Welte095ac6c2016-03-19 13:39:33 +0100307 int rc;
308
309 printf("-> %s\n", osmo_hexdump(buf, len));
310
311 switch (sh->msg_type) {
312 case CEMU_USB_MSGT_DO_STATUS:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100313 rc = process_do_status(ci, buf, len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100314 break;
315 case CEMU_USB_MSGT_DO_PTS:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100316 rc = process_do_pts(ci, buf, len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100317 break;
318 case CEMU_USB_MSGT_DO_ERROR:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100319 rc = process_do_error(ci, buf, len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100320 break;
321 case CEMU_USB_MSGT_DO_RX_DATA:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100322 rc = process_do_rx_da(ci, buf, len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100323 break;
324 default:
325 printf("unknown simtrace msg type 0x%02x\n", sh->msg_type);
326 rc = -1;
327 break;
328 }
329
330 return rc;
331}
332
333static void print_welcome(void)
334{
335 printf("simtrace2-remsim - Remote SIM card forwarding\n"
Harald Welteb170ea92017-03-06 18:59:41 +0100336 "(C) 2010-2017 by Harald Welte <laforge@gnumonks.org>\n\n");
Harald Welte095ac6c2016-03-19 13:39:33 +0100337}
338
339static void print_help(void)
340{
Harald Welte62bfd8a2017-03-06 20:56:14 +0100341 printf( "\t-r\t--remote-udp-host HOST\n"
342 "\t-p\t--remote-udp-port PORT\n"
Harald Welte095ac6c2016-03-19 13:39:33 +0100343 "\t-h\t--help\n"
Harald Welte62bfd8a2017-03-06 20:56:14 +0100344 "\t-i\t--gsmtap-ip\tA.B.C.D\n"
345 "\t-a\t--skip-atr\n"
Harald Welte095ac6c2016-03-19 13:39:33 +0100346 "\t-k\t--keep-running\n"
Harald Welte822d66e2017-03-06 20:58:03 +0100347 "\t-V\t--usb-vendor\tVENDOR_ID\n"
348 "\t-P\t--usb-product\tPRODUCT_ID\n"
349 "\t-C\t--usb-config\tCONFIG_ID\n"
350 "\t-I\t--usb-interface\tINTERFACE_ID\n"
351 "\t-S\t--usb-altsetting ALTSETTING_ID\n"
352 "\t-A\t--usb-address\tADDRESS\n"
Harald Welte095ac6c2016-03-19 13:39:33 +0100353 "\n"
354 );
355}
356
357static const struct option opts[] = {
Harald Welte62bfd8a2017-03-06 20:56:14 +0100358 { "remote-udp-host", 1, 0, 'r' },
359 { "remote-udp-port", 1, 0, 'p' },
Harald Welte095ac6c2016-03-19 13:39:33 +0100360 { "gsmtap-ip", 1, 0, 'i' },
361 { "skip-atr", 0, 0, 'a' },
362 { "help", 0, 0, 'h' },
363 { "keep-running", 0, 0, 'k' },
Harald Welte822d66e2017-03-06 20:58:03 +0100364 { "usb-vendor", 1, 0, 'V' },
365 { "usb-product", 1, 0, 'P' },
366 { "usb-config", 1, 0, 'C' },
367 { "usb-interface", 1, 0, 'I' },
368 { "usb-altsetting", 1, 0, 'S' },
369 { "usb-address", 1, 0, 'A' },
Harald Welte095ac6c2016-03-19 13:39:33 +0100370 { NULL, 0, 0, 0 }
371};
372
Harald Welte2ba03bb2017-03-06 18:51:39 +0100373static void run_mainloop(struct cardem_inst *ci)
Harald Welte095ac6c2016-03-19 13:39:33 +0100374{
375 unsigned int msg_count, byte_count = 0;
Harald Welteb170ea92017-03-06 18:59:41 +0100376 uint8_t buf[16*265];
Harald Welte095ac6c2016-03-19 13:39:33 +0100377 int xfer_len;
378 int rc;
379
380 printf("Entering main loop\n");
381
382 while (1) {
383 /* read data from SIMtrace2 device (local or via USB) */
Harald Welte2ba03bb2017-03-06 18:51:39 +0100384 if (ci->udp_fd < 0) {
385 rc = libusb_bulk_transfer(ci->usb_devh, ci->usb_ep.in,
386 buf, sizeof(buf), &xfer_len, 100000);
Harald Welte095ac6c2016-03-19 13:39:33 +0100387 if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT) {
388 fprintf(stderr, "BULK IN transfer error; rc=%d\n", rc);
389 return;
390 }
391 } else {
Harald Welte2ba03bb2017-03-06 18:51:39 +0100392 rc = read(ci->udp_fd, buf, sizeof(buf));
Harald Welte095ac6c2016-03-19 13:39:33 +0100393 if (rc <= 0) {
394 fprintf(stderr, "shor read from UDP\n");
395 return;
396 }
397 xfer_len = rc;
398 }
399 /* dispatch any incoming data */
400 if (xfer_len > 0) {
401 //printf("URB: %s\n", osmo_hexdump(buf, rc));
Harald Welte2ba03bb2017-03-06 18:51:39 +0100402 process_usb_msg(ci, buf, xfer_len);
Harald Welte095ac6c2016-03-19 13:39:33 +0100403 msg_count++;
404 byte_count += xfer_len;
405 }
406 }
407}
408
Harald Welte2ba03bb2017-03-06 18:51:39 +0100409struct cardem_inst _ci, *ci = &_ci;
410
Harald Welte1871c252016-03-20 15:30:46 +0100411static void signal_handler(int signal)
412{
413 switch (signal) {
414 case SIGINT:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100415 request_card_insert(ci, false);
Harald Welte1871c252016-03-20 15:30:46 +0100416 exit(0);
417 break;
418 default:
419 break;
420 }
421}
422
Harald Welte095ac6c2016-03-19 13:39:33 +0100423int main(int argc, char **argv)
424{
425 char *gsmtap_host = "127.0.0.1";
426 int rc;
427 int c, ret = 1;
428 int skip_atr = 0;
429 int keep_running = 0;
430 int remote_udp_port = 52342;
Harald Welte822d66e2017-03-06 20:58:03 +0100431 int if_num = 0, vendor_id = -1, product_id = -1;
432 int config_id = -1, altsetting = 0, addr = -1;
Harald Welte095ac6c2016-03-19 13:39:33 +0100433 char *remote_udp_host = NULL;
434 struct osim_reader_hdl *reader;
435 struct osim_card_hdl *card;
436
437 print_welcome();
438
439 while (1) {
440 int option_index = 0;
441
Harald Welte822d66e2017-03-06 20:58:03 +0100442 c = getopt_long(argc, argv, "r:p:hi:V:P:C:I:S:A:ak", opts, &option_index);
Harald Welte095ac6c2016-03-19 13:39:33 +0100443 if (c == -1)
444 break;
445 switch (c) {
446 case 'r':
447 remote_udp_host = optarg;
448 break;
449 case 'p':
450 remote_udp_port = atoi(optarg);
451 break;
452 case 'h':
453 print_help();
454 exit(0);
455 break;
456 case 'i':
457 gsmtap_host = optarg;
458 break;
459 case 'a':
460 skip_atr = 1;
461 break;
462 case 'k':
463 keep_running = 1;
464 break;
Harald Welte822d66e2017-03-06 20:58:03 +0100465 case 'V':
466 vendor_id = strtol(optarg, NULL, 16);
467 break;
468 case 'P':
469 product_id = strtol(optarg, NULL, 16);
470 break;
471 case 'C':
472 config_id = atoi(optarg);
473 break;
474 case 'I':
475 if_num = atoi(optarg);
476 break;
477 case 'S':
478 altsetting = atoi(optarg);
479 break;
480 case 'A':
481 addr = atoi(optarg);
482 break;
Harald Welte095ac6c2016-03-19 13:39:33 +0100483 }
484 }
485
Harald Welte822d66e2017-03-06 20:58:03 +0100486 if (!remote_udp_host && (vendor_id < 0 || product_id < 0)) {
487 fprintf(stderr, "You have to specify the vendor and product ID\n");
488 goto do_exit;
489 }
490
Harald Welte2ba03bb2017-03-06 18:51:39 +0100491 memset(ci, 0, sizeof(*ci));
492 ci->udp_fd = -1;
493
494 ci->card_prof = &osim_uicc_sim_cic_profile;
Harald Welte095ac6c2016-03-19 13:39:33 +0100495
496 if (!remote_udp_host) {
497 rc = libusb_init(NULL);
498 if (rc < 0) {
499 fprintf(stderr, "libusb initialization failed\n");
500 goto do_exit;
501 }
502 } else {
Harald Welte2ba03bb2017-03-06 18:51:39 +0100503 ci->udp_fd = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, remote_udp_host,
504 remote_udp_port+if_num, OSMO_SOCK_F_CONNECT);
505 if (ci->udp_fd < 0) {
Harald Welte095ac6c2016-03-19 13:39:33 +0100506 fprintf(stderr, "error binding UDP port\n");
507 goto do_exit;
508 }
509 }
510
511 g_gti = gsmtap_source_init(gsmtap_host, GSMTAP_UDP_PORT, 0);
512 if (!g_gti) {
513 perror("unable to open GSMTAP");
514 goto close_exit;
515 }
516 gsmtap_source_add_sink(g_gti);
517
518 reader = osim_reader_open(OSIM_READER_DRV_PCSC, 0, "", NULL);
519 if (!reader) {
520 perror("unable to open PC/SC reader");
521 goto close_exit;
522 }
523
524 card = osim_card_open(reader, OSIM_PROTO_T0);
525 if (!card) {
526 perror("unable to open SIM card");
527 goto close_exit;
528 }
529
Harald Welte2ba03bb2017-03-06 18:51:39 +0100530 ci->chan = llist_entry(card->channels.next, struct osim_chan_hdl, list);
531 if (!ci->chan) {
Harald Welte095ac6c2016-03-19 13:39:33 +0100532 perror("SIM card has no channel?!?");
533 goto close_exit;
534 }
535
Harald Welte1871c252016-03-20 15:30:46 +0100536 signal(SIGINT, &signal_handler);
537
Harald Welte095ac6c2016-03-19 13:39:33 +0100538 do {
Harald Welte2ba03bb2017-03-06 18:51:39 +0100539 if (ci->udp_fd < 0) {
Harald Welte822d66e2017-03-06 20:58:03 +0100540 struct usb_interface_match _ifm, *ifm = &_ifm;
541 ifm->vendor = vendor_id;
542 ifm->product = product_id;
543 ifm->configuration = config_id;
544 ifm->interface = if_num;
545 ifm->altsetting = altsetting;
546 ifm->addr = addr;
547 ci->usb_devh = usb_open_claim_interface(NULL, ifm);
Harald Welte2ba03bb2017-03-06 18:51:39 +0100548 if (!ci->usb_devh) {
Harald Welte095ac6c2016-03-19 13:39:33 +0100549 fprintf(stderr, "can't open USB device\n");
550 goto close_exit;
551 }
552
Harald Welte2ba03bb2017-03-06 18:51:39 +0100553 rc = libusb_claim_interface(ci->usb_devh, if_num);
Harald Welte095ac6c2016-03-19 13:39:33 +0100554 if (rc < 0) {
Harald Welte236caf62016-03-19 21:28:09 +0100555 fprintf(stderr, "can't claim interface %d; rc=%d\n", if_num, rc);
556 goto close_exit;
557 }
558
Harald Welte2ba03bb2017-03-06 18:51:39 +0100559 rc = get_usb_ep_addrs(ci->usb_devh, if_num, &ci->usb_ep.out,
560 &ci->usb_ep.in, &ci->usb_ep.irq_in);
Harald Welte236caf62016-03-19 21:28:09 +0100561 if (rc < 0) {
562 fprintf(stderr, "can't obtain EP addrs; rc=%d\n", rc);
Harald Welte095ac6c2016-03-19 13:39:33 +0100563 goto close_exit;
564 }
565 }
566
Harald Welte2ba03bb2017-03-06 18:51:39 +0100567 request_card_insert(ci, true);
Harald Welte9daaa792016-03-20 15:01:20 +0100568 uint8_t real_atr[] = { 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31,
569 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20,
570 0x07, 0x18, 0x00, 0x00, 0x01, 0xA5 };
571 atr_update_csum(real_atr, sizeof(real_atr));
Harald Welte2ba03bb2017-03-06 18:51:39 +0100572 request_set_atr(ci, real_atr, sizeof(real_atr));
Harald Welte095ac6c2016-03-19 13:39:33 +0100573
Harald Welte2ba03bb2017-03-06 18:51:39 +0100574 run_mainloop(ci);
Harald Welte095ac6c2016-03-19 13:39:33 +0100575 ret = 0;
576
Harald Welte2ba03bb2017-03-06 18:51:39 +0100577 if (ci->udp_fd < 0)
578 libusb_release_interface(ci->usb_devh, 0);
Harald Welte095ac6c2016-03-19 13:39:33 +0100579close_exit:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100580 if (ci->usb_devh)
581 libusb_close(ci->usb_devh);
Harald Welte095ac6c2016-03-19 13:39:33 +0100582 if (keep_running)
583 sleep(1);
584 } while (keep_running);
585
586release_exit:
Harald Welte2ba03bb2017-03-06 18:51:39 +0100587 if (ci->udp_fd < 0)
Harald Welte095ac6c2016-03-19 13:39:33 +0100588 libusb_exit(NULL);
589do_exit:
590 return ret;
591}