Revision 0e61400c

b/hw/usb/ccid-card-passthru.c
138 138
    ccid_card_vscard_send_init(card);
139 139
}
140 140

  
141
static int check_atr(PassthruState *card, uint8_t *data, int len)
142
{
143
    int historical_length, opt_bytes;
144
    int td_count = 0;
145
    int td;
146

  
147
    if (len < 2) {
148
        return 0;
149
    }
150
    historical_length = data[1] & 0xf;
151
    opt_bytes = 0;
152
    if (data[0] != 0x3b && data[0] != 0x3f) {
153
        DPRINTF(card, D_WARN, "atr's T0 is 0x%X, not in {0x3b, 0x3f}\n",
154
                data[0]);
155
        return 0;
156
    }
157
    td_count = 0;
158
    td = data[1] >> 4;
159
    while (td && td_count < 2 && opt_bytes + historical_length + 2 < len) {
160
        td_count++;
161
        if (td & 0x1) {
162
            opt_bytes++;
163
        }
164
        if (td & 0x2) {
165
            opt_bytes++;
166
        }
167
        if (td & 0x4) {
168
            opt_bytes++;
169
        }
170
        if (td & 0x8) {
171
            opt_bytes++;
172
            td = data[opt_bytes + 2] >> 4;
173
        }
174
    }
175
    if (len < 2 + historical_length + opt_bytes) {
176
        DPRINTF(card, D_WARN,
177
            "atr too short: len %d, but historical_len %d, T1 0x%X\n",
178
            len, historical_length, data[1]);
179
        return 0;
180
    }
181
    if (len > 2 + historical_length + opt_bytes) {
182
        DPRINTF(card, D_WARN,
183
            "atr too long: len %d, but hist/opt %d/%d, T1 0x%X\n",
184
            len, historical_length, opt_bytes, data[1]);
185
        /* let it through */
186
    }
187
    DPRINTF(card, D_VERBOSE,
188
            "atr passes check: %d total length, %d historical, %d optional\n",
189
            len, historical_length, opt_bytes);
190

  
191
    return 1;
192
}
193

  
141 194
static void ccid_card_vscard_handle_message(PassthruState *card,
142 195
    VSCMsgHeader *scr_msg_header)
143 196
{
......
152 205
                                        VSC_GENERAL_ERROR);
153 206
            break;
154 207
        }
208
        if (!check_atr(card, data, scr_msg_header->length)) {
209
            error_report("ATR is inconsistent, ignoring");
210
            ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
211
                                        VSC_GENERAL_ERROR);
212
            break;
213
        }
155 214
        memcpy(card->atr, data, scr_msg_header->length);
156 215
        card->atr_length = scr_msg_header->length;
157 216
        ccid_card_card_inserted(&card->base);

Also available in: Unified diff