[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 3/8] usb-ccid: Set protocol parameters based on c
From: |
Stefan Fritsch |
Subject: |
[Qemu-devel] [PATCH v2 3/8] usb-ccid: Set protocol parameters based on card ATR |
Date: |
Thu, 20 Jul 2017 11:02:46 +0200 |
From: Stefan Fritsch <address@hidden>
For the ATR interface bytes encoding see ISO/IEC 7816-3. For the
interpretation of the protocol parameter block see the CCID
specification.
- Values that are not present in the ATR default to zero.
- TA_1 is used to fill bmFindexDindex.
- The high nibble of bmTCCKST0 must be the protocol (T=0 or T=1).
- For T=0 the bWaitingInteger can be found in the global byte TC_2,
for T=1 the waiting integer is in TB_3 and bIFSC is in TA_3.
Signed-off-by: Stefan Fritsch <address@hidden>
Signed-off-by: Christian Ehrhardt <address@hidden>
---
hw/usb/dev-smartcard-reader.c | 66 +++++++++++++++++++++++++++++++++++--------
1 file changed, 54 insertions(+), 12 deletions(-)
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 49791492ea..769949144b 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -801,7 +801,7 @@ static void ccid_write_parameters(USBCCIDState *s,
CCID_Header *recv)
return;
}
h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters;
- h->b.hdr.dwLength = 0;
+ h->b.hdr.dwLength = (s->bProtocolNum == 1) ? 7 : 5;
h->b.hdr.bSlot = recv->bSlot;
h->b.hdr.bSeq = recv->bSeq;
h->b.bStatus = ccid_calc_status(s);
@@ -871,6 +871,49 @@ static uint8_t atr_get_protocol_num(const uint8_t *atr,
uint32_t len)
return atr[i] & 0x0f;
}
+/*
+ * Get a specific interface byte TX_y (X='A'..'D' y=1..3)
+ * See ISO/IEC 7816-3:2006 Chapter 8 for details.
+ */
+static uint8_t atr_get_TXY(const uint8_t *atr, uint32_t len, char x, int y)
+{
+ int pos;
+ uint8_t t0, ti, i;
+
+ if (x < 'A' || x > 'D') {
+ return 0;
+ }
+ x -= 'A';
+
+ if (len < 2) {
+ return 0;
+ }
+ t0 = atr[1] >> 4;
+ pos = 2;
+ ti = 1;
+ /* Skip TA_i..TD_i if present while not at requested index y */
+ while (ti < y) {
+ pos += !!(t0 & 0x01) + !!(t0 & 0x02) + !!(t0 & 0x04);
+ if (pos >= len || !(t0 & 0x08)) {
+ return 0;
+ }
+ t0 = atr[pos++] >> 4;
+ ti++;
+ }
+ if (!(t0 & 0x01 << x)) {
+ return 0;
+ }
+ for (i = 0; i < x; ++i) {
+ if (t0 & (1 << i)) {
+ pos++;
+ }
+ }
+ if (pos >= len) {
+ return 0;
+ }
+ return atr[pos];
+}
+
static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
{
const uint8_t *atr = NULL;
@@ -890,21 +933,20 @@ static void ccid_write_data_block_atr(USBCCIDState *s,
CCID_Header *recv)
: s->bProtocolNum);
switch (atr_protocol_num) {
case 0:
- /* TODO: unimplemented ATR T0 parameters */
- t0->bmFindexDindex = 0;
- t0->bmTCCKST0 = 0;
+ t0->bmFindexDindex = atr_get_TXY(atr, len, 'A', 1);
+ t0->bmTCCKST0 = 0; /* T0 */
t0->bGuardTimeT0 = 0;
- t0->bWaitingIntegerT0 = 0;
+ t0->bWaitingIntegerT0 = atr_get_TXY(atr, len, 'C', 2);
t0->bClockStop = 0;
break;
case 1:
- /* TODO: unimplemented ATR T1 parameters */
- t1->bmFindexDindex = 0;
- t1->bmTCCKST1 = 0;
- t1->bGuardTimeT1 = 0;
- t1->bWaitingIntegerT1 = 0;
- t1->bClockStop = 0;
- t1->bIFSC = 0;
+ /* NOTE: If present TD2 should specify protocl T=1 */
+ t1->bmFindexDindex = atr_get_TXY(atr, len, 'A', 1);
+ t1->bmTCCKST1 = 0x10; /* T1 */
+ t1->bGuardTimeT1 = atr_get_TXY(atr, len, 'C', 1);
+ t1->bWaitingIntegerT1 = atr_get_TXY(atr, len, 'B', 3);
+ t1->bClockStop = 0x00;
+ t1->bIFSC = atr_get_TXY(atr, len, 'A', 3);
t1->bNadValue = 0;
break;
default:
--
2.11.0