bankd: Move all PC/SC specific code to bankd_pcsc

Change-Id: I435b42982b54d74447c435dcefa26d1e317d15e0
diff --git a/src/bankd.h b/src/bankd.h
index 6d4f675..d56734c 100644
--- a/src/bankd.h
+++ b/src/bankd.h
@@ -17,6 +17,12 @@
 #include "client.h"
 #include "debug.h"
 
+extern struct value_string worker_state_names[];
+
+#define LOGW(w, fmt, args...) \
+	printf("[%03u %s] %s:%u " fmt, (w)->num, get_value_string(worker_state_names, (w)->state), \
+		__FILE__, __LINE__, ## args)
+
 struct bankd;
 
 enum bankd_worker_state {
@@ -64,6 +70,8 @@
 	/* top talloc context for this worker/thread */
 	void *tall_ctx;
 
+	const struct bankd_driver_ops *ops;
+
 	/* File descriptor of the TCP connection to the remsim-client (modem) */
 	struct {
 		int fd;
@@ -90,6 +98,15 @@
 	} card;
 };
 
+/* bankd card reader driver operations */
+struct bankd_driver_ops {
+	/* open a given card/slot: called once client + mapping exists */
+	int (*open_card)(struct bankd_worker *worker);
+	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 */
+	void (*cleanup)(struct bankd_worker *worker);
+};
 
 /* global bank deamon */
 struct bankd {
@@ -120,3 +137,5 @@
 
 int bankd_pcsc_read_slotnames(struct bankd *bankd, const char *csv_file);
 const char *bankd_pcsc_get_slot_name(struct bankd *bankd, const struct bank_slot *slot);
+
+extern const struct bankd_driver_ops pcsc_driver_ops;
diff --git a/src/bankd_main.c b/src/bankd_main.c
index c18a280..cb78718 100644
--- a/src/bankd_main.c
+++ b/src/bankd_main.c
@@ -31,10 +31,6 @@
 
 #include <pthread.h>
 
-#include <wintypes.h>
-#include <winscard.h>
-#include <pcsclite.h>
-
 #include <sys/socket.h>
 #include <netdb.h>
 
@@ -113,6 +109,7 @@
 
 	worker->bankd = bankd;
 	worker->num = i;
+	worker->ops = &pcsc_driver_ops;
 
 	/* in the initial state, the worker has no client.fd, bank_slot or pcsc handle yet */
 
@@ -299,18 +296,6 @@
 	{ 0, NULL }
 };
 
-#define LOGW(w, fmt, args...) \
-	printf("[%03u %s] %s:%u " fmt, (w)->num, get_value_string(worker_state_names, (w)->state), \
-		__FILE__, __LINE__, ## args)
-
-#define PCSC_ERROR(w, rv, text) \
-if (rv != SCARD_S_SUCCESS) { \
-	LOGW((w), text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
-	goto end; \
-} else { \
-        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)
@@ -372,10 +357,9 @@
 	pthread_mutex_unlock(&bankd->workers_mutex);
 }
 
-
 static int worker_open_card(struct bankd_worker *worker)
 {
-	long rc;
+	int rc;
 
 	OSMO_ASSERT(worker->state == BW_ST_CONN_CLIENT_MAPPED);
 
@@ -385,44 +369,19 @@
 		if (!worker->reader.name) {
 			LOGW(worker, "No PC/SC reader name configured for %u/%u, fix your config\n",
 				worker->slot.bank_id, worker->slot.slot_nr);
-			rc = -1;
-			goto end;
+			return -1;
 		}
 	}
 	OSMO_ASSERT(worker->reader.name);
 
-	if (!worker->reader.pcsc.hContext) {
-		LOGW(worker, "Attempting to open PC/SC context\n");
-		/* The PC/SC context must be created inside the thread where we'll later use it */
-		rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &worker->reader.pcsc.hContext);
-		PCSC_ERROR(worker, rc, "SCardEstablishContext")
-	}
-
-	if (!worker->reader.pcsc.hCard) {
-		LOGW(worker, "Attempting to open card/slot '%s'\n", worker->reader.name);
-		DWORD dwActiveProtocol;
-		rc = SCardConnect(worker->reader.pcsc.hContext, worker->reader.name, SCARD_SHARE_SHARED,
-				  SCARD_PROTOCOL_T0, &worker->reader.pcsc.hCard, &dwActiveProtocol);
-		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 = worker->ops->open_card(worker);
+	if (rc < 0)
+		return rc;
 
 	worker_set_state(worker, BW_ST_CONN_CLIENT_MAPPED_CARD);
 	/* FIXME: notify client about this state change */
 
 	return 0;
-end:
-	return rc;
 }
 
 
@@ -588,14 +547,12 @@
 static int worker_handle_tpduModemToCard(struct bankd_worker *worker, const RsproPDU_t *pdu)
 {
 	const struct TpduModemToCard *mdm2sim = &pdu->msg.choice.tpduModemToCard;
-	const SCARD_IO_REQUEST *pioSendPci = SCARD_PCI_T0;
-	SCARD_IO_REQUEST pioRecvPci;
 	uint8_t rx_buf[1024];
 	DWORD rx_buf_len = sizeof(rx_buf);
 	RsproPDU_t *pdu_resp;
 	struct client_slot clslot;
 	struct bank_slot bslot;
-	long rc;
+	int rc;
 
 	LOGW(worker, "tpduModemToCard(%s)\n", osmo_hexdump_nospc(mdm2sim->data.buf, mdm2sim->data.size));
 
@@ -618,10 +575,10 @@
 		return -106;
 	}
 
-	rc = SCardTransmit(worker->reader.pcsc.hCard,
-			   pioSendPci, mdm2sim->data.buf, mdm2sim->data.size,
-			   &pioRecvPci, rx_buf, &rx_buf_len);
-	PCSC_ERROR(worker, rc, "SCardTransmit");
+	rc = worker->ops->transceive(worker, mdm2sim->data.buf, mdm2sim->data.size,
+				     rx_buf, &rx_buf_len);
+	if (rc < 0)
+		return rc;
 
 	/* encode response PDU and send it */
 	pdu_resp = rspro_gen_TpduCard2Modem(&mdm2sim->toBankSlot, &mdm2sim->fromClientSlot,
@@ -629,8 +586,6 @@
 	worker_send_rspro(worker, pdu_resp);
 
 	return 0;
-end:
-	return rc;
 }
 
 /* handle one incoming RSPRO message from a client inside a worker thread */
@@ -828,14 +783,7 @@
 
 		/* 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;
-		}
-		if (g_worker->reader.pcsc.hContext) {
-			SCardReleaseContext(g_worker->reader.pcsc.hContext);
-			g_worker->reader.pcsc.hContext = 0;
-		}
+		g_worker->ops->cleanup(g_worker);
 		if (g_worker->reader.name)
 			g_worker->reader.name = NULL;
 		if (g_worker->client.fd >= 0)
diff --git a/src/bankd_pcsc.c b/src/bankd_pcsc.c
index 671c6bf..a390782 100644
--- a/src/bankd_pcsc.c
+++ b/src/bankd_pcsc.c
@@ -138,3 +138,81 @@
 	}
 	return NULL;
 }
+
+
+#include <wintypes.h>
+#include <winscard.h>
+#include <pcsclite.h>
+
+#define PCSC_ERROR(w, rv, text) \
+if (rv != SCARD_S_SUCCESS) { \
+	LOGW((w), text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
+	goto end; \
+} else { \
+        LOGW((w), ": OK\n"); \
+}
+
+static int pcsc_open_card(struct bankd_worker *worker)
+{
+	long rc;
+
+	if (!worker->reader.pcsc.hContext) {
+		LOGW(worker, "Attempting to open PC/SC context\n");
+		/* The PC/SC context must be created inside the thread where we'll later use it */
+		rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &worker->reader.pcsc.hContext);
+		PCSC_ERROR(worker, rc, "SCardEstablishContext")
+	}
+
+	if (!worker->reader.pcsc.hCard) {
+		LOGW(worker, "Attempting to open card/slot '%s'\n", worker->reader.name);
+		DWORD dwActiveProtocol;
+		rc = SCardConnect(worker->reader.pcsc.hContext, worker->reader.name, SCARD_SHARE_SHARED,
+				  SCARD_PROTOCOL_T0, &worker->reader.pcsc.hCard, &dwActiveProtocol);
+		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));
+end:
+	return rc;
+}
+
+static int pcsc_transceive(struct bankd_worker *worker, const uint8_t *out, size_t out_len,
+			   uint8_t *in, size_t *in_len)
+{
+	const SCARD_IO_REQUEST *pioSendPci = SCARD_PCI_T0;
+	SCARD_IO_REQUEST pioRecvPci;
+	long rc;
+
+	rc = SCardTransmit(worker->reader.pcsc.hCard, pioSendPci, out, out_len, &pioRecvPci, in, in_len);
+	PCSC_ERROR(worker, rc, "SCardTransmit");
+
+end:
+	return rc;
+}
+
+static void pcsc_cleanup(struct bankd_worker *worker)
+{
+	if (worker->reader.pcsc.hCard) {
+		SCardDisconnect(worker->reader.pcsc.hCard, SCARD_UNPOWER_CARD);
+		worker->reader.pcsc.hCard = 0;
+	}
+	if (worker->reader.pcsc.hContext) {
+		SCardReleaseContext(worker->reader.pcsc.hContext);
+		worker->reader.pcsc.hContext = 0;
+	}
+}
+
+const struct bankd_driver_ops pcsc_driver_ops = {
+	.open_card = pcsc_open_card,
+	.transceive = pcsc_transceive,
+	.cleanup = pcsc_cleanup,
+};
diff --git a/src/bankd_pcsc_slots.csv b/src/bankd_pcsc_slots.csv
index 32fc574..38a22c9 100644
--- a/src/bankd_pcsc_slots.csv
+++ b/src/bankd_pcsc_slots.csv
@@ -1,6 +1,6 @@
-"1","0","ACS ACR33 ICC Reader 01 00"
-"1","1","ACS ACR33 ICC Reader 01 01"
-"1","2","ACS ACR33 ICC Reader 01 02"
-"1","3","ACS ACR33 ICC Reader 01 03"
-"1","4","ACS ACR33 ICC Reader 01 04"
+"1","0","ACS ACR33 ICC Reader 00 00"
+"1","1","ACS ACR33 ICC Reader 00 01"
+"1","2","ACS ACR33 ICC Reader 00 02"
+"1","3","ACS ACR33 ICC Reader 00 03"
+"1","4","ACS ACR33 ICC Reader 00 04"
 "1","23","Alcor Micro AU9560 00 00"