bankd: Implement card reset based on clientSlotStatusInd
If a client is sending us a clientSlotStatusInd indicating that
the modem has switched off VCC or activated RST, bankd will
now issue a respective PC/SC command to perform a cold or warm
reset of the card.
Change-Id: Ifa615d239ec3ad6daebd8e99e4f7d5b99d32c0e1
Closes: OS#4330
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_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 @@
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 @@
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 @@
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 @@
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 @@
const struct bankd_driver_ops pcsc_driver_ops = {
.open_card = pcsc_open_card,
+ .reset_card = pcsc_reset_card,
.transceive = pcsc_transceive,
.cleanup = pcsc_cleanup,
};