From 1f699b405ab09bcfe7ae02650a9c42e2a657a18e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 28 Mar 2019 13:41:08 +0100 Subject: [PATCH] bankd_main: Obtain ATR of card via PC/SC API Change-Id: Ie73806e2190e604cab96b3f632b4bbfffb7d0112 --- src/bankd.h | 5 +++++ src/bankd_main.c | 40 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/bankd.h b/src/bankd.h index 0ca1984..6d4f675 100644 --- a/src/bankd.h +++ b/src/bankd.h @@ -83,6 +83,11 @@ struct bankd_worker { } pcsc; }; } reader; + + struct { + uint8_t atr[MAX_ATR_SIZE]; + unsigned int atr_len; + } card; }; diff --git a/src/bankd_main.c b/src/bankd_main.c index 0760811..c18a280 100644 --- a/src/bankd_main.c +++ b/src/bankd_main.c @@ -311,6 +311,8 @@ if (rv != SCARD_S_SUCCESS) { \ LOGW((w), ": OK\n"); \ } +static int worker_send_rspro(struct bankd_worker *worker, RsproPDU_t *pdu); + static void worker_set_state(struct bankd_worker *worker, enum bankd_worker_state new_state) { LOGW(worker, "Changing state to %s\n", get_value_string(worker_state_names, new_state)); @@ -404,6 +406,17 @@ static int worker_open_card(struct bankd_worker *worker) PCSC_ERROR(worker, rc, "SCardConnect") } + /* use DWORD type as this is what the PC/SC API expects */ + char pbReader[MAX_READERNAME]; + DWORD dwReaderLen = sizeof(pbReader); + DWORD dwAtrLen = worker->card.atr_len = sizeof(worker->card.atr); + DWORD dwState, dwProt; + rc = SCardStatus(worker->reader.pcsc.hCard, pbReader, &dwReaderLen, &dwState, &dwProt, + worker->card.atr, &dwAtrLen); + PCSC_ERROR(worker, rc, "SCardStatus") + worker->card.atr_len = dwAtrLen; + LOGW(worker, "Card ATR: %s\n", osmo_hexdump_nospc(worker->card.atr, worker->card.atr_len)); + worker_set_state(worker, BW_ST_CONN_CLIENT_MAPPED_CARD); /* FIXME: notify client about this state change */ @@ -508,6 +521,17 @@ static int worker_try_slotmap(struct bankd_worker *worker) } } +/* inform the remote end (client) about the (new) ATR */ +static int worker_send_atr(struct bankd_worker *worker) +{ + RsproPDU_t *set_atr; + set_atr = rspro_gen_SetAtrReq(worker->client.clslot.client_id, + worker->client.clslot.slot_nr, + worker->card.atr, worker->card.atr_len); + if (!set_atr) + return -1; + return worker_send_rspro(worker, set_atr); +} static int worker_handle_connectClientReq(struct bankd_worker *worker, const RsproPDU_t *pdu) { @@ -544,7 +568,14 @@ static int worker_handle_connectClientReq(struct bankd_worker *worker, const Rsp res = ResultCode_cardNotPresent; resp = rspro_gen_ConnectClientRes(&worker->bankd->comp_id, res); - return worker_send_rspro(worker, resp); + rc = worker_send_rspro(worker, resp); + if (rc < 0) + return rc; + + if (res == ResultCode_ok) + rc = worker_send_atr(worker); + + return rc; respond_and_err: if (res) { @@ -658,15 +689,17 @@ restart_wait: switch (worker->state) { case BW_ST_CONN_CLIENT_WAIT_MAP: /* re-check if mapping exists meanwhile? */ - worker_try_slotmap(worker); + rc = worker_try_slotmap(worker); break; case BW_ST_CONN_CLIENT_MAPPED: /* re-check if reader/card can be opened meanwhile? */ - worker_open_card(worker); + rc = worker_open_card(worker); break; default: OSMO_ASSERT(0); } + if (rc == 0) + worker_send_atr(worker); /* return early, so we do another select rather than the blocking read below */ return 0; }; @@ -794,6 +827,7 @@ static void *worker_main(void *arg) LOGW(g_worker, "Error %d occurred: Cleaning up state\n", rc); /* clean-up: reset to sane state */ + memset(&g_worker->card, 0, sizeof(g_worker->card)); if (g_worker->reader.pcsc.hCard) { SCardDisconnect(g_worker->reader.pcsc.hCard, SCARD_UNPOWER_CARD); g_worker->reader.pcsc.hCard = 0;