| /*! \file reader_pcsc.c |
| * PC/SC Card reader backend for libosmosim. */ |
| /* |
| * (C) 2012 by Harald Welte <laforge@gnumonks.org> |
| * |
| * All Rights Reserved |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| * |
| * 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 <wintypes.h> |
| #include <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"); |
| |
| 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, |
| }; |
| |