qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 3/8] usb-ccid: Set protocol parameters based


From: Marc-André Lureau
Subject: Re: [Qemu-devel] [PATCH v2 3/8] usb-ccid: Set protocol parameters based on card ATR
Date: Thu, 20 Jul 2017 09:35:02 +0000

On Thu, Jul 20, 2017 at 11:11 AM Stefan Fritsch <address@hidden> wrote:

> 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;
> +    }
>

or you could assert it, since it's compile time constant

(I have vague memories of parsing ATR, but the rest looks ok, it might be
worth to include tests for that function though)


> +    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
>
>
> --
Marc-André Lureau


reply via email to

[Prev in Thread] Current Thread [Next in Thread]