diff --git a/src/bankd/bankd.h b/src/bankd/bankd.h index 7f4d687..d713ed1 100644 --- a/src/bankd/bankd.h +++ b/src/bankd/bankd.h @@ -102,6 +102,8 @@ struct bankd_worker { struct bankd_driver_ops { /* open a given card/slot: called once client + mapping exists */ int (*open_card)(struct bankd_worker *worker); + /* reset a given card/slot with either cold or warm reset */ + int (*reset_card)(struct bankd_worker *worker, bool cold_reset); int (*transceive)(struct bankd_worker *worker, const uint8_t *out, size_t out_len, uint8_t *in, size_t *in_len); /* called at cleanup time of a worker thread: clear any driver related state */ diff --git a/src/bankd/bankd_main.c b/src/bankd/bankd_main.c index af25ded..b3e38b3 100644 --- a/src/bankd/bankd_main.c +++ b/src/bankd/bankd_main.c @@ -727,6 +727,26 @@ static int worker_handle_tpduModemToCard(struct bankd_worker *worker, const Rspr return 0; } +static int worker_handle_clientSlotStatusInd(struct bankd_worker *worker, const RsproPDU_t *pdu) +{ + const struct ClientSlotStatusInd *cssi = &pdu->msg.choice.clientSlotStatusInd; + const struct SlotPhysStatus *sps = &cssi->slotPhysStatus; + int rc = 0; + + LOGW(worker, "clientSlotStatusInd(RST=%s, VCC=%s, CLK=%s)\n", + sps->resetActive ? "ACTIVE" : "INACTIVE", + sps->vccPresent ? *sps->vccPresent ? "PRESENT" : "ABSENT" : "NULL", + sps->clkActive ? *sps->clkActive ? "ACTIVE" : "INACTIVE" : "NULL"); + + /* perform cold or warm reset */ + if (sps->vccPresent && *sps->vccPresent == 0) + rc = worker->ops->reset_card(worker, true); + else if (sps->resetActive) + rc = worker->ops->reset_card(worker, false); + + return rc; +} + /* handle one incoming RSPRO message from a client inside a worker thread */ static int worker_handle_rspro(struct bankd_worker *worker, const RsproPDU_t *pdu) { @@ -742,7 +762,7 @@ static int worker_handle_rspro(struct bankd_worker *worker, const RsproPDU_t *pd rc = worker_handle_tpduModemToCard(worker, pdu); break; case RsproPDUchoice_PR_clientSlotStatusInd: - /* FIXME */ + rc = worker_handle_clientSlotStatusInd(worker, pdu); rc = 0; break; case RsproPDUchoice_PR_setAtrRes: diff --git a/src/bankd/bankd_pcsc.c b/src/bankd/bankd_pcsc.c index a390782..f6e3683 100644 --- a/src/bankd/bankd_pcsc.c +++ b/src/bankd/bankd_pcsc.c @@ -152,6 +152,24 @@ if (rv != SCARD_S_SUCCESS) { \ LOGW((w), ": OK\n"); \ } +static int pcsc_get_atr(struct bankd_worker *worker) +{ + long rc; + char pbReader[MAX_READERNAME]; + /* use DWORD type as this is what the PC/SC API expects */ + 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)); +end: + return rc; +} + static int pcsc_open_card(struct bankd_worker *worker) { long rc; @@ -171,16 +189,23 @@ static int pcsc_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)); + rc = pcsc_get_atr(worker); +end: + return rc; +} + +static int pcsc_reset_card(struct bankd_worker *worker, bool cold_reset) +{ + long rc; + DWORD dwActiveProtocol; + + LOGW(worker, "Resetting card in '%s' (%s)\n", worker->reader.name, + cold_reset ? "cold reset" : "warm reset"); + rc = SCardReconnect(worker->reader.pcsc.hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, + cold_reset ? SCARD_UNPOWER_CARD : SCARD_RESET_CARD, &dwActiveProtocol); + PCSC_ERROR(worker, rc, "SCardReconnect"); + + rc = pcsc_get_atr(worker); end: return rc; } @@ -213,6 +238,7 @@ static void pcsc_cleanup(struct bankd_worker *worker) const struct bankd_driver_ops pcsc_driver_ops = { .open_card = pcsc_open_card, + .reset_card = pcsc_reset_card, .transceive = pcsc_transceive, .cleanup = pcsc_cleanup, };