diff options
| -rw-r--r-- | hw/usb-ccid.c | 286 | ||||
| -rw-r--r-- | vscard_common.h | 118 |
2 files changed, 292 insertions, 112 deletions
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 1fd028cb7..2d50f9444 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -1,19 +1,29 @@ /* * CCID Device emulation * + * Based on usb-serial.c: * Copyright (c) 2006 CodeSourcery. * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org> - * Copyright (c) 2010 Red Hat. * Written by Paul Brook, reused for FTDI by Samuel Thibault, * reused for CCID by Alon Levy. + * Copyright (c) 2010 Red Hat. * * This code is licenced under the LGPL. */ +/* References: + * + * CCID Specification Revision 1.1 April 22nd 2005 + * "Universal Serial Bus, Device Class: Smart Card" + * Specification for Integrated Circuit(s) Cards Interface Devices + * + */ + /* TODO * - * Discard additional answers - * Don't change answer while sending a multiple packet BULK_IN (answer_len > single_packet_len == 64) + * Discard additional answers (only one outstanding question per slot at a time + * according to spec). Don't change answer while sending a multiple packet + * BULK_IN (answer_len > single_packet_len == 64) * */ @@ -22,7 +32,7 @@ #include "usb.h" #include "qemu-char.h" -#include "scard_common.h" +#include "vscard_common.h" #define DEBUG_CCID @@ -35,8 +45,8 @@ do { printf("usb-ccid: " fmt , ## __VA_ARGS__); } while (0) #define RECV_BUF 384 -#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) -#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) +#define DeviceOutVendor ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) +#define DeviceInVendor ((USB_DIR_IN |USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8) #define CCID_CONTROL_ABORT 0x1 #define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x2 @@ -44,15 +54,15 @@ do { printf("usb-ccid: " fmt , ## __VA_ARGS__); } while (0) #define IMPERSONATE_ATHENA #ifdef IMPERSONATE_ATHENA -#define CCID_PRODUCT_DESCRIPTION "ASEDrive CCID" -#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION -#define CCID_INTERFACE_NAME "CCID Interface" -#define CCID_SERIAL_NUMBER_STRING "ASE016" +#define CCID_PRODUCT_DESCRIPTION "ASEDrive CCID" +#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION +#define CCID_INTERFACE_NAME "CCID Interface" +#define CCID_SERIAL_NUMBER_STRING "ASE016" #else -#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID" -#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION -#define CCID_INTERFACE_NAME "CCID Interface" -#define CCID_SERIAL_NUMBER_STRING "1" +#define CCID_PRODUCT_DESCRIPTION "QEMU USB CCID" +#define CCID_VENDOR_DESCRIPTION "QEMU " QEMU_VERSION +#define CCID_INTERFACE_NAME "CCID Interface" +#define CCID_SERIAL_NUMBER_STRING "1" #endif // BULK_OUT messages from PC to Reader @@ -89,9 +99,9 @@ do { printf("usb-ccid: " fmt , ## __VA_ARGS__); } while (0) // To support slot insertion and removal we must have an interrupt in ep // in addition we need a bulk in and bulk out ep // 5.2, page 20 -#define CCID_INT_IN_EP 1 -#define CCID_BULK_IN_EP 2 -#define CCID_BULK_OUT_EP 3 +#define CCID_INT_IN_EP 1 +#define CCID_BULK_IN_EP 2 +#define CCID_BULK_OUT_EP 3 // bmSlotICCState masks #define SLOT_0_STATE_MASK 1 @@ -116,17 +126,18 @@ enum { // to transmit. #define ERROR_NONE 0 enum { - ERROR_CMD_ABORTED = -1, - ERROR_ICC_MUTE = -2, - ERROR_XFR_PARITY_ERROR = -3, - ERROR_XFR_OVERRUN = -4, - ERROR_HW_ERROR = -5, + ERROR_CMD_ABORTED = -1, + ERROR_ICC_MUTE = -2, + ERROR_XFR_PARITY_ERROR = -3, + ERROR_XFR_OVERRUN = -4, + ERROR_HW_ERROR = -5, }; // 6.2.6 RDR_to_PC_SlotStatus definitions enum { - CLOCK_STATUS_RUNNING=0, - // 0 - Clock Running, 1 - Clock stopped in State L, 2 - H, 3 - unkonwn state. rest are RFU + CLOCK_STATUS_RUNNING = 0, + // 0 - Clock Running, 1 - Clock stopped in State L, 2 - H, + // 3 - unkonwn state. rest are RFU }; typedef struct __attribute__ ((__packed__)) { @@ -184,8 +195,8 @@ typedef struct { uint8_t bmSlotICCState; } CCID_Notify_Slot_Change; -#define MAX_ATR_SIZE 40 -#define MAX_PROTOCOL_SIZE 7 +#define MAX_ATR_SIZE 40 +#define MAX_PROTOCOL_SIZE 7 typedef struct { USBDevice dev; CharDriverState *cs; @@ -205,6 +216,7 @@ typedef struct { uint8_t bProtocolNum; uint8_t abProtocolDataStructure[MAX_PROTOCOL_SIZE]; uint32_t ulProtocolDataStructureSize; + bool got_reader_add_message; } USBCCIDState; /* Slot specific variables. We emulate a single slot card reader. @@ -221,10 +233,11 @@ uint8_t DEFAULT_ATR[] = { /* CCID Spec chapter 4: CCID uses a standard device descriptor per Chapter 9, - * "USB Device Framework", section 9.6.1, in the Universal Serial Bus Specification. + * "USB Device Framework", section 9.6.1, in the Universal Serial Bus + * Specification. * - * This device implemented based on the spec and with an Athena Smart Card Reader - * as reference: + * This device implemented based on the spec and with an Athena Smart Card + * Reader as reference: * 0dc3:1004 Athena Smartcard Solutions, Inc. */ @@ -347,55 +360,60 @@ static const uint8_t qemu_ccid_config_descriptor[] = { /* Interrupt-IN endpoint */ 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ - 0x80 | CCID_INT_IN_EP, /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + /* u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, + /* u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x80 | CCID_INT_IN_EP, 0x03, /* u8 ep_bmAttributes; Interrupt */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0xff, /* u8 ep_bInterval; */ /* Bulk-In endpoint */ 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ - 0x80 | CCID_BULK_IN_EP, /* u8 ep_bEndpointAddress; IN Endpoint 2 */ + /* u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, + /* u8 ep_bEndpointAddress; IN Endpoint 2 */ + 0x80 | CCID_BULK_IN_EP, 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ /* Bulk-Out endpoint */ 0x07, /* u8 ep_bLength; */ - USB_DT_ENDPOINT, /* u8 ep_bDescriptorType; Endpoint */ - CCID_BULK_OUT_EP, /* u8 ep_bEndpointAddress; OUT Endpoint 3 */ + /* u8 ep_bDescriptorType; Endpoint */ + USB_DT_ENDPOINT, + /* u8 ep_bEndpointAddress; OUT Endpoint 3 */ + CCID_BULK_OUT_EP, 0x02, /* u8 ep_bmAttributes; Bulk */ 0x40, 0x00, /* u16 ep_wMaxPacketSize; */ 0x00, /* u8 ep_bInterval; */ }; -static void usb_ccid_reset(USBCCIDState *s) +static void ccid_reset(USBCCIDState *s) { - /* TODO: Set flow control to none */ s->recv_ptr = 0; s->recv_used = 0; - /* TODO: purge in char driver */ + s->got_reader_add_message = false; } -static void usb_ccid_handle_reset(USBDevice *dev) +static void ccid_handle_reset(USBDevice *dev) { USBCCIDState *s = (USBCCIDState *)dev; DPRINTF("Reset\n"); - usb_ccid_reset(s); - /* TODO: Reset char device, send BREAK? */ + ccid_reset(s); + /* TODO: Reset qemu chardev, send BREAK? SCMsg? */ } -static int usb_ccid_handle_control(USBDevice *dev, int request, int value, +static int ccid_handle_control(USBDevice *dev, int request, int value, int index, int length, uint8_t *data) { //USBCCIDState *s = (USBCCIDState *)dev; int ret = 0; - //DPRINTF("got control %x, value %x\n",request, value); + DPRINTF("got control %x, value %x\n",request, value); switch (request) { case DeviceRequest | USB_REQ_GET_STATUS: data[0] = (0 << USB_DEVICE_SELF_POWERED) | @@ -434,16 +452,6 @@ static int usb_ccid_handle_control(USBDevice *dev, int request, int value, memcpy(data, qemu_ccid_config_descriptor, sizeof(qemu_ccid_config_descriptor)); ret = sizeof(qemu_ccid_config_descriptor); - /* I got a request with size 8 - even though the - * basic descriptor is size 9. So handle it correctly. - * byte zero is the length*/ - /* BROKEN - TODO? - if (length < data[0]) { - DPRINTF("Adjusting length of descriptor to requested length\n"); - data[0] = length; - ret = length; - } - */ break; case USB_DT_STRING: switch(value & 0xff) { @@ -500,15 +508,15 @@ static int usb_ccid_handle_control(USBDevice *dev, int request, int value, /* Class specific requests. */ case DeviceOutVendor | CCID_CONTROL_ABORT: - DPRINTF("ccid_control abort\n"); + DPRINTF("ccid_control abort UNIMPLEMENTED\n"); ret = USB_RET_STALL; break; case DeviceOutVendor | CCID_CONTROL_GET_CLOCK_FREQUENCIES: - DPRINTF("ccid_control get clock frequencies\n"); + DPRINTF("ccid_control get clock frequencies UNIMPLEMENTED\n"); ret = USB_RET_STALL; break; case DeviceOutVendor | CCID_CONTROL_GET_DATA_RATES: - DPRINTF("ccid_control get data rates\n"); + DPRINTF("ccid_control get data rates UNIMPLEMENTED\n"); ret = USB_RET_STALL; break; default: @@ -523,7 +531,8 @@ static int usb_ccid_handle_control(USBDevice *dev, int request, int value, static uint8_t* ccid_reserve_recv_buf(USBCCIDState* s, uint16_t len) { if (len + s->recv_used > RECV_BUF) { - printf("usb-ccid.c: %s: overflow of receive buf. bailing out.\n", __func__); + printf("usb-ccid.c: %s: overflow of receive buf. bailing out.\n", + __func__); exit(-1); } if (s->recv_used == 0) { @@ -533,16 +542,19 @@ static uint8_t* ccid_reserve_recv_buf(USBCCIDState* s, uint16_t len) return s->recv_buf + s->recv_ptr; } -static bool usb_ccid_card_inserted(USBCCIDState *s) +static bool ccid_card_inserted(USBCCIDState *s) { return s->bmSlotICCState & SLOT_0_STATE_MASK; } -static uint8_t usb_ccid_calc_status(USBCCIDState *s) +static uint8_t ccid_calc_status(USBCCIDState *s) { - // page 55, 6.2.6, calculation of bStatus from bmICCStatus and bmCommandStatus - return (usb_ccid_card_inserted(s) ? ICC_STATUS_PRESENT_ACTIVE : ICC_STATUS_NOT_PRESENT) - | (s->bmCommandStatus << 6); + // page 55, 6.2.6, calculation of bStatus from bmICCStatus and + // bmCommandStatus + return (ccid_card_inserted(s) + ? ICC_STATUS_PRESENT_ACTIVE + : ICC_STATUS_NOT_PRESENT) + | (s->bmCommandStatus << 6); } static void ccid_reset_error_status(USBCCIDState* s) @@ -558,7 +570,7 @@ static void ccid_write_slot_status(USBCCIDState* s, CCID_Header* recv) h->b.hdr.dwLength = 0; h->b.hdr.bSlot = recv->bSlot; h->b.hdr.bSeq = recv->bSeq; - h->b.bStatus = usb_ccid_calc_status(s); + h->b.bStatus = ccid_calc_status(s); h->b.bError = s->bError; h->bClockStatus = CLOCK_STATUS_RUNNING; ccid_reset_error_status(s); @@ -574,7 +586,7 @@ static void ccid_write_parameters(USBCCIDState* s, CCID_Header* recv) h->b.hdr.dwLength = 0; h->b.hdr.bSlot = recv->bSlot; h->b.hdr.bSeq = recv->bSeq; - h->b.bStatus = usb_ccid_calc_status(s); + h->b.bStatus = ccid_calc_status(s); h->b.bError = s->bError; h->bProtocolNum = s->bProtocolNum; memcpy(h->abProtocolDataStructure,s->abProtocolDataStructure, len); @@ -595,7 +607,7 @@ static void ccid_write_data_block( p->b.hdr.dwLength = len; p->b.hdr.bSlot = slot; p->b.hdr.bSeq = seq; - p->b.bStatus = usb_ccid_calc_status(s); + p->b.bStatus = ccid_calc_status(s); p->b.bError = s->bError; memcpy(p->abData, data, len); ccid_reset_error_status(s); @@ -643,7 +655,7 @@ static void ccid_reset_parameters(USBCCIDState *s) memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len); } -static void usb_ccid_on_slot_change(USBCCIDState* s, bool full) +static void ccid_on_slot_change(USBCCIDState* s, bool full) { // RDR_to_PC_NotifySlotChange, 6.3.1 page 56 uint8_t current = s->bmSlotICCState; @@ -658,20 +670,52 @@ static void usb_ccid_on_slot_change(USBCCIDState* s, bool full) s->notify_slot_change = true; } -static void ccid_write_data_block_error(USBCCIDState *s, uint8_t slot, uint8_t seq) +static void ccid_write_data_block_error( + USBCCIDState *s, uint8_t slot, uint8_t seq) { ccid_write_data_block(s, slot, seq, NULL, 0); } +static void ccid_vscard_send_msg( + USBCCIDState *s, VSCMsgType type, uint32_t reader_id, + uint8_t* payload, uint32_t length) +{ + VSCMsgHeader scr_msg_header; + scr_msg_header.type = type; + scr_msg_header.reader_id = reader_id; + scr_msg_header.length = length; + qemu_chr_write(s->cs, (uint8_t*)&scr_msg_header, sizeof(VSCMsgHeader)); + qemu_chr_write(s->cs, payload, length); +} + +static void ccid_vscard_send_apdu( + USBCCIDState *s, uint8_t* apdu, uint32_t length) +{ + ccid_vscard_send_msg(s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length); +} + +static void ccid_vscard_send_error( + USBCCIDState *s, uint32_t reader_id, VSCErrorCode code) +{ + VSCMsgError msg = {.code=code}; + ccid_vscard_send_msg(s, VSC_Error, reader_id, (uint8_t*)&msg, sizeof(msg)); +} + +static void ccid_vscard_send_init(USBCCIDState *s) +{ + VSCMsgInit msg = {.version=VSCARD_VERSION}; + ccid_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID, + (uint8_t*)&msg, sizeof(msg)); +} + static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock* recv) { - static SCRMsgHeader scr_msg_header; if (!s->cs) { printf("usb-ccid: discarding apdu length %d\n", recv->hdr.dwLength); return; // XXX - dummy mode for testing, or just have the whole virtual card here. } - if (!usb_ccid_card_inserted(s)) { + if (!ccid_card_inserted(s)) { printf("usb-ccid: not sending apdu to client, no card connected\n"); ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq); return; @@ -679,15 +723,11 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock* recv) s->answer_slot = recv->hdr.bSlot; s->answer_seq = recv->hdr.bSeq; printf("usb-ccid: apdu_from_guest %d: len %d\n", recv->hdr.bSeq, recv->hdr.dwLength); - scr_msg_header.type = SCard_APDU; - scr_msg_header.nLength = recv->hdr.dwLength; - // send request to remote card - qemu_chr_write(s->cs, (uint8_t*)&scr_msg_header, sizeof(SCRMsgHeader)); - qemu_chr_write(s->cs, recv->abData, recv->hdr.dwLength); + ccid_vscard_send_apdu(s, recv->abData, recv->hdr.dwLength); s->waiting_for_answer = true; } -static void usb_ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) +static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) { static uint8_t data[70000]; // TODO - set to correct max size of packet. static uint32_t len = 0; @@ -737,7 +777,7 @@ static void usb_ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) len = 0; } -static int usb_ccid_handle_data(USBDevice *dev, USBPacket *p) +static int ccid_handle_data(USBDevice *dev, USBPacket *p) { USBCCIDState *s = (USBCCIDState *)dev; int ret = 0; @@ -763,7 +803,7 @@ static int usb_ccid_handle_data(USBDevice *dev, USBPacket *p) switch (p->pid) { case USB_TOKEN_OUT: - usb_ccid_handle_bulk_out(s, p); + ccid_handle_bulk_out(s, p); break; case USB_TOKEN_IN: @@ -812,7 +852,7 @@ static int usb_ccid_handle_data(USBDevice *dev, USBPacket *p) return ret; } -static void usb_ccid_handle_destroy(USBDevice *dev) +static void ccid_handle_destroy(USBDevice *dev) { USBCCIDState *s = (USBCCIDState *)dev; @@ -823,63 +863,73 @@ static void usb_ccid_handle_destroy(USBDevice *dev) /* APDU chardev */ -static int usb_ccid_scard_can_read(void *opaque) +static int ccid_scard_can_read(void *opaque) { //USBCCIDState *s = opaque; return 70000; // XXX number has meaning, or just positive for yes? } -static void usb_ccid_scard_read(void *opaque, const uint8_t *buf, int size) +static void ccid_vscard_read(void *opaque, const uint8_t *buf, int size) { static uint8_t readbuf[10000]; static uint32_t readpos = 0; USBCCIDState *s = opaque; - const SCRMsgHeader* scr_msg_header = (const SCRMsgHeader*)readbuf; - const uint8_t* data = readbuf + sizeof(SCRMsgHeader); + const VSCMsgHeader* scr_msg_header = (const VSCMsgHeader*)readbuf; + const uint8_t* data = readbuf + sizeof(VSCMsgHeader); uint32_t available = size + readpos; assert(readpos + size <= sizeof(readbuf)); memcpy(readbuf + readpos, buf, size); readpos += size; - if (available - sizeof(SCRMsgHeader) < scr_msg_header->nLength) { + if (available - sizeof(VSCMsgHeader) < scr_msg_header->length) { return; } readpos = 0; // ready for next message switch (scr_msg_header->type) { - case SCard_ATR: - DPRINTF("SCard_ATR %d\n", scr_msg_header->nLength); - assert(scr_msg_header->nLength <= MAX_ATR_SIZE); - memcpy(s->atr, data, scr_msg_header->nLength); - s->atr_length = scr_msg_header->nLength; + case VSC_ATR: + DPRINTF("VSC_ATR %d\n", scr_msg_header->length); + assert(scr_msg_header->length <= MAX_ATR_SIZE); + memcpy(s->atr, data, scr_msg_header->length); + s->atr_length = scr_msg_header->length; s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; - usb_ccid_on_slot_change(s, true); + ccid_on_slot_change(s, true); break; - case SCard_APDU: + case VSC_APDU: if (!s->waiting_for_answer) { - DPRINTF("SCard_APDU: ERROR: got an APDU while not waiting_for_answer\n"); + DPRINTF("VSC_APDU: ERROR: got an APDU while not waiting_for_answer\n"); assert(s->waiting_for_answer); } s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; - DPRINTF("SCard_APDU %d (answer seq %d, slot %d)\n", - scr_msg_header->nLength, + DPRINTF("VSC_APDU %d (answer seq %d, slot %d)\n", + scr_msg_header->length, s->answer_seq, s->answer_slot); - ccid_write_data_block_answer(s, data, scr_msg_header->nLength); + ccid_write_data_block_answer(s, data, scr_msg_header->length); break; - case SCard_Remove: - DPRINTF("SCard_Remove\n"); - usb_ccid_on_slot_change(s, false); + case VSC_CardRemove: + DPRINTF("VSC_CardRemove\n"); + ccid_on_slot_change(s, false); if (s->waiting_for_answer) { ccid_write_data_block_answer(s, NULL, 0); } break; - case SCard_Error: + case VSC_Init: + ccid_vscard_send_init(s); + break; + case VSC_ReaderAdd: + if (!s->got_reader_add_message) { + s->got_reader_add_message = true; + } else { + ccid_vscard_send_error(s, VSCARD_UNDEFINED_READER_ID, + VSC_CANNOT_ADD_MORE_READERS); + } + case VSC_Error: // TODO - actually look at the error s->bmCommandStatus = COMMAND_STATUS_FAILED; s->last_answer_error = *(uint64_t*)data; - DPRINTF("SCard_Error: %lX\n", s->last_answer_error); + DPRINTF("VSC_Error: %lX\n", s->last_answer_error); ccid_write_data_block_answer(s, NULL, 0); break; default: @@ -891,14 +941,23 @@ static void usb_ccid_scard_read(void *opaque, const uint8_t *buf, int size) } } -static void usb_ccid_scard_event(void *opaque, int event) +static void ccid_scard_event(void *opaque, int event) { - //USBCCIDState *s = opaque; + USBCCIDState *s = opaque; + switch (event) { + case CHR_EVENT_BREAK: + break; + case CHR_EVENT_FOCUS: + break; + case CHR_EVENT_OPENED: + ccid_reset(s); + break; + } } /* Control chardev */ -static int usb_ccid_initfn(USBDevice *dev) +static int ccid_initfn(USBDevice *dev) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); s->dev.speed = USB_SPEED_FULL; @@ -911,13 +970,16 @@ static int usb_ccid_initfn(USBDevice *dev) assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE); memcpy(s->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR)); s->atr_length = sizeof(DEFAULT_ATR); + s->got_reader_add_message = false; if (s->cs) { DPRINTF("initing chardev\n"); - qemu_chr_add_handlers(s->cs, usb_ccid_scard_can_read, usb_ccid_scard_read, - usb_ccid_scard_event, s); + qemu_chr_add_handlers(s->cs, + ccid_scard_can_read, + ccid_vscard_read, + ccid_scard_event, s); } ccid_reset_parameters(s); - usb_ccid_handle_reset(dev); + ccid_handle_reset(dev); return 0; } @@ -925,12 +987,12 @@ static struct USBDeviceInfo ccid_info = { .product_desc = "QEMU USB CCID", .qdev.name = "usb-ccid", .qdev.size = sizeof(USBCCIDState), - .init = usb_ccid_initfn, + .init = ccid_initfn, .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_ccid_handle_reset, - .handle_control = usb_ccid_handle_control, - .handle_data = usb_ccid_handle_data, - .handle_destroy = usb_ccid_handle_destroy, + .handle_reset = ccid_handle_reset, + .handle_control = ccid_handle_control, + .handle_data = ccid_handle_data, + .handle_destroy = ccid_handle_destroy, .usbdevice_name = "ccid", .qdev.props = (Property[]) { DEFINE_PROP_CHR("chardev", USBCCIDState, cs), @@ -938,8 +1000,8 @@ static struct USBDeviceInfo ccid_info = { }, }; -static void usb_ccid_register_devices(void) +static void ccid_register_devices(void) { usb_qdev_register(&ccid_info); } -device_init(usb_ccid_register_devices) +device_init(ccid_register_devices) diff --git a/vscard_common.h b/vscard_common.h new file mode 100644 index 000000000..38ffdf2ba --- /dev/null +++ b/vscard_common.h @@ -0,0 +1,118 @@ +/* Virtual Smart Card protocol definition + * + * This protocol is between a host implementing a group of virtual smart card + * reader, and a client implementing a virtual smart card, or passthrough to + * a real card. + * + * The current implementation passes the raw APDU's from 7816 and additionally + * contains messages to setup and teardown readers, handle insertion and + * removal of cards, negotiate the protocol and provide for error responses. + * + * Copyright (c) 2010 Red Hat. + * + * This code is licensed under the LGPL. + */ + +#ifndef _VSCARD_COMMON_H +#define _VSCARD_COMMON_H + + +#define VERSION_MAJOR_BITS 11 +#define VERSION_MIDDLE_BITS 11 +#define VERSION_MINOR_BITS 10 + +#define MAKE_VERSION(major, middle, minor) \ + ( (major << (VERSION_MINOR_BITS + VERSION_MIDDLE_BITS)) \ + | (middle << VERSION_MINOR_BITS) \ + | (minor) ) + +/** IMPORTANT NOTE on VERSION + * + * The version below MUST be changed whenever a change in this file is made. + * + * The last digit, the minor, is for bug fix changes only. + * + * The middle digit is for backward / forward compatible changes, updates + * to the existing messages, addition of fields. + * + * The major digit is for a breaking change of protocol, presumably + * something that cannot be accomodated with the existing protocol. + */ + +#define VSCARD_VERSION MAKE_VERSION(0,0,1) + +#define VSCARD_UNDEFINED_READER_ID -1 +#define VSCARD_MINIMAL_READER_ID 0 + +typedef enum { + VSC_Init, + VSC_Error, + VSC_ReaderAdd, + VSC_ReaderAddResponse, + VSC_ReaderRemove, + VSC_ATR, + VSC_CardRemove, + VSC_APDU +} VSCMsgType; + +typedef enum { + VSC_GENERAL_ERROR=1, + VSC_CANNOT_ADD_MORE_READERS, +} VSCErrorCode; + +typedef struct VSCMsgHeader { + VSCMsgType type; + uint32_t reader_id; + uint32_t length; +} VSCMsgHeader; + +/* VSCMsgInit Client <-> Host + * Host replies with allocated reader id in ReaderAddResponse + * */ +typedef struct VSCMsgInit { + uint32_t version; +} VSCMsgInit; + +/* VSCMsgError Client <-> Host + * */ +typedef struct VSCMsgError { + VSCErrorCode code; +} VSCMsgError; + +/* VSCMsgReaderAdd Client -> Host + * Host replies with allocated reader id in ReaderAddResponse + * */ +typedef struct VSCMsgReaderAdd { + uint8_t name[0]; +} VSCMsgReaderAdd; + +/* VSCMsgReaderAddResponse Host -> Client + * Reply to ReaderAdd + * */ +typedef struct VSCMsgReaderAddResponse { +} VSCMsgReaderAddResponse; + +/* VSCMsgReaderRemove Client -> Host + * */ +typedef struct VSCMsgReaderRemove { +} VSCMsgReaderRemove; + +/* VSCMsgATR Client -> Host + * Answer to reset. Sent for card insertion or card reset. + * */ +typedef struct VSCMsgATR { + uint8_t atr[0]; +} VSCMsgATR; + +/* VSCMsgCardRemove Client -> Host + * */ +typedef struct VSCMsgCardRemove { +} VSCMsgCardRemove; + +/* VSCMsgAPDU Client <-> Host + * */ +typedef struct VSCMsgAPDU { + uint8_t data[0]; +} VSCMsgAPDU; + +#endif |
