aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-04-24 13:23:26 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-04-24 13:23:26 -0500
commit1bfffe21a686ab273abce5ef12e8d2a3de320023 (patch)
tree81c245e4096100d287192cd3fdb68f79529db851 /hw
parentf3aa844bbb2922a5b8393d17620eca7d7e921ab3 (diff)
parent57f97834efe0c208ffadc9d2959f3d3d55580e52 (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.c9
-rw-r--r--hw/usb/ccid-card-passthru.c63
-rw-r--r--hw/usb/dev-smartcard-reader.c243
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),