blob: 5b296387d006daa6565564907906337f4ee8c6bc [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file reader_pcsc.c
2 * PC/SC Card reader backend for libosmosim. */
Harald Weltead418632012-09-10 10:49:59 +02003/*
4 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24
Harald Welted54c2ee2012-01-17 18:25:50 +010025#include <string.h>
26#include <stdint.h>
27#include <stdio.h>
28#include <errno.h>
29
30#include <osmocom/core/talloc.h>
31#include <osmocom/sim/sim.h>
32
Holger Hans Peter Freytherb0310dd2014-10-27 12:00:37 +010033#include <wintypes.h>
34#include <winscard.h>
Harald Welted54c2ee2012-01-17 18:25:50 +010035
36#include "sim_int.h"
37
38#define PCSC_ERROR(rv, text) \
39if (rv != SCARD_S_SUCCESS) { \
40 fprintf(stderr, text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
41 goto end; \
42} else { \
43 printf(text ": OK\n\n"); \
44}
45
46
47
48struct pcsc_reader_state {
49 SCARDCONTEXT hContext;
50 SCARDHANDLE hCard;
51 DWORD dwActiveProtocol;
52 const SCARD_IO_REQUEST *pioSendPci;
53 SCARD_IO_REQUEST pioRecvPci;
54 char *name;
55};
56
57static struct osim_reader_hdl *pcsc_reader_open(int num, const char *id, void *ctx)
58{
59 struct osim_reader_hdl *rh;
60 struct pcsc_reader_state *st;
Harald Welte0d246442014-05-04 13:58:54 +020061 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +010062 LPSTR mszReaders = NULL;
63 DWORD dwReaders;
64 unsigned int num_readers;
65 char *ptr;
66
67 /* FIXME: implement matching on id or num */
68
69 rh = talloc_zero(ctx, struct osim_reader_hdl);
70 st = rh->priv = talloc_zero(rh, struct pcsc_reader_state);
71
72 rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
73 &st->hContext);
Harald Welted83d2962013-03-04 17:52:33 +000074 PCSC_ERROR(rc, "SCardEstablishContext");
Harald Welted54c2ee2012-01-17 18:25:50 +010075
76 dwReaders = SCARD_AUTOALLOCATE;
77 rc = SCardListReaders(st->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
78 PCSC_ERROR(rc, "SCardListReaders");
79
80 num_readers = 0;
81 ptr = mszReaders;
82 while (*ptr != '\0') {
83 ptr += strlen(ptr)+1;
84 num_readers++;
85 }
86
87 if (num_readers == 0)
88 goto end;
89
90 st->name = talloc_strdup(rh, mszReaders);
91 st->dwActiveProtocol = -1;
92
93 return rh;
94end:
95 talloc_free(rh);
96 return NULL;
97}
98
Harald Welte55790aa2014-10-26 18:46:50 +010099static struct osim_card_hdl *pcsc_card_open(struct osim_reader_hdl *rh,
100 enum osim_proto proto)
Harald Welted54c2ee2012-01-17 18:25:50 +0100101{
102 struct pcsc_reader_state *st = rh->priv;
103 struct osim_card_hdl *card;
104 struct osim_chan_hdl *chan;
Harald Welte0d246442014-05-04 13:58:54 +0200105 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100106
Harald Welte55790aa2014-10-26 18:46:50 +0100107 if (proto != OSIM_PROTO_T0)
108 return NULL;
109
Harald Welted54c2ee2012-01-17 18:25:50 +0100110 rc = SCardConnect(st->hContext, st->name, SCARD_SHARE_SHARED,
111 SCARD_PROTOCOL_T0, &st->hCard, &st->dwActiveProtocol);
112 PCSC_ERROR(rc, "SCardConnect");
113
114 st->pioSendPci = SCARD_PCI_T0;
115
116 card = talloc_zero(rh, struct osim_card_hdl);
117 INIT_LLIST_HEAD(&card->channels);
118 card->reader = rh;
119 rh->card = card;
120
121 /* create a default channel */
122 chan = talloc_zero(card, struct osim_chan_hdl);
123 chan->card = card;
124 llist_add(&chan->list, &card->channels);
125
126 return card;
127
128end:
129 return NULL;
130}
131
132
133static int pcsc_transceive(struct osim_reader_hdl *rh, struct msgb *msg)
134{
135 struct pcsc_reader_state *st = rh->priv;
136 DWORD rlen = msgb_tailroom(msg);
Harald Welte0d246442014-05-04 13:58:54 +0200137 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100138
139 printf("TX: %s\n", osmo_hexdump(msg->data, msg->len));
140
141 rc = SCardTransmit(st->hCard, st->pioSendPci, msg->data, msgb_length(msg),
142 &st->pioRecvPci, msg->tail, &rlen);
143 PCSC_ERROR(rc, "SCardEndTransaction");
144
145 printf("RX: %s\n", osmo_hexdump(msg->tail, rlen));
146 msgb_put(msg, rlen);
147 msgb_apdu_le(msg) = rlen;
148
149 return 0;
150end:
151 return -EIO;
152}
153
154const struct osim_reader_ops pcsc_reader_ops = {
155 .name = "PC/SC",
156 .reader_open = pcsc_reader_open,
157 .card_open = pcsc_card_open,
158 .transceive = pcsc_transceive,
159};
160