/* PC/SC Card reader backend for libosmosim */ /* * (C) 2012 by Harald Welte * * 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 #include #include #include #include #include #include #include #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) { struct pcsc_reader_state *st = rh->priv; struct osim_card_hdl *card; struct osim_chan_hdl *chan; int rc; 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); int 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, };