* [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) @ 2010-10-12 12:58 Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 1/2] usb-ccid: add CCID device. add configure option Alon Levy ` (2 more replies) 0 siblings, 3 replies; 16+ messages in thread From: Alon Levy @ 2010-10-12 12:58 UTC (permalink / raw) To: qemu-devel This patch adds a new device, it is described in full in the second patch intro and also in the documentation in docs. In brief it provides a standard smart card reader device. The first patch is the configure change and docs. The second patch contains the actual device, I couldn't figure out a good way to split it to ease review. v2 changed: * all QSIMPLEQ turned into fixed sized rings * all allocated buffers turned into fixed size buffers * added migration support * added a message to tell client qemu has migrated to ip:port * for lack of monitor commands ip:port are 0:0, which causes the updated vscclient to connect to one port higher on the same host. will add monitor commands in a separate patch. tested with current setup. Alon Levy (2): usb-ccid: add CCID device. add configure option. usb-ccid: add CCID device (device itself) Makefile.objs | 1 + configure | 12 + docs/usb-ccid.txt | 115 +++++ hw/usb-ccid.c | 1376 ++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/vscard_common.h | 131 +++++ 5 files changed, 1635 insertions(+), 0 deletions(-) create mode 100644 docs/usb-ccid.txt create mode 100644 hw/usb-ccid.c create mode 100644 hw/vscard_common.h -- 1.7.3.1 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 1/2] usb-ccid: add CCID device. add configure option. 2010-10-12 12:58 [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Alon Levy @ 2010-10-12 12:58 ` Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 2/2] usb-ccid: add CCID device (device itself) Alon Levy 2010-10-12 13:24 ` [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Anthony Liguori 2 siblings, 0 replies; 16+ messages in thread From: Alon Levy @ 2010-10-12 12:58 UTC (permalink / raw) To: qemu-devel This patch adds the configure option --enable-smartcard, adds hw/usb-ccid.c to Makefile.objs, and adds the documentation. Only an empty hw/usb-ccid.c is provided (couldn't add an empty file so added initial comment only). Signed-off-by: Alon Levy <alevy@redhat.com> --- Makefile.objs | 1 + configure | 12 +++++ docs/usb-ccid.txt | 115 +++++++++++++++++++++++++++++++++++++++++++++ hw/usb-ccid.c | 13 +++++ hw/vscard_common.h | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 272 insertions(+), 0 deletions(-) create mode 100644 docs/usb-ccid.txt create mode 100644 hw/usb-ccid.c create mode 100644 hw/vscard_common.h diff --git a/Makefile.objs b/Makefile.objs index 9c13bb3..4b581e7 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -170,6 +170,7 @@ hw-obj-$(CONFIG_FDC) += fdc.o hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o hw-obj-$(CONFIG_DMA) += dma.o +hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o diff --git a/configure b/configure index e0d34fd..fc59a40 100755 --- a/configure +++ b/configure @@ -327,6 +327,7 @@ user_pie="no" zero_malloc="" trace_backend="nop" trace_file="trace" +smartcard="no" # OS specific if check_define __linux__ ; then @@ -730,6 +731,10 @@ for opt do ;; --enable-vhost-net) vhost_net="yes" ;; + --disable-smartcard) smartcard="no" + ;; + --enable-smartcard) smartcard="yes" + ;; --*dir) ;; *) echo "ERROR: unknown option $opt"; show_help="yes" @@ -921,6 +926,8 @@ echo " --enable-vhost-net enable vhost-net acceleration support" echo " --trace-backend=B Trace backend nop simple ust" echo " --trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-<pid>" +echo " --disable-smartcard disable smartcard support" +echo " --enable-smartcard enable smartcard support" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -2285,6 +2292,7 @@ echo "uuid support $uuid" echo "vhost-net support $vhost_net" echo "Trace backend $trace_backend" echo "Trace output file $trace_file-<pid>" +echo "smartcard support $smartcard" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -2540,6 +2548,10 @@ if test "$posix_madvise" = "yes" ; then echo "CONFIG_POSIX_MADVISE=y" >> $config_host_mak fi +if test "$smartcard" = "yes" ; then + echo "CONFIG_SMARTCARD=y" >> $config_host_mak +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "CONFIG_BSD=y" >> $config_host_mak diff --git a/docs/usb-ccid.txt b/docs/usb-ccid.txt new file mode 100644 index 0000000..e418456 --- /dev/null +++ b/docs/usb-ccid.txt @@ -0,0 +1,115 @@ +Contents +1. What is the USB CCID device? +2. What is it the CCID used for? +3. How can I remote my smart card reader to the guest? +4. How do I emulate a smart card using certificates? +5. Build instructions for qemu with usb-ccid and libcaccard +6. How does it work? + +1. What is the USB CCID device? + +The USB CCID device is a USB device implementing the CCID specification, which lets one connect smart card readers that implement the same spec. For more information see the specification: + + Universal Serial Bus + Device Class: Smart Card + CCID + Specification for + Integrated Circuit(s) Cards Interface Devices + Revision 1.1 + April 22rd, 2005 + +2. What is the CCID used for? + +Smartcard are used for authentication, single sign on, decryption in +public/private schemes and digital signatures. A smartcard reader on the client +cannot be used on a guest with simple usb passthrough since it will then not be +available on the client, possibly locking the computer when it is "removed". On +the other hand this device can let you use the smartcard on both the client and +the guest machine. It is also possible to have a completely virtual smart card +reader and smart card (i.e. not backed by a physical device) using this device. + +3. How do I remote a smartcard reader to the guest? + +After following the building instructions for qemu and vscclient run vscclient on the client machine (the one with the smart card reader) and qemu on another (possibly the same) machine like this: + +Assume we use port 2001 on the qemu machine, which we call qemuhost: + +on qemuhost: (run this first, qemu acts as the server) + + qemu -chardev socket,server,host=0.0.0.0,port=2001,id=ccid,nowait -usb -device usb-ccid,chardev=ccid + +on client: + + vscclient qemuhost 2001 + +4. How do I emulate a smartcard using certificates? + +qmeu side doesn't change. + +on client side: +create the certificates. vscclient uses libcac_card, which currently uses +NSS as the backend. To create some self signed certificates using nss: + + certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=cert1" -n cert1 + +Note: three certificates are the maximum the emulated card will take. + +Then run vscclient with the local certificates: +(Note: vscclient command line interface is in a state of change) + + ./vscclient -e "db=\"/etc/pki/nssdb\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)" localhost 2001 + + +5. Build instructions for qemu with usb-ccid and libcaccard + +prerequisites: +clone libcaccard (there are no binary or source releases at this time): +git clone git://anongit.freedesktop.org/~alon/cac_card + +fedora: + yum install nss-devel +ubuntu: + apt-get install libnss3-dev + (not tested on ubuntu) + +build cac_card: + cd cac_card + ./configure && make && sudo make install + +qemu: + ./configure --enable-smartcard && make + +Note that if you install to a non default prefix you need to set +PKG_CONFIG_PATH to compile qemu successfully. + +6. How does it work? + +usb-ccid is a usb device. It defaults to an unattached usb device on startup. +usb-ccid expects a chardev and expects the protocol defined in cac_card/vscard_common.h to be passed over that. +A typical interchange is: + +client event vscclient usb-ccid guest event + + VSC_Init + VSC_ReaderAdd + sees new usb device. +card inserted + VSC_ATR + some guest operation on the card + VSC_APDU + VSC_APDU + [APDU<->APDU repeats several times] +card removed + VSC_CardRemove +kill/quit vscclient + VSC_ReaderRemove + usb device removed. + + +vscclient implements a completely virtual CAC (DoD standard for smart cards) +compliant card and uses NSS to actually retrive certificates and do any +encryption using the backend (real reader + card or file backed certificates +and on pc encryption). + +For documentation of cac_card see README in libcac_card package. + diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c new file mode 100644 index 0000000..98805bb --- /dev/null +++ b/hw/usb-ccid.c @@ -0,0 +1,13 @@ +/* + * CCID Device emulation + * + * Based on usb-serial.c: + * Copyright (c) 2006 CodeSourcery. + * Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org> + * 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. + */ + diff --git a/hw/vscard_common.h b/hw/vscard_common.h new file mode 100644 index 0000000..1a4afd7 --- /dev/null +++ b/hw/vscard_common.h @@ -0,0 +1,131 @@ +/* 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 + +#include <stdint.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, + VSC_Reconnect +} VSCMsgType; + +typedef enum { + VSC_GENERAL_ERROR=1, + VSC_CANNOT_ADD_MORE_READERS, +} VSCErrorCode; + +typedef uint32_t reader_id_t; + +typedef struct VSCMsgHeader { + VSCMsgType type; + reader_id_t reader_id; + uint32_t length; + uint8_t data[0]; +} 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 { + uint32_t code; +} VSCMsgError; + +/* VSCMsgReaderAdd Client -> Host + * Host replies with allocated reader id in ReaderAddResponse + * name - name of the reader on client side. + * */ +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; + +/* VSCMsgReconnect Host -> Client + * */ +typedef struct VSCMsgReconnect { + uint32_t ip; + uint16_t port; +} VSCMsgReconnect; + +#endif -- 1.7.3.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 2/2] usb-ccid: add CCID device (device itself) 2010-10-12 12:58 [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 1/2] usb-ccid: add CCID device. add configure option Alon Levy @ 2010-10-12 12:58 ` Alon Levy 2010-10-12 13:24 ` [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Anthony Liguori 2 siblings, 0 replies; 16+ messages in thread From: Alon Levy @ 2010-10-12 12:58 UTC (permalink / raw) To: qemu-devel A CCID device is a smart card reader. It is a USB device, defined at [2]. The usb-ccid device expects a chardev option and uses the VSCARD protocol defined in vscard_common.h. It starts as an unattached device unless auto_attach=1. The utility vscclient, bundled with libcac_card, provides the client side, together they provide simultaneous access to the card reader an the card attached to it, both in the guest and client machines, as opposed t a simple usb host passthrough. You can also use it to provide a virtual card [1] libcac_card http://cgit.freedesktop.org/~alon/cac_card (temporary home) written by Robert Relyea <rrelyea@redhat.com> [2] http://www.usb.org/developers/devclass_docs/DWG_Smart-Card_CCID_Rev110. Signed-off-by: Alon Levy <alevy@redhat.com> --- hw/usb-ccid.c | 1363 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1363 insertions(+), 0 deletions(-) diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index 98805bb..d9d216c 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -11,3 +11,1366 @@ * 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 + * + * KNOWN BUGS + * 1. remove/insert can sometimes result in removed state instead of inserted. + * This is a result of the following: + * symptom: dmesg shows ERMOTEIO (-121), pcscd shows -99. Thsi happens + * when we send a too short packet, seen in uhci-usb.c, resulting from + * a urb requesting SPD and us returning a smaller packet. + * Not sure which messages trigger this. + * + */ + +#include "qemu-common.h" +#include "qemu-error.h" +#include "usb.h" +#include "qemu-char.h" + +#include "hw/vscard_common.h" + +//#define DEBUG_CCID + +static int debug = 0; + +#define DPRINTF(lvl, fmt, ...) \ +do { if (lvl <= debug) { printf("usb-ccid: " fmt , ## __VA_ARGS__); } } while (0) + +#define CCID_DEV_NAME "usb-ccid" + +/* The two options for variable sized buffers: + * make them constant size, for large enough constant, + * or handle the migration complexity - VMState doesn't handle this case. + * sizes are expected never to be exceeded, unless client misbehaves. */ +#define BULK_OUT_DATA_SIZE 65536 +#define PENDING_ANSWERS_NUM 128 +#define VSCARD_IN_SIZE 65536 + +#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_CONTROL_ABORT 0x1 +#define CCID_CONTROL_GET_CLOCK_FREQUENCIES 0x2 +#define CCID_CONTROL_GET_DATA_RATES 0x3 + +#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" +/* Using Gemplus Vendor and Product id + Effect on various drivers: + * usbccid.sys (winxp, others untested) is a class driver so it doesn't care. + * linux has a number of class drivers, but openct filters based on + vendor/product (/etc/openct.conf under fedora), hence Gemplus. + */ +#define CCID_VENDOR_ID 0x08e6 +#define CCID_PRODUCT_ID 0x4433 +#define CCID_DEVICE_VERSION 0x0000 + +/* BULK_OUT messages from PC to Reader + Defined in CCID Rev 1.1 6.1 (page 26) + */ +#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn 0x62 +#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff 0x63 +#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus 0x65 +#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock 0x6f +#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters 0x6c +#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters 0x6d +#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters 0x61 +#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape 0x6b +#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock 0x6e +#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU 0x6a +#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure 0x69 +#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical 0x71 +#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort 0x72 +#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73 + +/* BULK_IN messages from Reader to PC + Defined in CCID Rev 1.1 6.2 (page 48) + */ +#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock 0x80 +#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus 0x81 +#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters 0x82 +#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape 0x83 +#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84 + +/* INTERRUPT_IN messages from Reader to PC + Defined in CCID Rev 1.1 6.3 (page 56) + */ +#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange 0x50 +#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError 0x51 + +/* Endpoints for CCID - addresses are up to us to decide. + 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 + +/* bmSlotICCState masks */ +#define SLOT_0_STATE_MASK 1 +#define SLOT_0_CHANGED_MASK 2 + +/* Status codes that go in bStatus (see 6.2.6) */ +enum { + ICC_STATUS_PRESENT_ACTIVE = 0, + ICC_STATUS_PRESENT_INACTIVE, + ICC_STATUS_NOT_PRESENT +}; + +enum { + COMMAND_STATUS_NO_ERROR = 0, + COMMAND_STATUS_FAILED, + COMMAND_STATUS_TIME_EXTENSION_REQUIRED +}; + +/* Error codes that go in bError (see 6.2.6) + */ +enum { + ERROR_CMD_NOT_SUPPORTED = 0, + 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 + */ +}; + +typedef struct __attribute__ ((__packed__)) { + uint8_t bMessageType; + uint32_t dwLength; + uint8_t bSlot; + uint8_t bSeq; +} CCID_Header; + +typedef struct __attribute__ ((__packed__)) { + CCID_Header hdr; + uint8_t bStatus; /* Only used in BULK_IN */ + uint8_t bError; /* Only used in BULK_IN */ +} CCID_BULK_IN; + +typedef struct __attribute__ ((__packed__)) { + CCID_BULK_IN b; + uint8_t bClockStatus; +} CCID_SlotStatus; + +typedef struct __attribute__ ((__packed__)) { + CCID_BULK_IN b; + uint8_t bProtocolNum; + uint8_t abProtocolDataStructure[0]; +} CCID_Parameter; + +typedef struct __attribute__ ((__packed__)) { + CCID_BULK_IN b; + uint8_t bChainParameter; + uint8_t abData[0]; +} CCID_DataBlock; + +/* 6.1.4 PC_to_RDR_XfrBlock */ +typedef struct __attribute__ ((__packed__)) { + CCID_Header hdr; + uint8_t bBWI; /* Block Waiting Timeout */ + uint16_t wLevelParameter; + uint8_t abData[0]; +} CCID_XferBlock; + +typedef struct __attribute__ ((__packed__)) { + CCID_Header hdr; + uint8_t bPowerSelect; + uint16_t abRFU; +} CCID_IccPowerOn; + +typedef struct __attribute__ ((__packed__)) { + CCID_Header hdr; + uint16_t abRFU; +} CCID_IccPowerOff; + +typedef struct __attribute__ ((__packed__)) { + CCID_Header hdr; + uint8_t bProtocolNum; + uint8_t abProtocolDataStructure[0]; +} CCID_SetParameter; + +typedef struct { + uint8_t bMessageType; /* CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange */ + uint8_t bmSlotICCState; +} CCID_Notify_Slot_Change; + +#define MAX_ATR_SIZE 40 +#define MAX_PROTOCOL_SIZE 7 + +/* used for DataBlock response to XferBlock */ +typedef struct answer_t { + uint8_t slot; + uint8_t seq; +} answer_t; + +/* pending bulk_in messages */ +typedef struct bulk_in_t { + uint8_t data[BULK_IN_BUF_SIZE]; + uint32_t len; + uint32_t pos; +} bulk_in_t; + +enum { + MIGRATION_NONE, + MIGRATION_MIGRATED, +}; + +/** + * powered - defaults to true, changed by PowerOn/PowerOff messages + */ +typedef struct { + USBDevice dev; + CharDriverState *cs; + uint8_t debug; + uint8_t auto_attach; + uint8_t atr[MAX_ATR_SIZE]; + uint8_t atr_length; + bulk_in_t bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */ + uint32_t bulk_in_pending_start; + uint32_t bulk_in_pending_end; /* first free */ + uint32_t bulk_in_pending_num; + bulk_in_t *current_bulk_in; + uint8_t bulk_out_data[BULK_OUT_DATA_SIZE]; + uint32_t bulk_out_pos; + uint8_t vscard_in_data[VSCARD_IN_SIZE]; + uint32_t vscard_in_pos; + uint32_t vscard_in_hdr; + uint8_t bmSlotICCState; + uint8_t powered; + uint8_t notify_slot_change; + uint64_t last_answer_error; + answer_t pending_answers[PENDING_ANSWERS_NUM]; + uint32_t pending_answers_start; + uint32_t pending_answers_end; + uint32_t pending_answers_num; + uint8_t bError; + uint8_t bmCommandStatus; + uint8_t bProtocolNum; + uint8_t abProtocolDataStructure[MAX_PROTOCOL_SIZE]; + uint32_t ulProtocolDataStructureSize; + uint8_t attached_vmstate; + uint32_t state_vmstate; + uint8_t migration_state; + uint32_t migration_target_ip; + uint16_t migration_target_port; +} USBCCIDState; + +/* Slot specific variables. We emulate a single slot card reader. + */ + +uint8_t DEFAULT_ATR[] = { +/* From some example somewhere + 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28 + */ + +/* From an Athena smart card */ + 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21, 0x13, 0x08 + +}; /* maximum size of ATR - from 7816-3 */ + + +/* 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. + * + * This device implemented based on the spec and with an Athena Smart Card + * Reader as reference: + * 0dc3:1004 Athena Smartcard Solutions, Inc. + */ + +static const uint8_t qemu_ccid_dev_descriptor[] = { + 0x12, /* u8 bLength; */ + USB_DT_DEVICE, /* u8 bDescriptorType; Device */ + 0x10, 0x01, /* u16 bcdUSB; v1.1 */ + + 0x00, /* u8 bDeviceClass; */ + 0x00, /* u8 bDeviceSubClass; */ + 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */ + 0x40, /* u8 bMaxPacketSize0; 8 Bytes (valid: 8,16,32,64) */ + + /* Vendor and product id are arbitrary. */ + /* u16 idVendor */ + CCID_VENDOR_ID & 0xff, CCID_VENDOR_ID >> 8, + /* u16 idProduct */ + CCID_PRODUCT_ID & 0xff, CCID_PRODUCT_ID >> 8, + /* u16 bcdDevice */ + CCID_DEVICE_VERSION & 0xff, CCID_DEVICE_VERSION >> 8, + 0x01, /* u8 iManufacturer; */ + 0x02, /* u8 iProduct; */ + 0x03, /* u8 iSerialNumber; */ + 0x01, /* u8 bNumConfigurations; */ +}; + +static const uint8_t qemu_ccid_config_descriptor[] = { + + /* one configuration */ + 0x09, /* u8 bLength; */ + USB_DT_CONFIG, /* u8 bDescriptorType; Configuration */ + 0x5d, 0x00, /* u16 wTotalLength; 9+9+54+7+7+7 */ + 0x01, /* u8 bNumInterfaces; (1) */ + 0x01, /* u8 bConfigurationValue; */ + 0x00, /* u8 iConfiguration; */ + 0xe0, /* u8 bmAttributes; + Bit 7: must be set, + 6: Self-powered, + 5: Remote wakeup, + 4..0: resvd */ + 100/2, /* u8 MaxPower; 50 == 100mA */ + + /* one interface */ + 0x09, /* u8 if_bLength; */ + USB_DT_INTERFACE, /* u8 if_bDescriptorType; Interface */ + 0x00, /* u8 if_bInterfaceNumber; */ + 0x00, /* u8 if_bAlternateSetting; */ + 0x03, /* u8 if_bNumEndpoints; */ + 0x0b, /* u8 if_bInterfaceClass; Smart Card Device Class */ + 0x00, /* u8 if_bInterfaceSubClass; Subclass code */ + 0x00, /* u8 if_bInterfaceProtocol; Protocol code */ + 0x04, /* u8 if_iInterface; Index of string descriptor */ + + /* Smart Card Device Class Descriptor */ + 0x36, /* u8 bLength; */ + 0x21, /* u8 bDescriptorType; Functional */ + 0x10, 0x01, /* u16 bcdCCID; CCID Specification Release Number. */ + 0x00, /* u8 bMaxSlotIndex; The index of the highest available + slot on this device. All slots are consecutive starting + at 00h. */ + 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 */ + /* u32 dwDefaultClock; in kHZ (0x0fa0 is 4 MHz) */ + 0xa0, 0x0f, 0x00, 0x00, + /* u32 dwMaximumClock; */ + 0x00, 0x00, 0x01, 0x00, + 0x00, /* u8 bNumClockSupported; 0 means just the default and max. */ + /* u32 dwDataRate ;bps. 9600 == 00002580h */ + 0x80, 0x25, 0x00, 0x00, + /* u32 dwMaxDataRate ; 11520 bps == 0001C200h */ + 0x00, 0xC2, 0x01, 0x00, + 0x00, /* u8 bNumDataRatesSupported; 00 means all rates between + * default and max */ + /* u32 dwMaxIFSD; maximum IFSD supported by CCID for protocol + * T=1 (Maximum seen from various cards) */ + 0xfe, 0x00, 0x00, 0x00, + /* u32 dwSyncProtocols; 1 - 2-wire, 2 - 3-wire, 4 - I2C */ + 0x00, 0x00, 0x00, 0x00, + /* u32 dwMechanical; 0 - no special characteristics. */ + 0x00, 0x00, 0x00, 0x00, + /* u32 dwFeatures; + * 0 - No special characteristics + * + 2 Automatic parameter configuration based on ATR data + * + 4 Automatic activation of ICC on inserting + * + 8 Automatic ICC voltage selection + * + 10 Automatic ICC clock frequency change + * + 20 Automatic baud rate change + * + 40 Automatic parameters negotiation made by the CCID + * + 80 automatic PPS made by the CCID + * 100 CCID can set ICC in clock stop mode + * 200 NAD value other then 00 accepted (T=1 protocol) + * + 400 Automatic IFSD exchange as first exchange (T=1) + * One of the following only: + * + 10000 TPDU level exchanges with CCID + * 20000 Short APDU level exchange with CCID + * 40000 Short and Extended APDU level exchange with CCID + * + * + 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, + /* u32 dwMaxCCIDMessageLength; For extended APDU in [261 + 10 + * , 65544 + 10]. Otherwise the minimum is wMaxPacketSize of + * the Bulk-OUT endpoint */ + 0x12, 0x00, 0x01, 0x00, + 0xFF, /* u8 bClassGetResponse; Significant only for CCID that + * offers an APDU level for exchanges. Indicates the default + * class value used by the CCID when it sends a Get Response + * command to perform the transportation of an APDU by T=0 + * protocol + * FFh indicates that the CCID echos the class of the APDU. + */ + 0xFF, /* u8 bClassEnvelope; EAPDU only. Envelope command for T=0 */ + 0x00, 0x00, /* u16 wLcdLayout; XXYY Number of lines (XX) and chars per + * line for LCD display used for PIN entry. 0000 - no LCD */ + 0x01, /* u8 bPINSupport; 01h PIN Verification, + * 02h PIN Modification */ + 0x01, /* u8 bMaxCCIDBusySlots; */ + + /* Interrupt-IN endpoint */ + 0x07, /* u8 ep_bLength; */ + /* 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; */ + /* 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; */ + /* 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 bool ccid_has_pending_answers(USBCCIDState *s) +{ + return s->pending_answers_num > 0; +} + +static void ccid_clear_pending_answers(USBCCIDState *s) +{ + s->pending_answers_num = 0; + s->pending_answers_start = 0; + s->pending_answers_end = 0; +} + +static void ccid_print_pending_answers(USBCCIDState *s) +{ +#ifdef DEBUG_CCID + answer_t *answer; + int i, count; + + printf("usb-ccid: pending answers:"); + if (!ccid_has_pending_answers(s)) { + printf(" empty\n"); + return; + } + for (i = s->pending_answers_start, count=s->pending_answers_num ; + count > 0; count--, i++) { + answer = &s->pending_answers[i % PENDING_ANSWERS_NUM]; + if (count == 1) { + printf("%d:%d\n", answer->slot, answer->seq); + } else { + printf("%d:%d,", answer->slot, answer->seq); + } + } +#endif +} + +static void ccid_add_pending_answer(USBCCIDState *s, CCID_Header *hdr) +{ + answer_t* answer; + + assert(s->pending_answers_num++ < PENDING_ANSWERS_NUM); + answer = &s->pending_answers[(s->pending_answers_end++) % PENDING_ANSWERS_NUM]; + answer->slot = hdr->bSlot; + answer->seq = hdr->bSeq; + ccid_print_pending_answers(s); +} + +static void ccid_remove_pending_answer(USBCCIDState *s, + uint8_t *slot, uint8_t *seq) +{ + answer_t *answer; + + assert(s->pending_answers_num-- > 0); + answer = &s->pending_answers[(s->pending_answers_start++) % PENDING_ANSWERS_NUM]; + *slot = answer->slot; + *seq = answer->seq; + ccid_print_pending_answers(s); +} + +static void ccid_bulk_in_clear(USBCCIDState *s) +{ + s->bulk_in_pending_start = 0; + s->bulk_in_pending_end = 0; + s->bulk_in_pending_num = 0; +} + +static void ccid_bulk_in_release(USBCCIDState *s) +{ + assert(s->current_bulk_in != NULL); + s->current_bulk_in->pos = 0; + s->current_bulk_in = NULL; +} + +static void ccid_bulk_in_get(USBCCIDState *s) +{ + if (s->current_bulk_in != NULL || s->bulk_in_pending_num == 0) { + return; + } + assert(s->bulk_in_pending_num > 0); + s->bulk_in_pending_num--; + s->current_bulk_in = &s->bulk_in_pending[ + (s->bulk_in_pending_start++) % BULK_IN_PENDING_NUM]; +} + +static uint8_t* ccid_reserve_recv_buf(USBCCIDState* s, uint16_t len) +{ + bulk_in_t* bulk_in; + + DPRINTF(4, "%s: QUEUE: reserve %d bytes\n", __func__, len); + + /* look for an existing element */ + if (len > BULK_IN_BUF_SIZE) { + printf("usb-ccid.c: %s: len larger then max (%d>%d). bailing out.\n", + __func__, len, BULK_IN_BUF_SIZE); + exit(-1); + } + if (s->bulk_in_pending_num >= BULK_IN_PENDING_NUM) { + printf("usb-ccid.c: %s: No free bulk_in buffers. discarding message.\n", + __func__); + return NULL; + } + bulk_in = &s->bulk_in_pending[(s->bulk_in_pending_end++) % BULK_IN_PENDING_NUM]; + s->bulk_in_pending_num++; + bulk_in->len = len; + return bulk_in->data; +} + +static void ccid_reset(USBCCIDState *s) +{ + ccid_bulk_in_clear(s); + ccid_clear_pending_answers(s); +} + +static void ccid_detach(USBCCIDState *s) +{ + ccid_reset(s); + if (s->auto_attach == 0 && s->dev.attached) { + usb_device_detach(&s->dev); + } +} + +static void ccid_handle_reset(USBDevice *dev) +{ + USBCCIDState *s = (USBCCIDState *)dev; + + DPRINTF(1, "Reset\n"); + + ccid_reset(s); +} + +static int ccid_handle_control(USBDevice *dev, int request, int value, + int index, int length, uint8_t *data) +{ + int ret = 0; + + DPRINTF(1, "got control %x, value %x\n",request, value); + switch (request) { + case DeviceRequest | USB_REQ_GET_STATUS: + data[0] = (0 << USB_DEVICE_SELF_POWERED) | + (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP); + data[1] = 0x00; + ret = 2; + break; + case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 0; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_FEATURE: + if (value == USB_DEVICE_REMOTE_WAKEUP) { + dev->remote_wakeup = 1; + } else { + goto fail; + } + ret = 0; + break; + case DeviceOutRequest | USB_REQ_SET_ADDRESS: + dev->addr = value; + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch(value >> 8) { + case USB_DT_DEVICE: + memcpy(data, qemu_ccid_dev_descriptor, + sizeof(qemu_ccid_dev_descriptor)); + ret = sizeof(qemu_ccid_dev_descriptor); + break; + case USB_DT_CONFIG: + memcpy(data, qemu_ccid_config_descriptor, + sizeof(qemu_ccid_config_descriptor)); + ret = sizeof(qemu_ccid_config_descriptor); + break; + case USB_DT_STRING: + switch(value & 0xff) { + case 0: + /* language ids */ + data[0] = 4; + data[1] = 3; + data[2] = 0x09; + data[3] = 0x04; + ret = 4; + break; + case 1: + /* vendor description */ + ret = set_usb_string(data, CCID_VENDOR_DESCRIPTION); + break; + case 2: + /* product description */ + ret = set_usb_string(data, CCID_PRODUCT_DESCRIPTION); + break; + case 3: + /* serial number */ + ret = set_usb_string(data, CCID_SERIAL_NUMBER_STRING); + break; + case 4: + /* interface name */ + ret = set_usb_string(data, CCID_INTERFACE_NAME); + break; + default: + goto fail; + } + break; + default: + goto fail; + } + break; + case DeviceRequest | USB_REQ_GET_CONFIGURATION: + data[0] = 1; + ret = 1; + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + /* Only one configuration - we just ignore the request */ + ret = 0; + break; + case DeviceRequest | USB_REQ_GET_INTERFACE: + data[0] = 0; + ret = 1; + break; + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + ret = 0; + break; + case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: + ret = 0; + break; + + /* Class specific requests. */ + case InterfaceOutClass | CCID_CONTROL_ABORT: + DPRINTF(1, "ccid_control abort UNIMPLEMENTED\n"); + ret = USB_RET_STALL; + break; + case InterfaceInClass | CCID_CONTROL_GET_CLOCK_FREQUENCIES: + DPRINTF(1, "ccid_control get clock frequencies UNIMPLEMENTED\n"); + ret = USB_RET_STALL; + break; + case InterfaceInClass | CCID_CONTROL_GET_DATA_RATES: + DPRINTF(1, "ccid_control get data rates UNIMPLEMENTED\n"); + ret = USB_RET_STALL; + break; + default: + fail: + DPRINTF(1, "got unsupported/bogus control %x, value %x\n", request, value); + ret = USB_RET_STALL; + break; + } + return ret; +} + +static bool ccid_card_inserted(USBCCIDState *s) +{ + return s->bmSlotICCState & SLOT_0_STATE_MASK; +} + +static uint8_t ccid_card_status(USBCCIDState *s) +{ + return ccid_card_inserted(s) + ? (s->powered ? + ICC_STATUS_PRESENT_ACTIVE + : ICC_STATUS_PRESENT_INACTIVE + ) + : ICC_STATUS_NOT_PRESENT; +} + +static uint8_t ccid_calc_status(USBCCIDState *s) +{ + /* page 55, 6.2.6, calculation of bStatus from bmICCStatus and + bmCommandStatus + */ + uint8_t ret = ccid_card_status(s) | (s->bmCommandStatus << 6); + DPRINTF(4, "status = %d\n", ret); + return ret; +} + +static void ccid_reset_error_status(USBCCIDState* s) +{ + s->bError = ERROR_CMD_NOT_SUPPORTED; + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; +} + +static void ccid_write_slot_status(USBCCIDState* s, CCID_Header* recv) +{ + CCID_SlotStatus *h = (CCID_SlotStatus*)ccid_reserve_recv_buf(s, sizeof(CCID_SlotStatus)); + if (h == NULL) { + return; + } + h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus; + h->b.hdr.dwLength = 0; + h->b.hdr.bSlot = recv->bSlot; + h->b.hdr.bSeq = recv->bSeq; + h->b.bStatus = ccid_calc_status(s); + h->b.bError = s->bError; + h->bClockStatus = CLOCK_STATUS_RUNNING; + ccid_reset_error_status(s); +} + +static void ccid_write_parameters(USBCCIDState* s, CCID_Header* recv) +{ + CCID_Parameter *h; + uint32_t len = s->ulProtocolDataStructureSize; + + h = (CCID_Parameter *)ccid_reserve_recv_buf(s, sizeof(CCID_Parameter) + len); + if (h == NULL) { + return; + } + h->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_Parameters; + h->b.hdr.dwLength = 0; + h->b.hdr.bSlot = recv->bSlot; + h->b.hdr.bSeq = recv->bSeq; + h->b.bStatus = ccid_calc_status(s); + h->b.bError = s->bError; + h->bProtocolNum = s->bProtocolNum; + memcpy(h->abProtocolDataStructure, s->abProtocolDataStructure, len); + ccid_reset_error_status(s); +} + +static void ccid_write_data_block( + USBCCIDState* s, uint8_t slot, uint8_t seq, + const uint8_t* data, uint32_t len) +{ + CCID_DataBlock *p; + + p = (CCID_DataBlock*)ccid_reserve_recv_buf(s, sizeof(*p) + len); + if (p == NULL) { + return; + } + p->b.hdr.bMessageType = CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock; + p->b.hdr.dwLength = len; + p->b.hdr.bSlot = slot; + p->b.hdr.bSeq = seq; + p->b.bStatus = ccid_calc_status(s); + p->b.bError = s->bError; +#ifdef DEBUG_CCID + if (p->b.bError) { + DPRINTF(4, "error %d", p->b.bError); + } +#endif + memcpy(p->abData, data, len); + ccid_reset_error_status(s); +} + +static void ccid_write_data_block_answer(USBCCIDState* s, + const uint8_t* data, uint32_t len) +{ + uint8_t seq; + uint8_t slot; + + if (!ccid_has_pending_answers(s)) { + abort(); + } + ccid_remove_pending_answer(s, &slot, &seq); + ccid_write_data_block(s, slot, seq, data, len); +} + +static void ccid_write_data_block_atr(USBCCIDState* s, CCID_Header* recv) +{ + ccid_write_data_block(s, recv->bSlot, recv->bSeq, s->atr, s->atr_length); +} + +static void ccid_set_parameters(USBCCIDState *s, CCID_Header *recv) +{ + CCID_SetParameter *ph = (CCID_SetParameter *) recv; + uint32_t len = 0; + if (ph->bProtocolNum == 0) { + len = 5; + } + if (ph->bProtocolNum == 1) { + len = 7; + } + if (len == 0) { + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->bError = 7; /* Protocol invalid or not supported */ + return; + } + s->bProtocolNum = ph->bProtocolNum; + memcpy(s->abProtocolDataStructure, ph->abProtocolDataStructure, len); + s->ulProtocolDataStructureSize = len; + DPRINTF(1, "%s: using len %d\n", __func__, len); +} + +/* 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 void ccid_reset_parameters(USBCCIDState *s) +{ + uint32_t len = sizeof(abDefaultProtocolDataStructure); + + s->bProtocolNum = 1; /* T=1 */ + s->ulProtocolDataStructureSize = len; + memcpy(s->abProtocolDataStructure, abDefaultProtocolDataStructure, len); +} + +/* NOTE: only a single slot is supported (SLOT_0) + */ +static void ccid_on_slot_change(USBCCIDState* s, bool full) +{ + /* RDR_to_PC_NotifySlotChange, 6.3.1 page 56 + */ + uint8_t current = s->bmSlotICCState; + if (full) { + s->bmSlotICCState |= SLOT_0_STATE_MASK; + } else { + s->bmSlotICCState &= ~SLOT_0_STATE_MASK; + } + if (current != s->bmSlotICCState) { + s->bmSlotICCState |= SLOT_0_CHANGED_MASK; + } + s->notify_slot_change = true; +} + +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, reader_id_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, reader_id_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) +{ + if (!s->cs) { + printf("usb-ccid: discarding apdu length %d\n", recv->hdr.dwLength); + return; + } + if (ccid_card_status(s) != ICC_STATUS_PRESENT_ACTIVE) { + DPRINTF(1, "usb-ccid: not sending apdu to client, no card connected\n"); + ccid_write_data_block_error(s, recv->hdr.bSlot, recv->hdr.bSeq); + return; + } + DPRINTF(1, "%s: seq %d, len %d\n", __FUNCTION__, + recv->hdr.bSeq, recv->hdr.dwLength); + ccid_add_pending_answer(s, (CCID_Header*)recv); + ccid_vscard_send_apdu(s, recv->abData, recv->hdr.dwLength); +} + +static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) +{ + CCID_Header* ccid_header; + + assert(p->len + s->bulk_out_pos <= BULK_OUT_DATA_SIZE); + ccid_header = (CCID_Header*)s->bulk_out_data; + memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len); + s->bulk_out_pos += p->len; + if (p->len == 64) { + DPRINTF(4, "usb-ccid: bulk_in: expecting more packets (%d/%d)\n", + p->len, ccid_header->dwLength); + return; + } + if (s->bulk_out_pos < 10) { + DPRINTF(1, "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n", __func__); + } else { + DPRINTF(3, "%s %x\n", __func__, 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: + /* We need to send an ATR back */ + DPRINTF(1, "PowerOn: %d\n", + ((CCID_IccPowerOn*)(ccid_header))->bPowerSelect); + s->powered = true; + ccid_write_data_block_atr(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff: + DPRINTF(1, "PowerOff\n"); + ccid_reset_error_status(s); + s->powered = false; + ccid_write_slot_status(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock: + ccid_on_apdu_from_guest(s, (CCID_XferBlock*)s->bulk_out_data); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters: + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; + ccid_set_parameters(s, ccid_header); + ccid_write_parameters(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters: + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; + ccid_reset_parameters(s); + ccid_write_parameters(s, ccid_header); + break; + case CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters: + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; + ccid_write_parameters(s, ccid_header); + break; + default: + DPRINTF(1, "handle_data: ERROR: unhandled message type %Xh\n", + ccid_header->bMessageType); + /* the caller is expecting the device to respond, tell it we + * do't support the operation */ + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->bError = ERROR_CMD_NOT_SUPPORTED; + ccid_write_slot_status(s, ccid_header); + break; + } + } + s->bulk_out_pos = 0; +} + +static int ccid_bulk_in_copy_out(USBCCIDState *s, uint8_t *data, int len) +{ + int ret = 0; + + assert(len>0); + ccid_bulk_in_get(s); + if (s->current_bulk_in != NULL) { + ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len); + memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret); + s->current_bulk_in->pos += ret; + if (s->current_bulk_in->pos == s->current_bulk_in->len) { + ccid_bulk_in_release(s); + } + } else { + ret = USB_RET_NAK; /* return when device has no data - usb 2.0 spec Table 8-4 */ + } + if (ret > 0) { + DPRINTF(3, "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret); + } + if (ret != USB_RET_NAK && ret < len) { + DPRINTF(1, "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len); + } + return ret; +} + +static int ccid_handle_data(USBDevice *dev, USBPacket *p) +{ + USBCCIDState *s = (USBCCIDState *)dev; + int ret = 0; + uint8_t *data = p->data; + int len = p->len; + + switch (p->pid) { + case USB_TOKEN_OUT: + ccid_handle_bulk_out(s, p); + break; + + case USB_TOKEN_IN: + switch (p->devep & 0xf) { + case CCID_BULK_IN_EP: + if (!len) { + ret = USB_RET_NAK; + } else { + ret = ccid_bulk_in_copy_out(s, data, len); + } + break; + case CCID_INT_IN_EP: + if (s->notify_slot_change) { + /* page 56, RDR_to_PC_NotifySlotChange */ + data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange; + data[1] = s->bmSlotICCState; + ret = 2; + s->notify_slot_change = false; + s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK; + DPRINTF(2, "handle_data: int_in: notify_slot_change %X, requested len %d\n", + s->bmSlotICCState, len); + } + break; + default: + DPRINTF(1, "Bad endpoint\n"); + break; + } + break; + default: + DPRINTF(1, "Bad token\n"); + ret = USB_RET_STALL; + break; + } + + return ret; +} + +static void ccid_handle_destroy(USBDevice *dev) +{ + USBCCIDState *s = (USBCCIDState *)dev; + + if (s->cs) { + qemu_chr_close(s->cs); + } + ccid_bulk_in_clear(s); +} + +/* APDU chardev */ + +static int ccid_vscard_can_read(void *opaque) +{ + return 65535; +} + +static void ccid_vscard_handle_message(USBCCIDState *s, + VSCMsgHeader* scr_msg_header) +{ + uint8_t *data = (uint8_t*)&scr_msg_header[1]; + answer_t *answer; + + switch (scr_msg_header->type) { + case VSC_ATR: + DPRINTF(1, "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; + if (ccid_has_pending_answers(s)) { + ccid_write_data_block_answer(s, NULL, 0); + } + ccid_on_slot_change(s, true); + break; + case VSC_APDU: + if (!ccid_has_pending_answers(s)) { + DPRINTF(1, "VSC_APDU: ERROR: got an APDU without pending answers\n"); + break; + } + s->bmCommandStatus = COMMAND_STATUS_NO_ERROR; + answer = s->pending_answers_num == 0 ? NULL : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM]; + if (answer == NULL) { + abort(); + } + DPRINTF(1, "VSC_APDU %d (answer seq %d, slot %d)\n", + scr_msg_header->length, + answer->seq, answer->slot); + ccid_write_data_block_answer(s, data, scr_msg_header->length); + break; + case VSC_CardRemove: + DPRINTF(1, "VSC_CardRemove\n"); + ccid_on_slot_change(s, false); + if (ccid_has_pending_answers(s)) { + ccid_write_data_block_answer(s, NULL, 0); + } + ccid_reset(s); + break; + case VSC_Init: + break; + case VSC_Error: + s->bmCommandStatus = COMMAND_STATUS_FAILED; + s->last_answer_error = *(uint64_t*)data; + DPRINTF(1, "VSC_Error: %lX\n", s->last_answer_error); + ccid_write_data_block_answer(s, NULL, 0); + break; + case VSC_ReaderAdd: + DPRINTF(1, "VSC_ReaderAdd\n"); + if (s->auto_attach==0 && !s->dev.attached) { + usb_device_attach(&s->dev); + ccid_vscard_send_msg(s, VSC_ReaderAddResponse, + VSCARD_MINIMAL_READER_ID, NULL, 0); + } else { + if (s->migration_state == MIGRATION_MIGRATED) { + s->migration_state = MIGRATION_NONE; + ccid_vscard_send_msg(s, VSC_ReaderAddResponse, + VSCARD_MINIMAL_READER_ID, NULL, 0); + } else { + ccid_vscard_send_error(s, VSCARD_UNDEFINED_READER_ID, + VSC_CANNOT_ADD_MORE_READERS); + } + } + break; + case VSC_ReaderRemove: + DPRINTF(1, "VSC_ReaderRemove\n"); + if (ccid_card_inserted(s)) { + ccid_on_slot_change(s, false); + ccid_clear_pending_answers(s); + } + if (s->auto_attach == 0 && s->dev.attached) { + usb_device_detach(&s->dev); + } + break; + default: + printf("usb-ccid: chardev: unexpected message of type %X\n", + scr_msg_header->type); + ccid_vscard_send_error(s, scr_msg_header->reader_id, + VSC_GENERAL_ERROR); + } +} + +static void ccid_vscard_read(void *opaque, const uint8_t *buf, int size) +{ + USBCCIDState *s = opaque; + VSCMsgHeader *hdr; + + assert(s->vscard_in_pos + size <= VSCARD_IN_SIZE); + memcpy(s->vscard_in_data + s->vscard_in_pos, buf, size); + s->vscard_in_pos += size; + hdr = (VSCMsgHeader*)(s->vscard_in_data + s->vscard_in_hdr); + + while ((s->vscard_in_pos - s->vscard_in_hdr >= sizeof(VSCMsgHeader)) && + (s->vscard_in_pos - s->vscard_in_hdr - sizeof(VSCMsgHeader) >= + hdr->length)) { + ccid_vscard_handle_message(s, hdr); + s->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader); + hdr = (VSCMsgHeader*)(s->vscard_in_data + s->vscard_in_hdr); + } + if (s->vscard_in_hdr == s->vscard_in_pos) { + s->vscard_in_pos = s->vscard_in_hdr = 0; + } +} + +static void ccid_vscard_event(void *opaque, int event) +{ + USBCCIDState *s = opaque; + + switch (event) { + case CHR_EVENT_BREAK: + break; + case CHR_EVENT_FOCUS: + break; + case CHR_EVENT_OPENED: + DPRINTF(1, "%s: CHR_EVENT_OPENED\n", __func__); + if (s->migration_state != MIGRATION_MIGRATED) { + ccid_detach(s); + } + break; + } +} + +static int ccid_initfn(USBDevice *dev) +{ + USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); + + s->migration_state = MIGRATION_NONE; + dev->auto_attach = s->auto_attach; + debug = s->debug; + s->migration_target_ip = 0; + s->migration_target_port = 0; + s->dev.speed = USB_SPEED_FULL; + s->notify_slot_change = false; + s->powered = true; + s->pending_answers_num = 0; + s->last_answer_error = 0; + s->bulk_in_pending_start = 0; + s->bulk_in_pending_end = 0; + s->current_bulk_in = NULL; + ccid_reset_error_status(s); + assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE); + memcpy(s->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR)); + s->atr_length = sizeof(DEFAULT_ATR); + s->bulk_out_pos = 0; + s->vscard_in_pos = 0; + s->vscard_in_hdr = 0; + if (s->cs) { + DPRINTF(1, "initing chardev\n"); + qemu_chr_add_handlers(s->cs, + ccid_vscard_can_read, + ccid_vscard_read, + ccid_vscard_event, s); + ccid_vscard_send_init(s); + } + ccid_reset_parameters(s); + ccid_reset(s); + return 0; +} + +static int ccid_post_load(void *opaque, int version_id) +{ + USBCCIDState *s = opaque; + + if (s->auto_attach == 0 && s->attached_vmstate && !s->dev.attached) { + usb_device_attach(&s->dev); + } + // This must be done after usb_device_attach, which sets state to ATTACHED, + // while it must be DEFAULT in order to accept packets (like it is after + // reset, but reset will reset our addr and call our reset handler which + // may change state, and we don't want to do that when migrating). + s->dev.state = s->state_vmstate; + return 0; +} + +static void ccid_pre_save(void *opaque) +{ + USBCCIDState *s = opaque; + VSCMsgReconnect reconnect; + + reconnect.ip = s->migration_target_ip; + reconnect.port = s->migration_target_port; + ccid_vscard_send_msg(s, VSC_Reconnect, VSCARD_UNDEFINED_READER_ID, + (uint8_t*)&reconnect, sizeof(reconnect)); + s->attached_vmstate = s->dev.attached; + s->state_vmstate = s->dev.state; + if (s->dev.attached) { + // migrating an open device, ignore reconnection CHR_EVENT to avoid an + // erronous detach. + s->migration_state = MIGRATION_MIGRATED; + } +} + +static VMStateDescription bulk_in_t_vmstate = { + .name = "bulk_in_t", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) { + VMSTATE_BUFFER(data, bulk_in_t), + VMSTATE_UINT32(len, bulk_in_t), + VMSTATE_UINT32(pos, bulk_in_t), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription answer_t_vmstate = { + .name = "answer_t", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) { + VMSTATE_UINT8(slot, answer_t), + VMSTATE_UINT8(seq, answer_t), + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription usb_device_vmstate = { + .name = "usb_device", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) { + //int speed; + VMSTATE_UINT8(addr, USBDevice), + //VMSTATE_BUFFER(product_desc, USBDevice), // char, not uint8_t - casting error + //int auto_attach; + //int attached; + //int state; + VMSTATE_BUFFER(setup_buf, USBDevice), + VMSTATE_BUFFER(data_buf, USBDevice), + // int remote_wakeup; + // int setup_state; + // int setup_len; + // int setup_index; + VMSTATE_END_OF_LIST() + } +}; + +static VMStateDescription ccid_vmstate = { + .name = CCID_DEV_NAME, + .version_id = 1, + .minimum_version_id = 1, + .post_load = ccid_post_load, + .pre_save = ccid_pre_save, + .fields = (VMStateField []) { + VMSTATE_STRUCT(dev, USBCCIDState, 1, usb_device_vmstate, USBDevice), + VMSTATE_UINT8(debug, USBCCIDState), + VMSTATE_UINT8(auto_attach, USBCCIDState), + VMSTATE_BUFFER(atr, USBCCIDState), + VMSTATE_UINT8(atr_length, USBCCIDState), + VMSTATE_BUFFER(bulk_out_data, USBCCIDState), + VMSTATE_UINT32(bulk_out_pos, USBCCIDState), + VMSTATE_BUFFER(vscard_in_data, USBCCIDState), + VMSTATE_UINT32(vscard_in_pos, USBCCIDState), + VMSTATE_UINT32(vscard_in_hdr, USBCCIDState), + VMSTATE_UINT8(bmSlotICCState, USBCCIDState), + VMSTATE_UINT8(powered, USBCCIDState), + VMSTATE_UINT8(notify_slot_change, USBCCIDState), + VMSTATE_UINT64(last_answer_error, USBCCIDState), + VMSTATE_UINT8(bError, USBCCIDState), + VMSTATE_UINT8(bmCommandStatus, USBCCIDState), + VMSTATE_UINT8(bProtocolNum, USBCCIDState), + VMSTATE_BUFFER(abProtocolDataStructure, USBCCIDState), + VMSTATE_UINT32(ulProtocolDataStructureSize, USBCCIDState), + VMSTATE_STRUCT_ARRAY(bulk_in_pending, USBCCIDState, + BULK_IN_PENDING_NUM, 1, bulk_in_t_vmstate, bulk_in_t), + VMSTATE_UINT32(bulk_in_pending_start, USBCCIDState), + VMSTATE_UINT32(bulk_in_pending_end, USBCCIDState), + VMSTATE_STRUCT_ARRAY(pending_answers, USBCCIDState, + PENDING_ANSWERS_NUM, 1, answer_t_vmstate, answer_t), + VMSTATE_UINT32(pending_answers_num, USBCCIDState), + VMSTATE_UINT8(migration_state, USBCCIDState), + VMSTATE_UINT8(attached_vmstate, USBCCIDState), + VMSTATE_UINT32(state_vmstate, USBCCIDState), + VMSTATE_END_OF_LIST() + } +}; + +static struct USBDeviceInfo ccid_info = { + .product_desc = "QEMU USB CCID", + .qdev.name = CCID_DEV_NAME, + .qdev.size = sizeof(USBCCIDState), + .qdev.vmsd = &ccid_vmstate, + .init = ccid_initfn, + .handle_packet = usb_generic_handle_packet, + .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), + DEFINE_PROP_UINT8("auto_attach", USBCCIDState, auto_attach, 0), + DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void ccid_register_devices(void) +{ + usb_qdev_register(&ccid_info); +} +device_init(ccid_register_devices) -- 1.7.3.1 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-12 12:58 [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 1/2] usb-ccid: add CCID device. add configure option Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 2/2] usb-ccid: add CCID device (device itself) Alon Levy @ 2010-10-12 13:24 ` Anthony Liguori 2 siblings, 0 replies; 16+ messages in thread From: Anthony Liguori @ 2010-10-12 13:24 UTC (permalink / raw) To: Alon Levy; +Cc: qemu-devel On 10/12/2010 07:58 AM, Alon Levy wrote: > This patch adds a new device, it is described in full in the second patch > intro and also in the documentation in docs. In brief it provides a standard > smart card reader device. > > The first patch is the configure change and docs. > The second patch contains the actual device, I couldn't figure out a good > way to split it to ease review. > > v2 changed: > * all QSIMPLEQ turned into fixed sized rings > * all allocated buffers turned into fixed size buffers > * added migration support > * added a message to tell client qemu has migrated to ip:port > * for lack of monitor commands ip:port are 0:0, which causes the updated > vscclient to connect to one port higher on the same host. will add monitor > commands in a separate patch. tested with current setup. > This is way too much magic to live within a device. Devices manage reconnecting themselves during migration. When you create the destination qemu instance, you specify what to connect to. IOW, On the source: qemu -chardev tcp:localhost:1025,id=foo -usbdevice ccid,chardev=foo ... On the destination: qemu -chardev tcp:localhost:1026,id=foo -usbdevice ccid,chardev=foo -incoming tcp:0.0.0.0:1024 ... A connection happens when the device is created. But now I'm even further confused then when I first reviewed it.. If you're now supporting migration, does that mean that you're relying on the daemon to emulate the device? Regards, Anthony Liguori > Alon Levy (2): > usb-ccid: add CCID device. add configure option. > usb-ccid: add CCID device (device itself) > > Makefile.objs | 1 + > configure | 12 + > docs/usb-ccid.txt | 115 +++++ > hw/usb-ccid.c | 1376 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/vscard_common.h | 131 +++++ > 5 files changed, 1635 insertions(+), 0 deletions(-) > create mode 100644 docs/usb-ccid.txt > create mode 100644 hw/usb-ccid.c > create mode 100644 hw/vscard_common.h > > ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <1045788737.212361286898758903.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com>]
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) [not found] <1045788737.212361286898758903.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com> @ 2010-10-12 16:03 ` Alon Levy 2010-10-12 16:21 ` Anthony Liguori 0 siblings, 1 reply; 16+ messages in thread From: Alon Levy @ 2010-10-12 16:03 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel ----- "Anthony Liguori" <anthony@codemonkey.ws> wrote: > On 10/12/2010 07:58 AM, Alon Levy wrote: > > This patch adds a new device, it is described in full in the second > patch > > intro and also in the documentation in docs. In brief it provides a > standard > > smart card reader device. > > > > The first patch is the configure change and docs. > > The second patch contains the actual device, I couldn't figure out a > good > > way to split it to ease review. > > > > v2 changed: > > * all QSIMPLEQ turned into fixed sized rings > > * all allocated buffers turned into fixed size buffers > > * added migration support > > * added a message to tell client qemu has migrated to ip:port > > * for lack of monitor commands ip:port are 0:0, which causes the > updated > > vscclient to connect to one port higher on the same host. will > add monitor > > commands in a separate patch. tested with current setup. > > > > This is way too much magic to live within a device. Devices manage > reconnecting themselves during migration. When you create the > destination qemu instance, you specify what to connect to. > > IOW, > > On the source: > > qemu -chardev tcp:localhost:1025,id=foo -usbdevice ccid,chardev=foo > ... > > On the destination: > > qemu -chardev tcp:localhost:1026,id=foo -usbdevice ccid,chardev=foo > -incoming tcp:0.0.0.0:1024 ... > > A connection happens when the device is created. > > But now I'm even further confused then when I first reviewed it.. If > > you're now supporting migration, does that mean that you're relying on > > the daemon to emulate the device? > Let me try to clarify this. Nothing has changed since the last patch except for what's in the notes, i.e. migration support. The device I'm adding is a reader. The reader is just a pipe between smart cards and the guest operating system. The smart card logic does live outside of this device, and is available in the cac_card sources at http://cgit.freedesktop.org/~alon/cac_card/ (all of this is in docs/usb_ccid.txt). So when I speak of vscclient, I'm talking of an application that emulates a smart card and initiates a tcp connection to qemu that connects to the usb-ccid device. vscclient is also in the cac_card sources. Regarding the method of reconnection: You are absolutely right that if I have qemu connect to the remote instead of the other way around then I remove the need to inform vscclient of the new address. But the way it stands requires the client to know the address of the destination qemu. I have to inform it somehow. You are saying that devices shouldn't know this information? ok, that's why I talked about monitor commands. I come from the world of spice - in spice we use monitor commands for this. I could change this to have qemu connect to vscclient, but I don't see the logic in general - sometimes you do want to have a chardev that is listening (the fact that it is implemented suggests someone found it useful), if you then migrate you have the same problem I'm solving. > Regards, > > Anthony Liguori > > > Alon Levy (2): > > usb-ccid: add CCID device. add configure option. > > usb-ccid: add CCID device (device itself) > > > > Makefile.objs | 1 + > > configure | 12 + > > docs/usb-ccid.txt | 115 +++++ > > hw/usb-ccid.c | 1376 > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > > hw/vscard_common.h | 131 +++++ > > 5 files changed, 1635 insertions(+), 0 deletions(-) > > create mode 100644 docs/usb-ccid.txt > > create mode 100644 hw/usb-ccid.c > > create mode 100644 hw/vscard_common.h > > > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-12 16:03 ` Alon Levy @ 2010-10-12 16:21 ` Anthony Liguori 0 siblings, 0 replies; 16+ messages in thread From: Anthony Liguori @ 2010-10-12 16:21 UTC (permalink / raw) To: Alon Levy; +Cc: qemu-devel On 10/12/2010 11:03 AM, Alon Levy wrote: > ----- "Anthony Liguori"<anthony@codemonkey.ws> wrote: > > >> On 10/12/2010 07:58 AM, Alon Levy wrote: >> >>> This patch adds a new device, it is described in full in the second >>> >> patch >> >>> intro and also in the documentation in docs. In brief it provides a >>> >> standard >> >>> smart card reader device. >>> >>> The first patch is the configure change and docs. >>> The second patch contains the actual device, I couldn't figure out a >>> >> good >> >>> way to split it to ease review. >>> >>> v2 changed: >>> * all QSIMPLEQ turned into fixed sized rings >>> * all allocated buffers turned into fixed size buffers >>> * added migration support >>> * added a message to tell client qemu has migrated to ip:port >>> * for lack of monitor commands ip:port are 0:0, which causes the >>> >> updated >> >>> vscclient to connect to one port higher on the same host. will >>> >> add monitor >> >>> commands in a separate patch. tested with current setup. >>> >>> >> This is way too much magic to live within a device. Devices manage >> reconnecting themselves during migration. When you create the >> destination qemu instance, you specify what to connect to. >> >> IOW, >> >> On the source: >> >> qemu -chardev tcp:localhost:1025,id=foo -usbdevice ccid,chardev=foo >> ... >> >> On the destination: >> >> qemu -chardev tcp:localhost:1026,id=foo -usbdevice ccid,chardev=foo >> -incoming tcp:0.0.0.0:1024 ... >> >> A connection happens when the device is created. >> >> But now I'm even further confused then when I first reviewed it.. If >> >> you're now supporting migration, does that mean that you're relying on >> >> the daemon to emulate the device? >> >> > Let me try to clarify this. Nothing has changed since the last patch except > for what's in the notes, i.e. migration support. The device I'm adding is a > reader. The reader is just a pipe between smart cards and the guest operating > system. The smart card logic does live outside of this device, and is available > in the cac_card sources at http://cgit.freedesktop.org/~alon/cac_card/ (all of > this is in docs/usb_ccid.txt). > > So when I speak of vscclient, I'm talking of an application that emulates a smart > card and initiates a tcp connection to qemu that connects to the usb-ccid device. > vscclient is also in the cac_card sources. > Okay, let me be clear. We shouldn't be doing device emulation outside of QEMU's source tree--at least, not in this type of context. External devices present a great deal of challenges and we shouldn't just approach it in an ad-hoc fashion. I'm not opposed to passthrough although I'd prefer QEMU to talk to the device directly instead of going through a daemon. There's a lot of delicate integration between QEMU and a device and if a device lives outside of QEMU, it makes it extremely difficult for us to influence changes to that device to support QEMU new features. > Regarding the method of reconnection: You are absolutely right that if I have qemu > connect to the remote instead of the other way around then I remove the need to inform > vscclient of the new address. But the way it stands requires the client to know the > address of the destination qemu. I have to inform it somehow. You are saying that > devices shouldn't know this information? ok, that's why I talked about monitor commands. > I come from the world of spice - in spice we use monitor commands for this. And none of that is upstream. Regards, Anthony Liguori > I could > change this to have qemu connect to vscclient, but I don't see the logic in general - > sometimes you do want to have a chardev that is listening (the fact that it is implemented > suggests someone found it useful), if you then migrate you have the same problem I'm > solving. > > >> Regards, >> >> Anthony Liguori >> >> >>> Alon Levy (2): >>> usb-ccid: add CCID device. add configure option. >>> usb-ccid: add CCID device (device itself) >>> >>> Makefile.objs | 1 + >>> configure | 12 + >>> docs/usb-ccid.txt | 115 +++++ >>> hw/usb-ccid.c | 1376 >>> >> ++++++++++++++++++++++++++++++++++++++++++++++++++++ >> >>> hw/vscard_common.h | 131 +++++ >>> 5 files changed, 1635 insertions(+), 0 deletions(-) >>> create mode 100644 docs/usb-ccid.txt >>> create mode 100644 hw/usb-ccid.c >>> create mode 100644 hw/vscard_common.h >>> >>> >>> ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <593949580.216281286900989465.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com>]
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) [not found] <593949580.216281286900989465.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com> @ 2010-10-12 16:43 ` Alon Levy 2010-10-12 16:49 ` Anthony Liguori 0 siblings, 1 reply; 16+ messages in thread From: Alon Levy @ 2010-10-12 16:43 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel ----- "Anthony Liguori" <anthony@codemonkey.ws> wrote: > On 10/12/2010 11:03 AM, Alon Levy wrote: > > ----- "Anthony Liguori"<anthony@codemonkey.ws> wrote: > > > > > >> On 10/12/2010 07:58 AM, Alon Levy wrote: > >> > >>> This patch adds a new device, it is described in full in the > second > >>> > >> patch > >> > >>> intro and also in the documentation in docs. In brief it provides > a > >>> > >> standard > >> > >>> smart card reader device. > >>> > >>> The first patch is the configure change and docs. > >>> The second patch contains the actual device, I couldn't figure out > a > >>> > >> good > >> > >>> way to split it to ease review. > >>> > >>> v2 changed: > >>> * all QSIMPLEQ turned into fixed sized rings > >>> * all allocated buffers turned into fixed size buffers > >>> * added migration support > >>> * added a message to tell client qemu has migrated to ip:port > >>> * for lack of monitor commands ip:port are 0:0, which causes > the > >>> > >> updated > >> > >>> vscclient to connect to one port higher on the same host. > will > >>> > >> add monitor > >> > >>> commands in a separate patch. tested with current setup. > >>> > >>> > >> This is way too much magic to live within a device. Devices > manage > >> reconnecting themselves during migration. When you create the > >> destination qemu instance, you specify what to connect to. > >> > >> IOW, > >> > >> On the source: > >> > >> qemu -chardev tcp:localhost:1025,id=foo -usbdevice > ccid,chardev=foo > >> ... > >> > >> On the destination: > >> > >> qemu -chardev tcp:localhost:1026,id=foo -usbdevice > ccid,chardev=foo > >> -incoming tcp:0.0.0.0:1024 ... > >> > >> A connection happens when the device is created. > >> > >> But now I'm even further confused then when I first reviewed it.. > If > >> > >> you're now supporting migration, does that mean that you're relying > on > >> > >> the daemon to emulate the device? > >> > >> > > Let me try to clarify this. Nothing has changed since the last patch > except > > for what's in the notes, i.e. migration support. The device I'm > adding is a > > reader. The reader is just a pipe between smart cards and the guest > operating > > system. The smart card logic does live outside of this device, and > is available > > in the cac_card sources at > http://cgit.freedesktop.org/~alon/cac_card/ (all of > > this is in docs/usb_ccid.txt). > > > > So when I speak of vscclient, I'm talking of an application that > emulates a smart > > card and initiates a tcp connection to qemu that connects to the > usb-ccid device. > > vscclient is also in the cac_card sources. > > > > Okay, let me be clear. We shouldn't be doing device emulation outside > > of QEMU's source tree--at least, not in this type of context. > External > devices present a great deal of challenges and we shouldn't just > approach it in an ad-hoc fashion. There are two devices: smart card reader, aka CCID device - emulated inside qemu. Submitted. smart card - emulated outside of qemu. Fully available, open source separate project. The idea here is to allow a remote device to be accessed from the guest. The remote device is not running necessarily on the qemu host, so there has to be a network connection, which implies some remote client. The only thing that is changeable is where the card is emulated - at the client side or at qemu side. I understand you favor qemu. But really this is not that much of a change as you imply, and there is a good reason for having it on the client side, namely latency of talking to the real card reader. Even if it was local to qemu, it would still have to wait for responses from the network, so I don't see how it would be less fragile. I don't think the device right now is done ad-hoc, but you are welcome to comment on anything specific (it is up for review). (sorry for repeating myself, I guess what follows is the main point): The CCID device is a standard USB class device, some of the USB events are handled without access to the network, and some result in a write to the chardev (==network), which is recorded, and when a read from the chardev happens some resulting USB activity happens. It is not yet without errors, but it is stable, passes migration, and works most of the time. The only exception are occasional short packets that I am still investigating, and hope won't prevent a review of the current status. > > I'm not opposed to passthrough although I'd prefer QEMU to talk to the > passthrough I'm familiar with are all on the same host QEMU is running on, that goes for pci and usb passthrough (afaik those are the only ones). > device directly instead of going through a daemon. > > There's a lot of delicate integration between QEMU and a device and if > a > device lives outside of QEMU, it makes it extremely difficult for us > to > influence changes to that device to support QEMU new features. > > > Regarding the method of reconnection: You are absolutely right that > if I have qemu > > connect to the remote instead of the other way around then I remove > the need to inform > > vscclient of the new address. But the way it stands requires the > client to know the > > address of the destination qemu. I have to inform it somehow. You > are saying that > > devices shouldn't know this information? ok, that's why I talked > about monitor commands. > > I come from the world of spice - in spice we use monitor commands > for this. > > And none of that is upstream. > You only replied to the last part. What is your suggested fix for this case: 1. qemu -chardev socket,server,host=0.0.0.0,port=2001,id=foo,nowait -device virtioserial-port,chardev=foo 2. app X connects to 2001 from clienthost 3. migrate to otherhost running on otherport otherhost$ qemu.. <same commandline, 2001 replaced with otherport> 4. X is left hanging I realize it seems a contrived example, but I imagine the socket,server option is actually used like this, otherwise what is it there for? > Regards, > > Anthony Liguori > > > I could > > change this to have qemu connect to vscclient, but I don't see the > logic in general - > > sometimes you do want to have a chardev that is listening (the fact > that it is implemented > > suggests someone found it useful), if you then migrate you have the > same problem I'm > > solving. > > > > > >> Regards, > >> > >> Anthony Liguori > >> > >> > >>> Alon Levy (2): > >>> usb-ccid: add CCID device. add configure option. > >>> usb-ccid: add CCID device (device itself) > >>> > >>> Makefile.objs | 1 + > >>> configure | 12 + > >>> docs/usb-ccid.txt | 115 +++++ > >>> hw/usb-ccid.c | 1376 > >>> > >> ++++++++++++++++++++++++++++++++++++++++++++++++++++ > >> > >>> hw/vscard_common.h | 131 +++++ > >>> 5 files changed, 1635 insertions(+), 0 deletions(-) > >>> create mode 100644 docs/usb-ccid.txt > >>> create mode 100644 hw/usb-ccid.c > >>> create mode 100644 hw/vscard_common.h > >>> > >>> > >>> ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-12 16:43 ` Alon Levy @ 2010-10-12 16:49 ` Anthony Liguori 2010-10-12 17:09 ` Alon Levy 0 siblings, 1 reply; 16+ messages in thread From: Anthony Liguori @ 2010-10-12 16:49 UTC (permalink / raw) To: Alon Levy; +Cc: qemu-devel On 10/12/2010 11:43 AM, Alon Levy wrote: > ----- "Anthony Liguori"<anthony@codemonkey.ws> wrote: > > >> On 10/12/2010 11:03 AM, Alon Levy wrote: >> >>> ----- "Anthony Liguori"<anthony@codemonkey.ws> wrote: >>> >>> >>> >>>> On 10/12/2010 07:58 AM, Alon Levy wrote: >>>> >>>> >>>>> This patch adds a new device, it is described in full in the >>>>> >> second >> >>>>> >>>>> >>>> patch >>>> >>>> >>>>> intro and also in the documentation in docs. In brief it provides >>>>> >> a >> >>>>> >>>>> >>>> standard >>>> >>>> >>>>> smart card reader device. >>>>> >>>>> The first patch is the configure change and docs. >>>>> The second patch contains the actual device, I couldn't figure out >>>>> >> a >> >>>>> >>>>> >>>> good >>>> >>>> >>>>> way to split it to ease review. >>>>> >>>>> v2 changed: >>>>> * all QSIMPLEQ turned into fixed sized rings >>>>> * all allocated buffers turned into fixed size buffers >>>>> * added migration support >>>>> * added a message to tell client qemu has migrated to ip:port >>>>> * for lack of monitor commands ip:port are 0:0, which causes >>>>> >> the >> >>>>> >>>>> >>>> updated >>>> >>>> >>>>> vscclient to connect to one port higher on the same host. >>>>> >> will >> >>>>> >>>>> >>>> add monitor >>>> >>>> >>>>> commands in a separate patch. tested with current setup. >>>>> >>>>> >>>>> >>>> This is way too much magic to live within a device. Devices >>>> >> manage >> >>>> reconnecting themselves during migration. When you create the >>>> destination qemu instance, you specify what to connect to. >>>> >>>> IOW, >>>> >>>> On the source: >>>> >>>> qemu -chardev tcp:localhost:1025,id=foo -usbdevice >>>> >> ccid,chardev=foo >> >>>> ... >>>> >>>> On the destination: >>>> >>>> qemu -chardev tcp:localhost:1026,id=foo -usbdevice >>>> >> ccid,chardev=foo >> >>>> -incoming tcp:0.0.0.0:1024 ... >>>> >>>> A connection happens when the device is created. >>>> >>>> But now I'm even further confused then when I first reviewed it.. >>>> >> If >> >>>> you're now supporting migration, does that mean that you're relying >>>> >> on >> >>>> the daemon to emulate the device? >>>> >>>> >>>> >>> Let me try to clarify this. Nothing has changed since the last patch >>> >> except >> >>> for what's in the notes, i.e. migration support. The device I'm >>> >> adding is a >> >>> reader. The reader is just a pipe between smart cards and the guest >>> >> operating >> >>> system. The smart card logic does live outside of this device, and >>> >> is available >> >>> in the cac_card sources at >>> >> http://cgit.freedesktop.org/~alon/cac_card/ (all of >> >>> this is in docs/usb_ccid.txt). >>> >>> So when I speak of vscclient, I'm talking of an application that >>> >> emulates a smart >> >>> card and initiates a tcp connection to qemu that connects to the >>> >> usb-ccid device. >> >>> vscclient is also in the cac_card sources. >>> >>> >> Okay, let me be clear. We shouldn't be doing device emulation outside >> >> of QEMU's source tree--at least, not in this type of context. >> External >> devices present a great deal of challenges and we shouldn't just >> approach it in an ad-hoc fashion. >> > There are two devices: > smart card reader, aka CCID device - emulated inside qemu. Submitted. > smart card - emulated outside of qemu. Fully available, open source separate project. > And how does the smart card state get migrated during migration? How do you keep it synced with QEMU? I don't understand the use-case behind this. Is this so that a local physical smart card can be passed through to a guest from a Spice client and when migration happens, the QEMU instance connects back to the Spice client? So the device is never actually migrated? Regards, Anthony Liguori ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-12 16:49 ` Anthony Liguori @ 2010-10-12 17:09 ` Alon Levy 2010-10-12 18:23 ` Anthony Liguori 0 siblings, 1 reply; 16+ messages in thread From: Alon Levy @ 2010-10-12 17:09 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel ----- "Anthony Liguori" <anthony@codemonkey.ws> wrote: > On 10/12/2010 11:43 AM, Alon Levy wrote: > > ----- "Anthony Liguori"<anthony@codemonkey.ws> wrote: > > > > > >> On 10/12/2010 11:03 AM, Alon Levy wrote: > >> > >>> ----- "Anthony Liguori"<anthony@codemonkey.ws> wrote: > >>> > >>> > >>> > >>>> On 10/12/2010 07:58 AM, Alon Levy wrote: > >>>> > >>>> > >>>>> This patch adds a new device, it is described in full in the > >>>>> > >> second > >> > >>>>> > >>>>> > >>>> patch > >>>> > >>>> > >>>>> intro and also in the documentation in docs. In brief it > provides > >>>>> > >> a > >> > >>>>> > >>>>> > >>>> standard > >>>> > >>>> > >>>>> smart card reader device. > >>>>> > >>>>> The first patch is the configure change and docs. > >>>>> The second patch contains the actual device, I couldn't figure > out > >>>>> > >> a > >> > >>>>> > >>>>> > >>>> good > >>>> > >>>> > >>>>> way to split it to ease review. > >>>>> > >>>>> v2 changed: > >>>>> * all QSIMPLEQ turned into fixed sized rings > >>>>> * all allocated buffers turned into fixed size buffers > >>>>> * added migration support > >>>>> * added a message to tell client qemu has migrated to > ip:port > >>>>> * for lack of monitor commands ip:port are 0:0, which > causes > >>>>> > >> the > >> > >>>>> > >>>>> > >>>> updated > >>>> > >>>> > >>>>> vscclient to connect to one port higher on the same host. > >>>>> > >> will > >> > >>>>> > >>>>> > >>>> add monitor > >>>> > >>>> > >>>>> commands in a separate patch. tested with current setup. > >>>>> > >>>>> > >>>>> > >>>> This is way too much magic to live within a device. Devices > >>>> > >> manage > >> > >>>> reconnecting themselves during migration. When you create the > >>>> destination qemu instance, you specify what to connect to. > >>>> > >>>> IOW, > >>>> > >>>> On the source: > >>>> > >>>> qemu -chardev tcp:localhost:1025,id=foo -usbdevice > >>>> > >> ccid,chardev=foo > >> > >>>> ... > >>>> > >>>> On the destination: > >>>> > >>>> qemu -chardev tcp:localhost:1026,id=foo -usbdevice > >>>> > >> ccid,chardev=foo > >> > >>>> -incoming tcp:0.0.0.0:1024 ... > >>>> > >>>> A connection happens when the device is created. > >>>> > >>>> But now I'm even further confused then when I first reviewed > it.. > >>>> > >> If > >> > >>>> you're now supporting migration, does that mean that you're > relying > >>>> > >> on > >> > >>>> the daemon to emulate the device? > >>>> > >>>> > >>>> > >>> Let me try to clarify this. Nothing has changed since the last > patch > >>> > >> except > >> > >>> for what's in the notes, i.e. migration support. The device I'm > >>> > >> adding is a > >> > >>> reader. The reader is just a pipe between smart cards and the > guest > >>> > >> operating > >> > >>> system. The smart card logic does live outside of this device, > and > >>> > >> is available > >> > >>> in the cac_card sources at > >>> > >> http://cgit.freedesktop.org/~alon/cac_card/ (all of > >> > >>> this is in docs/usb_ccid.txt). > >>> > >>> So when I speak of vscclient, I'm talking of an application that > >>> > >> emulates a smart > >> > >>> card and initiates a tcp connection to qemu that connects to the > >>> > >> usb-ccid device. > >> > >>> vscclient is also in the cac_card sources. > >>> > >>> > >> Okay, let me be clear. We shouldn't be doing device emulation > outside > >> > >> of QEMU's source tree--at least, not in this type of context. > >> External > >> devices present a great deal of challenges and we shouldn't just > >> approach it in an ad-hoc fashion. > >> > > There are two devices: > > smart card reader, aka CCID device - emulated inside qemu. > Submitted. > > smart card - emulated outside of qemu. Fully available, open > source separate project. > > > > And how does the smart card state get migrated during migration? How > do > you keep it synced with QEMU? The smart card is not being migrated. It is running on the client machine, which is not being migrated/shutdown (same as vncviewer isn't migrated). > > I don't understand the use-case behind this. Is this so that a local > > physical smart card can be passed through to a guest from a Spice > client > and when migration happens, the QEMU instance connects back to the > Spice > client? So the device is never actually migrated? > The *smart card* is never migrated. The ccid device is. Here is the scenario: Host A: qemu_a qemu_a: guest Host B: vscclient - physical reader Host C: qemu_b -incoming .. yes, we will use this for SPICE, but this is submitted to qemu on the hopes and with testing ensuring it is perfectly usable as is without using SPICE, otherwise I wouldn't have sent it upstream. non-SPICE usage: 1. user on B runs vscclient (and presumably the user has some connection to the guest to use the smartcard device, i.e. vnc/ssh/spice, but that's not relevant). 2. vscclient connects via tcp to qemu_a. 3. qemu_a starts migrating to qemu_b. (qemu_b is alive at this point, can receive incoming tcp connections on chardev - otherwise a migration fails immediately anyway) 4. pre_load for usb-ccid sends a Reconnect message 5. vscclient gets the Reconnect message, closes socket to qemu_a, opens socket to qemu_b 6. from guest pov nothing happened (no device detach/attach). I have to stress that the main problem the migration intends to solve is to avoid a detach/attach in the guest. Actual operations on the smartcard could possibly fail as a result of the migration, and it would not be a real problem (i.e. we could live without, but we can't leave with a lock of the guest screen as a result of a migration). Which is why I consider the current code good enough. It is certainly not perfect (short packet issue), or tested enough. The SPICE usage scenario is basically the same, just replace vscclient with spicec, and we don't need the Reconnect message since SPICE takes care of this for us (we just get a channel detach/attach event if we care). 1. user on B runs spicec 2. spicec connects to qemu via spice channel, smart card channel connects to usb-ccid device via spicevmc chardev (so it doesn't care it's spice or not). 3. qemu_a migrates 4. spicec disconnects from qemu_a and connects to qemu_b 5. from guest os pov nothing happens on the ccid usb device. > Regards, > > Anthony Liguori ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-12 17:09 ` Alon Levy @ 2010-10-12 18:23 ` Anthony Liguori 2010-10-13 11:54 ` Alon Levy 0 siblings, 1 reply; 16+ messages in thread From: Anthony Liguori @ 2010-10-12 18:23 UTC (permalink / raw) To: Alon Levy; +Cc: qemu-devel On 10/12/2010 12:09 PM, Alon Levy wrote: > The smart card is not being migrated. It is running on the client machine, > which is not being migrated/shutdown (same as vncviewer isn't migrated). > > Ok, let's look at this compared to another similar use-case: USB passthrough of a webcam device that's remoted using USB over IP. In this model, you have a USB bus that's modelled as a bus and a device. Within the USB bus, you have additional devices. These are all qdev devices and they may be emulated or they may be implemented using passthrough. While we don't do it today, USB over IP would be just another form of passthrough. Migration is a rather interesting challenge in this model. You've got a mix of client state and server state on the USB over IP connection. You could marshal up the client state and as long as you reconnected to the same server on the destination, I guess it would be okay. I think the problem with your current implementation is that you've completed skipped the bus modelling and you're also using the Device over IP connection to implement device emulation. What I would suggest is that you model the bus/device relationship via qdev and move the Smart Card emulation into QEMU. I would also suggest adding proper passthrough support in QEMU. CCID over IP is a reasonable thing to have but I think you've got way too much outside of QEMU right now such that long term maintenance is going to be exceedingly difficult. Regards, Anthony Liguori >> I don't understand the use-case behind this. Is this so that a local >> >> physical smart card can be passed through to a guest from a Spice >> client >> and when migration happens, the QEMU instance connects back to the >> Spice >> client? So the device is never actually migrated? >> >> > The *smart card* is never migrated. The ccid device is. Here is the scenario: > > Host A: qemu_a > qemu_a: guest > > Host B: vscclient > - physical reader > > Host C: qemu_b -incoming .. > > yes, we will use this for SPICE, but this is submitted > to qemu on the hopes and with testing ensuring it is perfectly usable as is > without using SPICE, otherwise I wouldn't have sent it upstream. > > non-SPICE usage: > > 1. user on B runs vscclient (and presumably the user has some connection to the guest to use the smartcard device, i.e. vnc/ssh/spice, but that's not relevant). > 2. vscclient connects via tcp to qemu_a. > 3. qemu_a starts migrating to qemu_b. > (qemu_b is alive at this point, can receive incoming tcp connections on chardev - otherwise a migration fails immediately anyway) > 4. pre_load for usb-ccid sends a Reconnect message > 5. vscclient gets the Reconnect message, closes socket to qemu_a, opens socket to qemu_b > 6. from guest pov nothing happened (no device detach/attach). > > I have to stress that the main problem the migration intends to solve is to avoid a detach/attach in the guest. Actual > operations on the smartcard could possibly fail as a result of the migration, and it would not be a real problem (i.e. > we could live without, but we can't leave with a lock of the guest screen as a result of a migration). Which is why I > consider the current code good enough. It is certainly not perfect (short packet issue), or tested enough. > > The SPICE usage scenario is basically the same, just replace vscclient with spicec, and > we don't need the Reconnect message since SPICE takes care of this for us (we just get > a channel detach/attach event if we care). > 1. user on B runs spicec > 2. spicec connects to qemu via spice channel, smart card channel connects to usb-ccid device via spicevmc chardev (so it doesn't care it's spice or not). > 3. qemu_a migrates > 4. spicec disconnects from qemu_a and connects to qemu_b > 5. from guest os pov nothing happens on the ccid usb device. > > >> Regards, >> >> Anthony Liguori >> ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-12 18:23 ` Anthony Liguori @ 2010-10-13 11:54 ` Alon Levy 0 siblings, 0 replies; 16+ messages in thread From: Alon Levy @ 2010-10-13 11:54 UTC (permalink / raw) To: Anthony Liguori; +Cc: qemu-devel ----- "Anthony Liguori" <anthony@codemonkey.ws> wrote: > On 10/12/2010 12:09 PM, Alon Levy wrote: > > The smart card is not being migrated. It is running on the client > machine, > > which is not being migrated/shutdown (same as vncviewer isn't > migrated). > > > > > > Ok, let's look at this compared to another similar use-case: USB > passthrough of a webcam device that's remoted using USB over IP. > > In this model, you have a USB bus that's modelled as a bus and a > device. Within the USB bus, you have additional devices. These are > all > qdev devices and they may be emulated or they may be implemented using > > passthrough. While we don't do it today, USB over IP would be just > another form of passthrough. > > Migration is a rather interesting challenge in this model. You've got > a > mix of client state and server state on the USB over IP connection. > You > could marshal up the client state and as long as you reconnected to > the > same server on the destination, I guess it would be okay. > > I think the problem with your current implementation is that you've > completed skipped the bus modelling and you're also using the Device > over IP connection to implement device emulation. > > What I would suggest is that you model the bus/device relationship via > > qdev and move the Smart Card emulation into QEMU. I would also > suggest > adding proper passthrough support in QEMU. CCID over IP is a > reasonable > thing to have but I think you've got way too much outside of QEMU > right > now such that long term maintenance is going to be exceedingly > difficult. > CCID over IP doesn't make any sense (It's just a specific sort of reader), but I assume you meant APDU (the smart card protocol) over IP, which is exactly what vscard_common.h protocol has (so that's already ready). I'll address the modeling of the reader device as a bus and add optional card emulation. You can regard the current implementation as exactly passthrough of APDU, that's what it does - pushes the APDU's to a remote client, and gets APDUs in return. Since I'm using an existing library for the card emulation I will make qemu link with it. Alon > Regards, > > Anthony Liguori > > >> I don't understand the use-case behind this. Is this so that a > local > >> > >> physical smart card can be passed through to a guest from a Spice > >> client > >> and when migration happens, the QEMU instance connects back to the > >> Spice > >> client? So the device is never actually migrated? > >> > >> > > The *smart card* is never migrated. The ccid device is. Here is the > scenario: > > > > Host A: qemu_a > > qemu_a: guest > > > > Host B: vscclient > > - physical reader > > > > Host C: qemu_b -incoming .. > > > > yes, we will use this for SPICE, but this is submitted > > to qemu on the hopes and with testing ensuring it is perfectly > usable as is > > without using SPICE, otherwise I wouldn't have sent it upstream. > > > > non-SPICE usage: > > > > 1. user on B runs vscclient (and presumably the user has some > connection to the guest to use the smartcard device, i.e. > vnc/ssh/spice, but that's not relevant). > > 2. vscclient connects via tcp to qemu_a. > > 3. qemu_a starts migrating to qemu_b. > > (qemu_b is alive at this point, can receive incoming tcp > connections on chardev - otherwise a migration fails immediately > anyway) > > 4. pre_load for usb-ccid sends a Reconnect message > > 5. vscclient gets the Reconnect message, closes socket to qemu_a, > opens socket to qemu_b > > 6. from guest pov nothing happened (no device detach/attach). > > > > I have to stress that the main problem the migration intends to > solve is to avoid a detach/attach in the guest. Actual > > operations on the smartcard could possibly fail as a result of the > migration, and it would not be a real problem (i.e. > > we could live without, but we can't leave with a lock of the guest > screen as a result of a migration). Which is why I > > consider the current code good enough. It is certainly not perfect > (short packet issue), or tested enough. > > > > The SPICE usage scenario is basically the same, just replace > vscclient with spicec, and > > we don't need the Reconnect message since SPICE takes care of this > for us (we just get > > a channel detach/attach event if we care). > > 1. user on B runs spicec > > 2. spicec connects to qemu via spice channel, smart card channel > connects to usb-ccid device via spicevmc chardev (so it doesn't care > it's spice or not). > > 3. qemu_a migrates > > 4. spicec disconnects from qemu_a and connects to qemu_b > > 5. from guest os pov nothing happens on the ccid usb device. > > > > > >> Regards, > >> > >> Anthony Liguori > >> ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2)
@ 2010-10-14 18:37 Robert Relyea
2010-10-14 18:52 ` Anthony Liguori
0 siblings, 1 reply; 16+ messages in thread
From: Robert Relyea @ 2010-10-14 18:37 UTC (permalink / raw)
To: qemu-devel; +Cc: Alon Levy
[-- Attachment #1.1: Type: text/plain, Size: 5097 bytes --]
Anthony Liguori wrote:
> > And how does the smart card state get migrated during migration? How
> > do you keep it synced with QEMU?
> >
> > I don't understand the use-case behind this. Is this so that a local
> > physical smart card can be passed through to a guest from a Spice
> > client and when migration happens, the QEMU instance connects back to
> > the Spice client? So the device is never actually migrated?
>
A lot of this discussion has confused me until I realized we are talking
2 different models.
My current understanding is that qemu assumes that all devices are local
to the qemu instance (that is on the host). When you migrate you want to
connect to the new hardware on the new host, not feed back to some
general client. The only exception seems to be mouse and keyboard, where
qemu depends on some external protocol (vncclient or xdesktop or the x
protocol itself) to transport the mouse and keyboard events.
Our model has been that the smart card is local to the user/client --
like the mouse and keyboard. When you migrate qemu you do not migrate
the smart card itself, since it's still physically on your client
machine (like the mouse and keyboard), and needs to be managed by the
local drivers on that client machine (which knows how to talk to the
specific smart card installed there). So the daemon stays right where
it's at and connects to the new qemu instance as it comes up. This is
where I think I was confused about your migration question. I think you
are assuming that the smart card itself connects to new hardware on the
new host, meaning the daemon itself needs to move. If that is the
semantic you are trying to present, then you are quite right, it's
ludicrous to have the external daemon as part of the emulation.
It now appears to me that qemu punts on this case, except for the
keyboard and mouse -- well maybe not punts, but simply doesn't support
any device that isn't on the host machine. If you look at the way qemu
handles the sound device, for instance. Normally you want the sound to
come out the speakers of the controlling console, not a random server
that's hosting the guest. However, straight qemu doesn't handle things
that way. The sound (if it comes out at all) comes out the server that
qemu is installed on. When you migrate qemu, the sound now comes out the
new server.
This probably isn't a problem since most of the time someone is using
the speaker, he's got the case where host == client. In that case it
makes perfect sense to put the emulator inside qemu. In the case where
we are running a hosted server service, it's highly unlikely anyone is
going to be using sound (or an attached webcam, etc.). In fact migration
for these devices are really a noop.
Smart cards are really like these devices. In fact more than a few
keyboards have built in smart card readers. The smart card model is I
want the smart card at the same location as my keyboard and mouse. I use
that set of smart cards to authenticate. The use case on machines
running with a server is that some customers have a requirement that you
need the smart card to log in and administer those machines. Those smart
cards are ones the operator carries with him, not ones that would sit on
some server farm. For their requirements, one needs a way to get back to
the local client.
As I said before, I don't think this requirement is unique. The only way
to handle it is to run code on the client machine. The devices that run
on that client are ones you don't migrate with qemu, but stay with the
client itself and reconnect to the new instance. I agree that having a
daemon for each devices will eventually become unweildy. It looks like
spice is the answer for this scenario. If you have devices other than
the mouse/keyboard/display that are located on the client == host, then
you should assume the need for spice and not use straight qemu?
In that world it makes sense to have a single protocol (passthru). It's
ok to integrate the smart card emul directly into qemu because it's
really only used either in the case where client != host, or in the case
where your server hardware has some smart card installed that is uses
for authentication. (NOTE: in this case, migrate means that the server
will loose authentication and have to authenticate with the new smart
card on the new host... I don't know how useful this really is, but I
think it's important to point out that migrate with smart cards means
something different than most devices. It means you have become a new
entity, not a continuation of the old... it's the equivalent of pulling
a smart card on a server and inserting a new one).
So if my understanding is correct, as long as you are willing to deal
with the card plug/unplug scenario on migration, it makes sense for qemu
to have passthru plus a local emulated smart card which goes directly to
local hardward. If you need to have the 'console' experience, then you
turn on spice and emulate the card in the spice client.
bob
[-- Attachment #1.2: Type: text/html, Size: 5859 bytes --]
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 6014 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-14 18:37 Robert Relyea @ 2010-10-14 18:52 ` Anthony Liguori 2010-10-14 22:03 ` Robert Relyea 0 siblings, 1 reply; 16+ messages in thread From: Anthony Liguori @ 2010-10-14 18:52 UTC (permalink / raw) To: Robert Relyea; +Cc: Alon Levy, qemu-devel [-- Attachment #1: Type: text/plain, Size: 6309 bytes --] On 10/14/2010 01:37 PM, Robert Relyea wrote: > Anthony Liguori wrote: > > >> > And how does the smart card state get migrated during migration? How >> > do you keep it synced with QEMU? >> > >> > I don't understand the use-case behind this. Is this so that a local >> > physical smart card can be passed through to a guest from a Spice >> > client and when migration happens, the QEMU instance connects back to >> > the Spice client? So the device is never actually migrated? >> > A lot of this discussion has confused me until I realized we are talking > 2 different models. > > My current understanding is that qemu assumes that all devices are local > to the qemu instance (that is on the host). When you migrate you want to > connect to the new hardware on the new host, not feed back to some > general client. The only exception seems to be mouse and keyboard, where > qemu depends on some external protocol (vncclient or xdesktop or the x > protocol itself) to transport the mouse and keyboard events. > > Our model has been that the smart card is local to the user/client -- > like the mouse and keyboard. When you migrate qemu you do not migrate > the smart card itself, since it's still physically on your client > machine (like the mouse and keyboard), and needs to be managed by the > local drivers on that client machine (which knows how to talk to the > specific smart card installed there). So the daemon stays right where > it's at and connects to the new qemu instance as it comes up. This is > where I think I was confused about your migration question. I think you > are assuming that the smart card itself connects to new hardware on the > new host, meaning the daemon itself needs to move. If that is the > semantic you are trying to present, then you are quite right, it's > ludicrous to have the external daemon as part of the emulation. > Remote device passthrough is just a special case of passthrough. It's got interesting characteristics in that unlike local device passthrough, if you preserve the connection to the remove device, migration is still possible. However, remote device *emulation* is the thing that I'm concerned about. Having a device emulated outside of QEMU means that it's not possible to participate in many of QEMU's features (like live migration, tracing, debugging, etc.). Device creation is extremely complicated because you have to launch the external daemon and somehow configure that. I have no objection to remote device passthrough but I don't think remote device emulation is right for QEMU today. After talking to Alon in IRC, I think a better model for Spice would be to integrate the smart card emulation into QEMU and then develop a specific protocol for the smart card emulation to interface with the physical smart card. This interface isn't really any different than the network interface or the block interface in QEMU today. Regards, Anthony Liguori > It now appears to me that qemu punts on this case, except for the > keyboard and mouse -- well maybe not punts, but simply doesn't support > any device that isn't on the host machine. If you look at the way qemu > handles the sound device, for instance. Normally you want the sound to > come out the speakers of the controlling console, not a random server > that's hosting the guest. However, straight qemu doesn't handle things > that way. The sound (if it comes out at all) comes out the server that > qemu is installed on. When you migrate qemu, the sound now comes out the > new server. > > This probably isn't a problem since most of the time someone is using > the speaker, he's got the case where host == client. In that case it > makes perfect sense to put the emulator inside qemu. In the case where > we are running a hosted server service, it's highly unlikely anyone is > going to be using sound (or an attached webcam, etc.). In fact migration > for these devices are really a noop. > > Smart cards are really like these devices. In fact more than a few > keyboards have built in smart card readers. The smart card model is I > want the smart card at the same location as my keyboard and mouse. I use > that set of smart cards to authenticate. The use case on machines > running with a server is that some customers have a requirement that you > need the smart card to log in and administer those machines. Those smart > cards are ones the operator carries with him, not ones that would sit on > some server farm. For their requirements, one needs a way to get back to > the local client. > > As I said before, I don't think this requirement is unique. The only way > to handle it is to run code on the client machine. The devices that run > on that client are ones you don't migrate with qemu, but stay with the > client itself and reconnect to the new instance. I agree that having a > daemon for each devices will eventually become unweildy. It looks like > spice is the answer for this scenario. If you have devices other than > the mouse/keyboard/display that are located on the client == host, then > you should assume the need for spice and not use straight qemu? > > In that world it makes sense to have a single protocol (passthru). It's > ok to integrate the smart card emul directly into qemu because it's > really only used either in the case where client != host, or in the case > where your server hardware has some smart card installed that is uses > for authentication. (NOTE: in this case, migrate means that the server > will loose authentication and have to authenticate with the new smart > card on the new host... I don't know how useful this really is, but I > think it's important to point out that migrate with smart cards means > something different than most devices. It means you have become a new > entity, not a continuation of the old... it's the equivalent of pulling > a smart card on a server and inserting a new one). > > So if my understanding is correct, as long as you are willing to deal > with the card plug/unplug scenario on migration, it makes sense for qemu > to have passthru plus a local emulated smart card which goes directly to > local hardward. If you need to have the 'console' experience, then you > turn on spice and emulate the card in the spice client. > > bob > > > > > > > > [-- Attachment #2: Type: text/html, Size: 7353 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-14 18:52 ` Anthony Liguori @ 2010-10-14 22:03 ` Robert Relyea 2010-10-14 22:16 ` Anthony Liguori 0 siblings, 1 reply; 16+ messages in thread From: Robert Relyea @ 2010-10-14 22:03 UTC (permalink / raw) To: Anthony Liguori; +Cc: Alon Levy, qemu-devel [-- Attachment #1.1: Type: text/plain, Size: 7503 bytes --] On 10/14/2010 11:52 AM, Anthony Liguori wrote: > On 10/14/2010 01:37 PM, Robert Relyea wrote: >> Anthony Liguori wrote: >> >> >>> > And how does the smart card state get migrated during migration? How >>> > do you keep it synced with QEMU? >>> > >>> > I don't understand the use-case behind this. Is this so that a local >>> > physical smart card can be passed through to a guest from a Spice >>> > client and when migration happens, the QEMU instance connects back to >>> > the Spice client? So the device is never actually migrated? >>> >> A lot of this discussion has confused me until I realized we are talking >> 2 different models. >> >> My current understanding is that qemu assumes that all devices are local >> to the qemu instance (that is on the host). When you migrate you want to >> connect to the new hardware on the new host, not feed back to some >> general client. The only exception seems to be mouse and keyboard, where >> qemu depends on some external protocol (vncclient or xdesktop or the x >> protocol itself) to transport the mouse and keyboard events. >> >> Our model has been that the smart card is local to the user/client -- >> like the mouse and keyboard. When you migrate qemu you do not migrate >> the smart card itself, since it's still physically on your client >> machine (like the mouse and keyboard), and needs to be managed by the >> local drivers on that client machine (which knows how to talk to the >> specific smart card installed there). So the daemon stays right where >> it's at and connects to the new qemu instance as it comes up. This is >> where I think I was confused about your migration question. I think you >> are assuming that the smart card itself connects to new hardware on the >> new host, meaning the daemon itself needs to move. If that is the >> semantic you are trying to present, then you are quite right, it's >> ludicrous to have the external daemon as part of the emulation. >> > > > Remote device passthrough is just a special case of passthrough. It's > got interesting characteristics in that unlike local device > passthrough, if you preserve the connection to the remove device, > migration is still possible. > > However, remote device *emulation* is the thing that I'm concerned > about. Having a device emulated outside of QEMU means that it's not > possible to participate in many of QEMU's features (like live > migration, tracing, debugging, etc.). Device creation is extremely > complicated because you have to launch the external daemon and somehow > configure that. There's always some emulation going on on the client side. The client side has the device drivers, so you are either emulating an actual device or you are emulating the abstraction you invent. Once you have the client side, you have to launch the external daemon anyway. It seems to me that the best way to go is to provide the native host == client support like other devices and allow the passthru. If you really need client support, just run spice (which is a single client daemon that handles everything). > > I have no objection to remote device passthrough but I don't think > remote device emulation is right for QEMU today. Probably right for raw qemu. > > After talking to Alon in IRC, I think a better model for Spice would > be to integrate the smart card emulation into QEMU and then develop a > specific protocol for the smart card emulation to interface with the > physical smart card. This interface isn't really any different than > the network interface or the block interface in QEMU today. I seems to me that a second protocol is overkill. Having 2 protocols is a bit much to manage. We can do everything we need with the passthru. My worry about creating any thing else is we may not have the flexibility to handle future cards. Smart cards themselves are programmable, so the interface for new cards are pretty dynamic. bob > > Regards, > > Anthony Liguori > >> It now appears to me that qemu punts on this case, except for the >> keyboard and mouse -- well maybe not punts, but simply doesn't support >> any device that isn't on the host machine. If you look at the way qemu >> handles the sound device, for instance. Normally you want the sound to >> come out the speakers of the controlling console, not a random server >> that's hosting the guest. However, straight qemu doesn't handle things >> that way. The sound (if it comes out at all) comes out the server that >> qemu is installed on. When you migrate qemu, the sound now comes out the >> new server. >> >> This probably isn't a problem since most of the time someone is using >> the speaker, he's got the case where host == client. In that case it >> makes perfect sense to put the emulator inside qemu. In the case where >> we are running a hosted server service, it's highly unlikely anyone is >> going to be using sound (or an attached webcam, etc.). In fact migration >> for these devices are really a noop. >> >> Smart cards are really like these devices. In fact more than a few >> keyboards have built in smart card readers. The smart card model is I >> want the smart card at the same location as my keyboard and mouse. I use >> that set of smart cards to authenticate. The use case on machines >> running with a server is that some customers have a requirement that you >> need the smart card to log in and administer those machines. Those smart >> cards are ones the operator carries with him, not ones that would sit on >> some server farm. For their requirements, one needs a way to get back to >> the local client. >> >> As I said before, I don't think this requirement is unique. The only way >> to handle it is to run code on the client machine. The devices that run >> on that client are ones you don't migrate with qemu, but stay with the >> client itself and reconnect to the new instance. I agree that having a >> daemon for each devices will eventually become unweildy. It looks like >> spice is the answer for this scenario. If you have devices other than >> the mouse/keyboard/display that are located on the client == host, then >> you should assume the need for spice and not use straight qemu? >> >> In that world it makes sense to have a single protocol (passthru). It's >> ok to integrate the smart card emul directly into qemu because it's >> really only used either in the case where client != host, or in the case >> where your server hardware has some smart card installed that is uses >> for authentication. (NOTE: in this case, migrate means that the server >> will loose authentication and have to authenticate with the new smart >> card on the new host... I don't know how useful this really is, but I >> think it's important to point out that migrate with smart cards means >> something different than most devices. It means you have become a new >> entity, not a continuation of the old... it's the equivalent of pulling >> a smart card on a server and inserting a new one). >> >> So if my understanding is correct, as long as you are willing to deal >> with the card plug/unplug scenario on migration, it makes sense for qemu >> to have passthru plus a local emulated smart card which goes directly to >> local hardward. If you need to have the 'console' experience, then you >> turn on spice and emulate the card in the spice client. >> >> bob >> >> >> >> >> >> >> >> > [-- Attachment #1.2: Type: text/html, Size: 8915 bytes --] [-- Attachment #2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 6014 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-14 22:03 ` Robert Relyea @ 2010-10-14 22:16 ` Anthony Liguori 2010-10-15 0:16 ` Robert Relyea 0 siblings, 1 reply; 16+ messages in thread From: Anthony Liguori @ 2010-10-14 22:16 UTC (permalink / raw) To: Robert Relyea; +Cc: Alon Levy, qemu-devel [-- Attachment #1: Type: text/plain, Size: 6626 bytes --] On 10/14/2010 05:03 PM, Robert Relyea wrote: >> Remote device passthrough is just a special case of passthrough. >> It's got interesting characteristics in that unlike local device >> passthrough, if you preserve the connection to the remove device, >> migration is still possible. >> >> However, remote device *emulation* is the thing that I'm concerned >> about. Having a device emulated outside of QEMU means that it's not >> possible to participate in many of QEMU's features (like live >> migration, tracing, debugging, etc.). Device creation is extremely >> complicated because you have to launch the external daemon and >> somehow configure that. > There's always some emulation going on on the client side. The client > side has the device drivers, so you are either emulating an actual > device or you are emulating the abstraction you invent. Once you have > the client side, you have to launch the external daemon anyway. That's not a very convincing argument. It's pretty simple really. We don't want to split QEMU into a bunch of different daemons that all implement device emulation in slightly different ways. The user complexity is enormous and the ability to manage the complexity because impossible because nothing is centralized. > It seems to me that the best way to go is to provide the native host > == client support like other devices and allow the passthru. If you > really need client support, just run spice (which is a single client > daemon that handles everything). Let's not confuse passthrough with implementing device emulation outside of QEMU. They are two very different things. I think a remote passthrough protocol who's sole purpose is to allow external device emulation is a bad idea for QEMU. >> >> After talking to Alon in IRC, I think a better model for Spice would >> be to integrate the smart card emulation into QEMU and then develop a >> specific protocol for the smart card emulation to interface with the >> physical smart card. This interface isn't really any different than >> the network interface or the block interface in QEMU today. > I seems to me that a second protocol is overkill. Having 2 protocols > is a bit much to manage. We can do everything we need with the passthru. How is external device emulation not overkill? I don't see why two protocols are necessary. You just need one. > My worry about creating any thing else is we may not have the > flexibility to handle future cards. Smart cards themselves are > programmable, so the interface for new cards are pretty dynamic. My worry is that we're creating an impossible situation to maintain in the long term because device emulation is happening in 10 different places. If there's a bug in your smart card emulation, a guest can now break into a Spice client. Part of the advantage of keeping everything contained in a single place (QEMU) is that we can restrict QEMU from a security perspective via sVirt and other mechanisms. Once you split apart device emulation, you break that security model. Regards, Anthony Liguori > bob >> >> Regards, >> >> Anthony Liguori >> >>> It now appears to me that qemu punts on this case, except for the >>> keyboard and mouse -- well maybe not punts, but simply doesn't support >>> any device that isn't on the host machine. If you look at the way qemu >>> handles the sound device, for instance. Normally you want the sound to >>> come out the speakers of the controlling console, not a random server >>> that's hosting the guest. However, straight qemu doesn't handle things >>> that way. The sound (if it comes out at all) comes out the server that >>> qemu is installed on. When you migrate qemu, the sound now comes out the >>> new server. >>> >>> This probably isn't a problem since most of the time someone is using >>> the speaker, he's got the case where host == client. In that case it >>> makes perfect sense to put the emulator inside qemu. In the case where >>> we are running a hosted server service, it's highly unlikely anyone is >>> going to be using sound (or an attached webcam, etc.). In fact migration >>> for these devices are really a noop. >>> >>> Smart cards are really like these devices. In fact more than a few >>> keyboards have built in smart card readers. The smart card model is I >>> want the smart card at the same location as my keyboard and mouse. I use >>> that set of smart cards to authenticate. The use case on machines >>> running with a server is that some customers have a requirement that you >>> need the smart card to log in and administer those machines. Those smart >>> cards are ones the operator carries with him, not ones that would sit on >>> some server farm. For their requirements, one needs a way to get back to >>> the local client. >>> >>> As I said before, I don't think this requirement is unique. The only way >>> to handle it is to run code on the client machine. The devices that run >>> on that client are ones you don't migrate with qemu, but stay with the >>> client itself and reconnect to the new instance. I agree that having a >>> daemon for each devices will eventually become unweildy. It looks like >>> spice is the answer for this scenario. If you have devices other than >>> the mouse/keyboard/display that are located on the client == host, then >>> you should assume the need for spice and not use straight qemu? >>> >>> In that world it makes sense to have a single protocol (passthru). It's >>> ok to integrate the smart card emul directly into qemu because it's >>> really only used either in the case where client != host, or in the case >>> where your server hardware has some smart card installed that is uses >>> for authentication. (NOTE: in this case, migrate means that the server >>> will loose authentication and have to authenticate with the new smart >>> card on the new host... I don't know how useful this really is, but I >>> think it's important to point out that migrate with smart cards means >>> something different than most devices. It means you have become a new >>> entity, not a continuation of the old... it's the equivalent of pulling >>> a smart card on a server and inserting a new one). >>> >>> So if my understanding is correct, as long as you are willing to deal >>> with the card plug/unplug scenario on migration, it makes sense for qemu >>> to have passthru plus a local emulated smart card which goes directly to >>> local hardward. If you need to have the 'console' experience, then you >>> turn on spice and emulate the card in the spice client. >>> >>> bob >>> >>> >>> >>> >>> >>> >>> >>> >> > [-- Attachment #2: Type: text/html, Size: 7546 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) 2010-10-14 22:16 ` Anthony Liguori @ 2010-10-15 0:16 ` Robert Relyea 0 siblings, 0 replies; 16+ messages in thread From: Robert Relyea @ 2010-10-15 0:16 UTC (permalink / raw) To: Anthony Liguori; +Cc: Alon Levy, qemu-devel [-- Attachment #1.1: Type: text/plain, Size: 4928 bytes --] On 10/14/2010 03:16 PM, Anthony Liguori wrote: > On 10/14/2010 05:03 PM, Robert Relyea wrote: >>> Remote device passthrough is just a special case of passthrough. >>> It's got interesting characteristics in that unlike local device >>> passthrough, if you preserve the connection to the remove device, >>> migration is still possible. >>> >>> However, remote device *emulation* is the thing that I'm concerned >>> about. Having a device emulated outside of QEMU means that it's not >>> possible to participate in many of QEMU's features (like live >>> migration, tracing, debugging, etc.). Device creation is extremely >>> complicated because you have to launch the external daemon and >>> somehow configure that. >> There's always some emulation going on on the client side. The client >> side has the device drivers, so you are either emulating an actual >> device or you are emulating the abstraction you invent. Once you have >> the client side, you have to launch the external daemon anyway. > > That's not a very convincing argument. Neither is that;). My point is that no matter what you do, there is *always* some sort of client emulation going on and the client is the only one in this scenario that has access to the local drivers. This is all moot. The only client side qemu supports is vnc/X/xdesktop. All those devices have client side drivers that are emulating the overall protocol. > > It's pretty simple really. We don't want to split QEMU into a bunch > of different daemons that all implement device emulation in slightly > different ways. The user complexity is enormous and the ability to > manage the complexity because impossible because nothing is centralized. I think you misunderstand me. In some sense I'm agreeing with you. I agree you don't want to split QEMU into a bunch of daemons, which is why I think you handle the smart card remotely only with spice. Currently QEMU doesn't have the infrastructure to handle lots of different client devices (pretty much only if there is some preexisting client like vnc that handles those things). In some sense we seem to be talking cross purposes here. I agree that QEMU isn't the right place to handle client side devices. It's clearly not in the QEMU model, so it makes sense NOT to emulate on the client side for QEMU... > >> It seems to me that the best way to go is to provide the native host >> == client support like other devices and allow the passthru. If you >> really need client support, just run spice (which is a single client >> daemon that handles everything). > > Let's not confuse passthrough with implementing device emulation > outside of QEMU. They are two very different things. > > I think a remote passthrough protocol who's sole purpose is to allow > external device emulation is a bad idea for QEMU. The passthru is passthru. I'm not sure what you mean here.... I'm presuming the way forward is to have passthru and qemu implementing a local smart card emulation. I'm fine with just passthru and local emulation to a local smart card. > >>> >>> After talking to Alon in IRC, I think a better model for Spice would >>> be to integrate the smart card emulation into QEMU and then develop >>> a specific protocol for the smart card emulation to interface with >>> the physical smart card. This interface isn't really any different >>> than the network interface or the block interface in QEMU today. >> I seems to me that a second protocol is overkill. Having 2 protocols >> is a bit much to manage. We can do everything we need with the passthru. > > How is external device emulation not overkill? I don't see why two > protocols are necessary. You just need one. If you have one for passthru and one for emulated cards, that's two protocols. > >> My worry about creating any thing else is we may not have the >> flexibility to handle future cards. Smart cards themselves are >> programmable, so the interface for new cards are pretty dynamic. > > My worry is that we're creating an impossible situation to maintain in > the long term because device emulation is happening in 10 different > places. If there's a bug in your smart card emulation, a guest can > now break into a Spice client. Part of the advantage of keeping > everything contained in a single place (QEMU) is that we can restrict > QEMU from a security perspective via sVirt and other mechanisms. Once > you split apart device emulation, you break that security model. That's true whether I'm emulating on qemu or not. If there is a bug in the emulation code, you can break out. If there is a bug in the client side driver, you can break out. The risk is exactly the same. But again, this is academic, I'm not advocating doing this in qemu. Clearly there needs to be more work before we can even talk about qemu client side devices where client != host. bob [-- Attachment #1.2: Type: text/html, Size: 6146 bytes --] [-- Attachment #2: S/MIME Cryptographic Signature --] [-- Type: application/pkcs7-signature, Size: 6014 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2010-10-15 0:16 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-10-12 12:58 [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 1/2] usb-ccid: add CCID device. add configure option Alon Levy 2010-10-12 12:58 ` [Qemu-devel] [PATCH 2/2] usb-ccid: add CCID device (device itself) Alon Levy 2010-10-12 13:24 ` [Qemu-devel] [PATCH 0/2] usb-ccid device (v2) Anthony Liguori [not found] <1045788737.212361286898758903.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com> 2010-10-12 16:03 ` Alon Levy 2010-10-12 16:21 ` Anthony Liguori [not found] <593949580.216281286900989465.JavaMail.root@zmail06.collab.prod.int.phx2.redhat.com> 2010-10-12 16:43 ` Alon Levy 2010-10-12 16:49 ` Anthony Liguori 2010-10-12 17:09 ` Alon Levy 2010-10-12 18:23 ` Anthony Liguori 2010-10-13 11:54 ` Alon Levy -- strict thread matches above, loose matches on Subject: below -- 2010-10-14 18:37 Robert Relyea 2010-10-14 18:52 ` Anthony Liguori 2010-10-14 22:03 ` Robert Relyea 2010-10-14 22:16 ` Anthony Liguori 2010-10-15 0:16 ` Robert Relyea
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).