blob: f020142e324e01d1c85e09dc9c6a14a045d57d1b [file] [log] [blame]
Harald Weltead418632012-09-10 10:49:59 +02001/* PC/SC Card reader backend for libosmosim */
2/*
3 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23
Harald Welted54c2ee2012-01-17 18:25:50 +010024#include <string.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <errno.h>
28
29#include <osmocom/core/talloc.h>
30#include <osmocom/sim/sim.h>
31
Holger Hans Peter Freytherb0310dd2014-10-27 12:00:37 +010032#include <wintypes.h>
33#include <winscard.h>
Harald Welted54c2ee2012-01-17 18:25:50 +010034
35#include "sim_int.h"
36
37#define PCSC_ERROR(rv, text) \
38if (rv != SCARD_S_SUCCESS) { \
39 fprintf(stderr, text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
40 goto end; \
41} else { \
42 printf(text ": OK\n\n"); \
43}
44
45
46
47struct pcsc_reader_state {
48 SCARDCONTEXT hContext;
49 SCARDHANDLE hCard;
50 DWORD dwActiveProtocol;
51 const SCARD_IO_REQUEST *pioSendPci;
52 SCARD_IO_REQUEST pioRecvPci;
53 char *name;
54};
55
56static struct osim_reader_hdl *pcsc_reader_open(int num, const char *id, void *ctx)
57{
58 struct osim_reader_hdl *rh;
59 struct pcsc_reader_state *st;
Harald Welte0d246442014-05-04 13:58:54 +020060 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +010061 LPSTR mszReaders = NULL;
62 DWORD dwReaders;
63 unsigned int num_readers;
64 char *ptr;
65
66 /* FIXME: implement matching on id or num */
67
68 rh = talloc_zero(ctx, struct osim_reader_hdl);
69 st = rh->priv = talloc_zero(rh, struct pcsc_reader_state);
70
71 rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
72 &st->hContext);
Harald Welted83d2962013-03-04 17:52:33 +000073 PCSC_ERROR(rc, "SCardEstablishContext");
Harald Welted54c2ee2012-01-17 18:25:50 +010074
75 dwReaders = SCARD_AUTOALLOCATE;
76 rc = SCardListReaders(st->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
77 PCSC_ERROR(rc, "SCardListReaders");
78
79 num_readers = 0;
80 ptr = mszReaders;
81 while (*ptr != '\0') {
82 ptr += strlen(ptr)+1;
83 num_readers++;
84 }
85
86 if (num_readers == 0)
87 goto end;
88
89 st->name = talloc_strdup(rh, mszReaders);
90 st->dwActiveProtocol = -1;
91
92 return rh;
93end:
94 talloc_free(rh);
95 return NULL;
96}
97
Harald Welte55790aa2014-10-26 18:46:50 +010098static struct osim_card_hdl *pcsc_card_open(struct osim_reader_hdl *rh,
99 enum osim_proto proto)
Harald Welted54c2ee2012-01-17 18:25:50 +0100100{
101 struct pcsc_reader_state *st = rh->priv;
102 struct osim_card_hdl *card;
103 struct osim_chan_hdl *chan;
Harald Welte0d246442014-05-04 13:58:54 +0200104 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100105
Harald Welte55790aa2014-10-26 18:46:50 +0100106 if (proto != OSIM_PROTO_T0)
107 return NULL;
108
Harald Welted54c2ee2012-01-17 18:25:50 +0100109 rc = SCardConnect(st->hContext, st->name, SCARD_SHARE_SHARED,
110 SCARD_PROTOCOL_T0, &st->hCard, &st->dwActiveProtocol);
111 PCSC_ERROR(rc, "SCardConnect");
112
113 st->pioSendPci = SCARD_PCI_T0;
114
115 card = talloc_zero(rh, struct osim_card_hdl);
116 INIT_LLIST_HEAD(&card->channels);
117 card->reader = rh;
118 rh->card = card;
119
120 /* create a default channel */
121 chan = talloc_zero(card, struct osim_chan_hdl);
122 chan->card = card;
123 llist_add(&chan->list, &card->channels);
124
125 return card;
126
127end:
128 return NULL;
129}
130
131
132static int pcsc_transceive(struct osim_reader_hdl *rh, struct msgb *msg)
133{
134 struct pcsc_reader_state *st = rh->priv;
135 DWORD rlen = msgb_tailroom(msg);
Harald Welte0d246442014-05-04 13:58:54 +0200136 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100137
138 printf("TX: %s\n", osmo_hexdump(msg->data, msg->len));
139
140 rc = SCardTransmit(st->hCard, st->pioSendPci, msg->data, msgb_length(msg),
141 &st->pioRecvPci, msg->tail, &rlen);
142 PCSC_ERROR(rc, "SCardEndTransaction");
143
144 printf("RX: %s\n", osmo_hexdump(msg->tail, rlen));
145 msgb_put(msg, rlen);
146 msgb_apdu_le(msg) = rlen;
147
148 return 0;
149end:
150 return -EIO;
151}
152
153const struct osim_reader_ops pcsc_reader_ops = {
154 .name = "PC/SC",
155 .reader_open = pcsc_reader_open,
156 .card_open = pcsc_card_open,
157 .transceive = pcsc_transceive,
158};
159