diff options
Diffstat (limited to 'src/sim/reader_pcsc.c')
-rw-r--r-- | src/sim/reader_pcsc.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/sim/reader_pcsc.c b/src/sim/reader_pcsc.c new file mode 100644 index 00000000..5e670912 --- /dev/null +++ b/src/sim/reader_pcsc.c @@ -0,0 +1,161 @@ +/* PC/SC Card reader backend for libosmosim */ +/* + * (C) 2012 by Harald Welte <laforge@gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include <string.h> +#include <stdint.h> +#include <stdio.h> +#include <errno.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/sim/sim.h> + +#include <PCSC/wintypes.h> +#include <PCSC/winscard.h> + +#include "sim_int.h" + +#define PCSC_ERROR(rv, text) \ +if (rv != SCARD_S_SUCCESS) { \ + fprintf(stderr, text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \ + goto end; \ +} else { \ + printf(text ": OK\n\n"); \ +} + + + +struct pcsc_reader_state { + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + DWORD dwActiveProtocol; + const SCARD_IO_REQUEST *pioSendPci; + SCARD_IO_REQUEST pioRecvPci; + char *name; +}; + +static struct osim_reader_hdl *pcsc_reader_open(int num, const char *id, void *ctx) +{ + struct osim_reader_hdl *rh; + struct pcsc_reader_state *st; + LONG rc; + LPSTR mszReaders = NULL; + DWORD dwReaders; + unsigned int num_readers; + char *ptr; + + /* FIXME: implement matching on id or num */ + + rh = talloc_zero(ctx, struct osim_reader_hdl); + st = rh->priv = talloc_zero(rh, struct pcsc_reader_state); + + rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, + &st->hContext); + PCSC_ERROR(rc, "SCardEstablishContext"); + if (rc != SCARD_S_SUCCESS) + goto end; + + dwReaders = SCARD_AUTOALLOCATE; + rc = SCardListReaders(st->hContext, NULL, (LPSTR)&mszReaders, &dwReaders); + PCSC_ERROR(rc, "SCardListReaders"); + + num_readers = 0; + ptr = mszReaders; + while (*ptr != '\0') { + ptr += strlen(ptr)+1; + num_readers++; + } + + if (num_readers == 0) + goto end; + + st->name = talloc_strdup(rh, mszReaders); + st->dwActiveProtocol = -1; + + return rh; +end: + talloc_free(rh); + return NULL; +} + +static struct osim_card_hdl *pcsc_card_open(struct osim_reader_hdl *rh, + enum osim_proto proto) +{ + struct pcsc_reader_state *st = rh->priv; + struct osim_card_hdl *card; + struct osim_chan_hdl *chan; + LONG rc; + + if (proto != OSIM_PROTO_T0) + return NULL; + + rc = SCardConnect(st->hContext, st->name, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0, &st->hCard, &st->dwActiveProtocol); + PCSC_ERROR(rc, "SCardConnect"); + + st->pioSendPci = SCARD_PCI_T0; + + card = talloc_zero(rh, struct osim_card_hdl); + INIT_LLIST_HEAD(&card->channels); + card->reader = rh; + rh->card = card; + + /* create a default channel */ + chan = talloc_zero(card, struct osim_chan_hdl); + chan->card = card; + llist_add(&chan->list, &card->channels); + + return card; + +end: + return NULL; +} + + +static int pcsc_transceive(struct osim_reader_hdl *rh, struct msgb *msg) +{ + struct pcsc_reader_state *st = rh->priv; + DWORD rlen = msgb_tailroom(msg); + LONG rc; + + printf("TX: %s\n", osmo_hexdump(msg->data, msg->len)); + + rc = SCardTransmit(st->hCard, st->pioSendPci, msg->data, msgb_length(msg), + &st->pioRecvPci, msg->tail, &rlen); + PCSC_ERROR(rc, "SCardEndTransaction"); + + printf("RX: %s\n", osmo_hexdump(msg->tail, rlen)); + msgb_put(msg, rlen); + msgb_apdu_le(msg) = rlen; + + return 0; +end: + return -EIO; +} + +const struct osim_reader_ops pcsc_reader_ops = { + .name = "PC/SC", + .reader_open = pcsc_reader_open, + .card_open = pcsc_card_open, + .transceive = pcsc_transceive, +}; + |