bankd_main: Obtain ATR of card via PC/SC API

Change-Id: Ie73806e2190e604cab96b3f632b4bbfffb7d0112
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 @@
 			} 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 @@
         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 @@
 		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 @@
 	}
 }
 
+/* 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 @@
 		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 @@
 		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 @@
 		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;