diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-04-24 13:23:26 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-04-24 13:23:26 -0500 |
commit | 1bfffe21a686ab273abce5ef12e8d2a3de320023 (patch) | |
tree | 81c245e4096100d287192cd3fdb68f79529db851 /hw | |
parent | f3aa844bbb2922a5b8393d17620eca7d7e921ab3 (diff) | |
parent | 57f97834efe0c208ffadc9d2959f3d3d55580e52 (diff) |
Merge remote-tracking branch 'alon/libcacard_ccid.1' into staging
# By Alon Levy (15) and others
# Via Alon Levy
* alon/libcacard_ccid.1: (28 commits)
libcacard/cac: change big switch functions to single return point
dev-smartcard-reader: empty implementation for Mechanical (fail correctly)
libcacard: move atr setting from macro to function
libcacard/vreader: add debugging messages for apdu
dev-smartcard-reader: copy atr protocol to ccid parameters
dev-smartcard-reader: change default protocol to T=0
dev-smartcard-reader: define structs for CCID_Parameter internals
ccid-card-passthru, dev-smartcard-reader: add debug environment variables
ccid-card-passthru: add atr check
libcacard: change default ATR
dev-smartcard-reader: reuse usb.h definitions
dev-smartcard-reader: support windows guest
dev-smartcard-reader: remove aborts (never triggered, but just in case)
dev-smartcard-reader: nicer debug messages
dev-smartcard-reader: white space fixes
libcacard: remove default libcoolkey loading
libcacard: remove sql: prefix
libcacard: teach vscclient to use GMainLoop for portability
libcacard: vscclient to use QemuThread for portability
libcacard: split vscclient main() from socket reading
...
Message-id: 921423767.1475937.1366790789930.JavaMail.root@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/usb/ccid-card-emulated.c | 9 | ||||
-rw-r--r-- | hw/usb/ccid-card-passthru.c | 63 | ||||
-rw-r--r-- | hw/usb/dev-smartcard-reader.c | 243 |
3 files changed, 254 insertions, 61 deletions
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index d534c94c1a..094284d664 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -462,17 +462,20 @@ typedef struct EnumTable { uint32_t value; } EnumTable; -EnumTable backend_enum_table[] = { +static const EnumTable backend_enum_table[] = { {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED}, {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES}, {NULL, 0}, }; static uint32_t parse_enumeration(char *str, - EnumTable *table, uint32_t not_found_value) + const EnumTable *table, uint32_t not_found_value) { uint32_t ret = not_found_value; + if (str == NULL) + return 0; + while (table->name != NULL) { if (strcmp(table->name, str) == 0) { ret = table->value; @@ -487,7 +490,7 @@ static int emulated_initfn(CCIDCardState *base) { EmulatedState *card = DO_UPCAST(EmulatedState, base, base); VCardEmulError ret; - EnumTable *ptable; + const EnumTable *ptable; QSIMPLEQ_INIT(&card->event_list); QSIMPLEQ_INIT(&card->guest_apdu_list); diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index 71a45f674f..01c7e6f20d 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -27,7 +27,7 @@ do { \ #define D_VERBOSE 4 /* TODO: do we still need this? */ -uint8_t DEFAULT_ATR[] = { +static const uint8_t DEFAULT_ATR[] = { /* * From some example somewhere * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28 @@ -138,6 +138,59 @@ static void ccid_card_vscard_handle_init( ccid_card_vscard_send_init(card); } +static int check_atr(PassthruState *card, uint8_t *data, int len) +{ + int historical_length, opt_bytes; + int td_count = 0; + int td; + + if (len < 2) { + return 0; + } + historical_length = data[1] & 0xf; + opt_bytes = 0; + if (data[0] != 0x3b && data[0] != 0x3f) { + DPRINTF(card, D_WARN, "atr's T0 is 0x%X, not in {0x3b, 0x3f}\n", + data[0]); + return 0; + } + td_count = 0; + td = data[1] >> 4; + while (td && td_count < 2 && opt_bytes + historical_length + 2 < len) { + td_count++; + if (td & 0x1) { + opt_bytes++; + } + if (td & 0x2) { + opt_bytes++; + } + if (td & 0x4) { + opt_bytes++; + } + if (td & 0x8) { + opt_bytes++; + td = data[opt_bytes + 2] >> 4; + } + } + if (len < 2 + historical_length + opt_bytes) { + DPRINTF(card, D_WARN, + "atr too short: len %d, but historical_len %d, T1 0x%X\n", + len, historical_length, data[1]); + return 0; + } + if (len > 2 + historical_length + opt_bytes) { + DPRINTF(card, D_WARN, + "atr too long: len %d, but hist/opt %d/%d, T1 0x%X\n", + len, historical_length, opt_bytes, data[1]); + /* let it through */ + } + DPRINTF(card, D_VERBOSE, + "atr passes check: %d total length, %d historical, %d optional\n", + len, historical_length, opt_bytes); + + return 1; +} + static void ccid_card_vscard_handle_message(PassthruState *card, VSCMsgHeader *scr_msg_header) { @@ -152,6 +205,12 @@ static void ccid_card_vscard_handle_message(PassthruState *card, VSC_GENERAL_ERROR); break; } + if (!check_atr(card, data, scr_msg_header->length)) { + error_report("ATR is inconsistent, ignoring"); + ccid_card_vscard_send_error(card, scr_msg_header->reader_id, + VSC_GENERAL_ERROR); + break; + } memcpy(card->atr, data, scr_msg_header->length); card->atr_length = scr_msg_header->length; ccid_card_card_inserted(&card->base); @@ -291,6 +350,8 @@ static int passthru_initfn(CCIDCardState *base) error_report("missing chardev"); return -1; } + card->debug = parse_debug_env("QEMU_CCID_PASSTHRU_DEBUG", D_VERBOSE, + card->debug); assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE); memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR)); card->atr_length = sizeof(DEFAULT_ATR); diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index db8ce02151..125cc2c221 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -68,12 +68,6 @@ do { \ #define BULK_IN_BUF_SIZE 384 #define BULK_IN_PENDING_NUM 8 -#define InterfaceOutClass \ - ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8) - -#define InterfaceInClass \ - ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)<<8) - #define CCID_MAX_PACKET_SIZE 64 #define CCID_CONTROL_ABORT 0x1 @@ -195,10 +189,34 @@ typedef struct QEMU_PACKED CCID_SlotStatus { uint8_t bClockStatus; } CCID_SlotStatus; +typedef struct QEMU_PACKED CCID_T0ProtocolDataStructure { + uint8_t bmFindexDindex; + uint8_t bmTCCKST0; + uint8_t bGuardTimeT0; + uint8_t bWaitingIntegerT0; + uint8_t bClockStop; +} CCID_T0ProtocolDataStructure; + +typedef struct QEMU_PACKED CCID_T1ProtocolDataStructure { + uint8_t bmFindexDindex; + uint8_t bmTCCKST1; + uint8_t bGuardTimeT1; + uint8_t bWaitingIntegerT1; + uint8_t bClockStop; + uint8_t bIFSC; + uint8_t bNadValue; +} CCID_T1ProtocolDataStructure; + +typedef union CCID_ProtocolDataStructure { + CCID_T0ProtocolDataStructure t0; + CCID_T1ProtocolDataStructure t1; + uint8_t data[7]; /* must be = max(sizeof(t0), sizeof(t1)) */ +} CCID_ProtocolDataStructure; + typedef struct QEMU_PACKED CCID_Parameter { CCID_BULK_IN b; uint8_t bProtocolNum; - uint8_t abProtocolDataStructure[0]; + CCID_ProtocolDataStructure abProtocolDataStructure; } CCID_Parameter; typedef struct QEMU_PACKED CCID_DataBlock { @@ -230,7 +248,7 @@ typedef struct QEMU_PACKED CCID_SetParameters { CCID_Header hdr; uint8_t bProtocolNum; uint16_t abRFU; - uint8_t abProtocolDataStructure[0]; + CCID_ProtocolDataStructure abProtocolDataStructure; } CCID_SetParameters; typedef struct CCID_Notify_Slot_Change { @@ -260,8 +278,6 @@ typedef struct CCIDBus { BusState qbus; } CCIDBus; -#define MAX_PROTOCOL_SIZE 7 - /* * powered - defaults to true, changed by PowerOn/PowerOff messages */ @@ -285,7 +301,7 @@ typedef struct USBCCIDState { uint8_t bError; uint8_t bmCommandStatus; uint8_t bProtocolNum; - uint8_t abProtocolDataStructure[MAX_PROTOCOL_SIZE]; + CCID_ProtocolDataStructure abProtocolDataStructure; uint32_t ulProtocolDataStructureSize; uint32_t state_vmstate; uint32_t migration_target_ip; @@ -319,8 +335,8 @@ static const uint8_t qemu_ccid_descriptor[] = { */ 0x07, /* u8 bVoltageSupport; 01h - 5.0v, 02h - 3.0, 03 - 1.8 */ - 0x03, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/ - 0x00, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */ + 0x00, 0x00, /* u32 dwProtocols; RRRR PPPP. RRRR = 0000h.*/ + 0x01, 0x00, /* PPPP: 0001h = Protocol T=0, 0002h = Protocol T=1 */ /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */ 0xa0, 0x0f, 0x00, 0x00, /* u32 dwMaximumClock; */ @@ -359,11 +375,11 @@ static const uint8_t qemu_ccid_descriptor[] = { * 20000 Short APDU level exchange with CCID * 40000 Short and Extended APDU level exchange with CCID * - * + 100000 USB Wake up signaling supported on card + * 100000 USB Wake up signaling supported on card * insertion and removal. Must set bit 5 in bmAttributes * in Configuration descriptor if 100000 is set. */ - 0xfe, 0x04, 0x11, 0x00, + 0xfe, 0x04, 0x01, 0x00, /* * u32 dwMaxCCIDMessageLength; For extended APDU in * [261 + 10 , 65544 + 10]. Otherwise the minimum is @@ -410,8 +426,8 @@ static const USBDescStrings desc_strings = { static const USBDescIface desc_iface0 = { .bInterfaceNumber = 0, .bNumEndpoints = 3, - .bInterfaceClass = 0x0b, - .bInterfaceSubClass = 0x00, + .bInterfaceClass = USB_CLASS_CSCID, + .bInterfaceSubClass = USB_SUBCLASS_UNDEFINED, .bInterfaceProtocol = 0x00, .iInterface = STR_INTERFACE, .ndesc = 1, @@ -471,6 +487,7 @@ static const USBDesc desc_ccid = { static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len) { CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->get_atr) { return cc->get_atr(card, len); } @@ -482,6 +499,7 @@ static void ccid_card_apdu_from_guest(CCIDCardState *card, uint32_t len) { CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->apdu_from_guest) { cc->apdu_from_guest(card, apdu, len); } @@ -490,6 +508,7 @@ static void ccid_card_apdu_from_guest(CCIDCardState *card, static int ccid_card_exitfn(CCIDCardState *card) { CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->exitfn) { return cc->exitfn(card); } @@ -499,6 +518,7 @@ static int ccid_card_exitfn(CCIDCardState *card) static int ccid_card_initfn(CCIDCardState *card) { CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->initfn) { return cc->initfn(card); } @@ -635,13 +655,47 @@ static void ccid_handle_reset(USBDevice *dev) ccid_reset(s); } +static const char *ccid_control_to_str(USBCCIDState *s, int request) +{ + switch (request) { + /* generic - should be factored out if there are other debugees */ + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + return "(generic) set address"; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + return "(generic) get descriptor"; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + return "(generic) get configuration"; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + return "(generic) set configuration"; + case DeviceRequest | USB_REQ_GET_STATUS: + return "(generic) get status"; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + return "(generic) clear feature"; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + return "(generic) set_feature"; + case InterfaceRequest | USB_REQ_GET_INTERFACE: + return "(generic) get interface"; + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + return "(generic) set interface"; + /* class requests */ + case ClassInterfaceOutRequest | CCID_CONTROL_ABORT: + return "ABORT"; + case ClassInterfaceRequest | CCID_CONTROL_GET_CLOCK_FREQUENCIES: + return "GET_CLOCK_FREQUENCIES"; + case ClassInterfaceRequest | CCID_CONTROL_GET_DATA_RATES: + return "GET_DATA_RATES"; + } + return "unknown"; +} + static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); int ret; - DPRINTF(s, 1, "got control %x, value %x\n", request, value); + DPRINTF(s, 1, "%s: got control %s (%x), value %x\n", __func__, + ccid_control_to_str(s, request), request, value); ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { return; @@ -649,15 +703,15 @@ static void ccid_handle_control(USBDevice *dev, USBPacket *p, int request, switch (request) { /* Class specific requests. */ - case InterfaceOutClass | CCID_CONTROL_ABORT: + case ClassInterfaceOutRequest | CCID_CONTROL_ABORT: DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n"); p->status = USB_RET_STALL; break; - case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES: + case ClassInterfaceRequest | CCID_CONTROL_GET_CLOCK_FREQUENCIES: DPRINTF(s, 1, "ccid_control get clock frequencies UNIMPLEMENTED\n"); p->status = USB_RET_STALL; break; - case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES: + case ClassInterfaceRequest | CCID_CONTROL_GET_DATA_RATES: DPRINTF(s, 1, "ccid_control get data rates UNIMPLEMENTED\n"); p->status = USB_RET_STALL; break; @@ -691,7 +745,7 @@ static uint8_t ccid_calc_status(USBCCIDState *s) * bmCommandStatus */ uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6); - DPRINTF(s, D_VERBOSE, "status = %d\n", ret); + DPRINTF(s, D_VERBOSE, "%s: status = %d\n", __func__, ret); return ret; } @@ -733,7 +787,7 @@ static void ccid_write_parameters(USBCCIDState *s, CCID_Header *recv) h->b.bStatus = ccid_calc_status(s); h->b.bError = s->bError; h->bProtocolNum = s->bProtocolNum; - memcpy(h->abProtocolDataStructure, s->abProtocolDataStructure, len); + h->abProtocolDataStructure = s->abProtocolDataStructure; ccid_reset_error_status(s); } @@ -752,12 +806,18 @@ static void ccid_write_data_block(USBCCIDState *s, uint8_t slot, uint8_t seq, p->b.bStatus = ccid_calc_status(s); p->b.bError = s->bError; if (p->b.bError) { - DPRINTF(s, D_VERBOSE, "error %d", p->b.bError); + DPRINTF(s, D_VERBOSE, "error %d\n", p->b.bError); } memcpy(p->abData, data, len); ccid_reset_error_status(s); } +static void ccid_report_error_failed(USBCCIDState *s, uint8_t error) +{ + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->bError = error; +} + static void ccid_write_data_block_answer(USBCCIDState *s, const uint8_t *data, uint32_t len) { @@ -765,64 +825,103 @@ static void ccid_write_data_block_answer(USBCCIDState *s, uint8_t slot; if (!ccid_has_pending_answers(s)) { - abort(); + DPRINTF(s, D_WARN, "error: no pending answer to return to guest\n"); + ccid_report_error_failed(s, ERROR_ICC_MUTE); + return; } ccid_remove_pending_answer(s, &slot, &seq); ccid_write_data_block(s, slot, seq, data, len); } +static uint8_t atr_get_protocol_num(const uint8_t *atr, uint32_t len) +{ + int i; + + if (len < 2 || !(atr[1] & 0x80)) { + /* too short or TD1 not included */ + return 0; /* T=0, default */ + } + i = 1 + !!(atr[1] & 0x10) + !!(atr[1] & 0x20) + !!(atr[1] & 0x40); + i += !!(atr[1] & 0x80); + return atr[i] & 0x0f; +} + static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv) { const uint8_t *atr = NULL; uint32_t len = 0; + uint8_t atr_protocol_num; + CCID_T0ProtocolDataStructure *t0 = &s->abProtocolDataStructure.t0; + CCID_T1ProtocolDataStructure *t1 = &s->abProtocolDataStructure.t1; if (s->card) { atr = ccid_card_get_atr(s->card, &len); } + atr_protocol_num = atr_get_protocol_num(atr, len); + DPRINTF(s, D_VERBOSE, "%s: atr contains protocol=%d\n", __func__, + atr_protocol_num); + /* set parameters from ATR - see spec page 109 */ + s->bProtocolNum = (atr_protocol_num <= 1 ? atr_protocol_num + : s->bProtocolNum); + switch (atr_protocol_num) { + case 0: + /* TODO: unimplemented ATR T0 parameters */ + t0->bmFindexDindex = 0; + t0->bmTCCKST0 = 0; + t0->bGuardTimeT0 = 0; + t0->bWaitingIntegerT0 = 0; + 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; + t1->bNadValue = 0; + break; + default: + DPRINTF(s, D_WARN, "%s: error: unsupported ATR protocol %d\n", + __func__, atr_protocol_num); + } ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len); } static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv) { CCID_SetParameters *ph = (CCID_SetParameters *) recv; - uint32_t len = 0; - if ((ph->bProtocolNum & 3) == 0) { - len = 5; - } - if ((ph->bProtocolNum & 3) == 1) { - len = 7; - } - if (len == 0) { - s->bmCommandStatus = COMMAND_STATUS_FAILED; - s->bError = 7; /* Protocol invalid or not supported */ + uint32_t protocol_num = ph->bProtocolNum & 3; + + if (protocol_num != 0 && protocol_num != 1) { + ccid_report_error_failed(s, ERROR_CMD_NOT_SUPPORTED); return; } - s->bProtocolNum = ph->bProtocolNum; - memcpy(s->abProtocolDataStructure, ph->abProtocolDataStructure, len); - s->ulProtocolDataStructureSize = len; - DPRINTF(s, 1, "%s: using len %d\n", __func__, len); + s->bProtocolNum = protocol_num; + s->abProtocolDataStructure = ph->abProtocolDataStructure; } /* * must be 5 bytes for T=0, 7 bytes for T=1 * See page 52 */ -static const uint8_t abDefaultProtocolDataStructure[7] = { - 0x77, 0x00, 0x00, 0x00, 0x00, 0xfe /*IFSC*/, 0x00 /*NAD*/ }; +static const CCID_ProtocolDataStructure defaultProtocolDataStructure = { + .t1 = { + .bmFindexDindex = 0x77, + .bmTCCKST1 = 0x00, + .bGuardTimeT1 = 0x00, + .bWaitingIntegerT1 = 0x00, + .bClockStop = 0x00, + .bIFSC = 0xfe, + .bNadValue = 0x00, + } +}; static void ccid_reset_parameters(USBCCIDState *s) { - uint32_t len = sizeof(abDefaultProtocolDataStructure); - - s->bProtocolNum = 1; /* T=1 */ - s->ulProtocolDataStructureSize = len; - memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len); -} - -static void ccid_report_error_failed(USBCCIDState *s, uint8_t error) -{ - s->bmCommandStatus = COMMAND_STATUS_FAILED; - s->bError = error; + s->bProtocolNum = 0; /* T=0 */ + s->abProtocolDataStructure = defaultProtocolDataStructure; } /* NOTE: only a single slot is supported (SLOT_0) */ @@ -869,6 +968,28 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv) } } +static const char *ccid_message_type_to_str(uint8_t type) +{ + switch (type) { + case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn: return "IccPowerOn"; + case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff: return "IccPowerOff"; + case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus: return "GetSlotStatus"; + case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock: return "XfrBlock"; + case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters: return "GetParameters"; + case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters: return "ResetParameters"; + case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters: return "SetParameters"; + case CCID_MESSAGE_TYPE_PC_to_RDR_Escape: return "Escape"; + case CCID_MESSAGE_TYPE_PC_to_RDR_IccClock: return "IccClock"; + case CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU: return "T0APDU"; + case CCID_MESSAGE_TYPE_PC_to_RDR_Secure: return "Secure"; + case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical: return "Mechanical"; + case CCID_MESSAGE_TYPE_PC_to_RDR_Abort: return "Abort"; + case CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency: + return "SetDataRateAndClockFrequency"; + } + return "unknown"; +} + static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) { CCID_Header *ccid_header; @@ -891,13 +1012,15 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n", __func__); } else { - DPRINTF(s, D_MORE_INFO, "%s %x\n", __func__, ccid_header->bMessageType); + DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__, + ccid_header->bMessageType, + ccid_message_type_to_str(ccid_header->bMessageType)); switch (ccid_header->bMessageType) { case CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus: ccid_write_slot_status(s, ccid_header); break; case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn: - DPRINTF(s, 1, "PowerOn: %d\n", + DPRINTF(s, 1, "%s: PowerOn: %d\n", __func__, ((CCID_IccPowerOn *)(ccid_header))->bPowerSelect); s->powered = true; if (!ccid_card_inserted(s)) { @@ -907,7 +1030,6 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) ccid_write_data_block_atr(s, ccid_header); break; case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff: - DPRINTF(s, 1, "PowerOff\n"); ccid_reset_error_status(s); s->powered = false; ccid_write_slot_status(s, ccid_header); @@ -929,6 +1051,10 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) ccid_reset_error_status(s); ccid_write_parameters(s, ccid_header); break; + case CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical: + ccid_report_error_failed(s, 0); + ccid_write_slot_status(s, ccid_header); + break; default: DPRINTF(s, 1, "handle_data: ERROR: unhandled message type %Xh\n", @@ -1068,7 +1194,9 @@ void ccid_card_send_apdu_to_guest(CCIDCardState *card, s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; answer = ccid_peek_next_answer(s); if (answer == NULL) { - abort(); + DPRINTF(s, D_WARN, "%s: error: unexpected lack of answer\n", __func__); + ccid_report_error_failed(s, ERROR_HW_ERROR); + return; } DPRINTF(s, 1, "APDU returned to guest %d (answer seq %d, slot %d)\n", len, answer->seq, answer->slot); @@ -1201,6 +1329,7 @@ static int ccid_initfn(USBDevice *dev) s->bulk_out_pos = 0; ccid_reset_parameters(s); ccid_reset(s); + s->debug = parse_debug_env("QEMU_CCID_DEBUG", D_VERBOSE, s->debug); return 0; } @@ -1285,7 +1414,7 @@ static VMStateDescription ccid_vmstate = { VMSTATE_UINT8(bError, USBCCIDState), VMSTATE_UINT8(bmCommandStatus, USBCCIDState), VMSTATE_UINT8(bProtocolNum, USBCCIDState), - VMSTATE_BUFFER(abProtocolDataStructure, USBCCIDState), + VMSTATE_BUFFER(abProtocolDataStructure.data, USBCCIDState), VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState), VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState, BULK_IN_PENDING_NUM, 1, bulk_in_vmstate, BulkIn), |