From c51a5685554a06e00ae1e99070b44613b2f8d417 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Tue, 9 Jul 2019 10:56:09 +0900 Subject: [PATCH] scd: ccid-driver: Initial getting ATR more robustly. * scd/ccid-driver.c (send_power_off): New. (do_close_reader): Use send_power_off. (ccid_get_atr): Add error recovery. GnuPG-bug-id: 4616 Signed-off-by: NIIBE Yutaka --- scd/ccid-driver.c | 57 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index e092a2b9a..f791c3ad5 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1717,31 +1717,37 @@ ccid_require_get_status (ccid_driver_t handle) return 1; } - -static void -do_close_reader (ccid_driver_t handle) +static int +send_power_off (ccid_driver_t handle) { int rc; unsigned char msg[100]; size_t msglen; unsigned char seqno; - if (!handle->powered_off) - { - msg[0] = PC_to_RDR_IccPowerOff; - msg[5] = 0; /* slot */ - msg[6] = seqno = handle->seqno++; - msg[7] = 0; /* RFU */ - msg[8] = 0; /* RFU */ - msg[9] = 0; /* RFU */ - set_msg_len (msg, 0); - msglen = 10; + msg[0] = PC_to_RDR_IccPowerOff; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; - rc = bulk_out (handle, msg, msglen, 0); - if (!rc) - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, - seqno, 2000, 0); - } + rc = bulk_out (handle, msg, msglen, 0); + if (!rc) + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, + seqno, 2000, 0); + return rc; +} + +static void +do_close_reader (ccid_driver_t handle) +{ + int rc; + + if (!handle->powered_off) + send_power_off (handle); if (handle->transfer) { @@ -2597,6 +2603,21 @@ ccid_get_atr (ccid_driver_t handle, NULL, 0, NULL)) goto again; } + else if (statusbits == 0 && CCID_COMMAND_FAILED (msg)) + { + /* Card was active already, and something went wrong with + PC_to_RDR_IccPowerOn command. It may be baud-rate mismatch + between the card and the reader. To recover from this state, + send PC_to_RDR_IccPowerOff command to reset the card and try + again. + */ + rc = send_power_off (handle); + if (rc) + return rc; + + statusbits = 1; + goto again; + } else if (CCID_COMMAND_FAILED (msg)) return CCID_DRIVER_ERR_CARD_IO_ERROR;