/* $Id: UsbCardReader.cpp 57546 2015-08-26 10:25:36Z vboxsync $ */ /** @file * UsbCardReader - Driver Interface to USB Smart Card Reader emulation. */ /* * Copyright (C) 2011-2014 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /********************************************************************************************************************************* * Header Files * *********************************************************************************************************************************/ #define LOG_GROUP LOG_GROUP_USB_CARDREADER #include "UsbCardReader.h" #include "ConsoleImpl.h" #include "ConsoleVRDPServer.h" #include #include #include /********************************************************************************************************************************* * Structures and Typedefs * *********************************************************************************************************************************/ typedef struct USBCARDREADER USBCARDREADER; typedef struct USBCARDREADER *PUSBCARDREADER; struct USBCARDREADER { UsbCardReader *pUsbCardReader; PPDMDRVINS pDrvIns; PDMICARDREADERDOWN ICardReaderDown; PPDMICARDREADERUP pICardReaderUp; /* Thread handling Cmd to card reader */ PPDMTHREAD pThrCardReaderCmd; /* Queue handling requests to cardreader */ RTREQQUEUE hReqQCardReaderCmd; }; /* * Command queue's callbacks. */ static DECLCALLBACK(void) drvCardReaderCmdStatusChange(PUSBCARDREADER pThis, void *pvUser, uint32_t u32Timeout, PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats) { LogFlowFunc(("ENTER: pvUser:%p, u32Timeout:%d\n", pvUser, u32Timeout)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnSetStatusChange(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, paReaderStats, cReaderStats); } else { pUsbCardReader->GetStatusChange(pThis, pvUser, u32Timeout, paReaderStats, cReaderStats); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdEstablishContext(PUSBCARDREADER pThis) { LogFlowFunc(("\n")); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnEstablishContext(pThis->pICardReaderUp, VRDE_SCARD_E_NO_SMARTCARD); } else { pUsbCardReader->EstablishContext(pThis); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdReleaseContext(PUSBCARDREADER pThis, void *pvUser) { LogFlowFunc(("ENTER: pvUser:%p\n", pvUser)); NOREF(pvUser); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { /* Do nothing. */ } else { pUsbCardReader->ReleaseContext(pThis); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdStatus(PUSBCARDREADER pThis, void *pvUser) { LogFlowFunc(("ENTER: pvUser:%p\n", pvUser)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnStatus(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, /* pszReaderName */ NULL, /* cchReaderName */ 0, /* u32CardState */ 0, /* u32Protocol */ 0, /* pu8Atr */ 0, /* cbAtr */ 0); } else { pUsbCardReader->Status(pThis, pvUser); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdConnect(PUSBCARDREADER pThis, void *pvUser, const char *pcszCardReaderName, uint32_t u32ShareMode, uint32_t u32PreferredProtocols) { LogFlowFunc(("ENTER: pvUser:%p, pcszCardReaderName:%s, u32ShareMode:%RX32, u32PreferredProtocols:%RX32\n", pvUser, pcszCardReaderName, u32ShareMode, u32PreferredProtocols)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnConnect(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, 0); } else { pUsbCardReader->Connect(pThis, pvUser, pcszCardReaderName, u32ShareMode, u32PreferredProtocols); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdDisconnect(PUSBCARDREADER pThis, void *pvUser, uint32_t u32Disposition) { LogFlowFunc(("ENTER: pvUser:%p, u32Disposition:%RX32\n", pvUser, u32Disposition)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnDisconnect(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD); } else { pUsbCardReader->Disconnect(pThis, pvUser, u32Disposition); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdTransmit(PUSBCARDREADER pThis, void *pvUser, PDMICARDREADER_IO_REQUEST *pioSendRequest, uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer) { LogFlowFunc(("ENTER: pvUser:%p, pioSendRequest:%p, pu8SendBuffer:%p, cbSendBuffer:%d, cbRecvBuffer:%d\n", pvUser, pioSendRequest, pu8SendBuffer, cbSendBuffer, cbRecvBuffer)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnTransmit(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, /* pioRecvPci */ NULL, /* pu8RecvBuffer */ NULL, /* cbRecvBuffer*/ 0); } else { pUsbCardReader->Transmit(pThis, pvUser, pioSendRequest, pu8SendBuffer, cbSendBuffer, cbRecvBuffer); } /* Clean up buffers allocated by driver */ RTMemFree(pioSendRequest); RTMemFree(pu8SendBuffer); LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdGetAttr(PUSBCARDREADER pThis, void *pvUser, uint32_t u32AttrId, uint32_t cbAttrib) { LogFlowFunc(("ENTER: pvUser:%p, u32AttrId:%RX32, cbAttrib:%d\n", pvUser, u32AttrId, cbAttrib)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnGetAttrib(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, u32AttrId, /* pvAttrib */ NULL, /* cbAttrib */ 0); } else { pUsbCardReader->GetAttrib(pThis, pvUser, u32AttrId, cbAttrib); } LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdSetAttr(PUSBCARDREADER pThis, void *pvUser, uint32_t u32AttrId, void *pvAttrib, uint32_t cbAttrib) { LogFlowFunc(("ENTER: pvUser:%p, u32AttrId:%RX32, pvAttrib:%p, cbAttrib:%d\n", pvUser, u32AttrId, pvAttrib, cbAttrib)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnSetAttrib(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, u32AttrId); } else { pUsbCardReader->SetAttrib(pThis, pvUser, u32AttrId, (uint8_t *)pvAttrib, cbAttrib); } /* Clean up buffers allocated by driver */ RTMemFree(pvAttrib); LogFlowFuncLeave(); } static DECLCALLBACK(void) drvCardReaderCmdControl(PUSBCARDREADER pThis, void *pvUser, uint32_t u32ControlCode, void *pvInBuffer, uint32_t cbInBuffer, uint32_t cbOutBuffer) { LogFlowFunc(("ENTER: pvUser:%p, u32ControlCode:%RX32, pvInBuffer:%p, cbInBuffer:%d, cbOutBuffer:%d\n", pvUser, u32ControlCode, pvInBuffer, cbInBuffer, cbOutBuffer)); UsbCardReader *pUsbCardReader = pThis->pUsbCardReader; if (!pUsbCardReader) { pThis->pICardReaderUp->pfnControl(pThis->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, u32ControlCode, /* pvOutBuffer */ NULL, /* cbOutBuffer */ 0); } else { pUsbCardReader->Control(pThis, pvUser, u32ControlCode, (uint8_t *)pvInBuffer, cbInBuffer, cbOutBuffer); } /* Clean up buffers allocated by driver */ RTMemFree(pvInBuffer); LogFlowFuncLeave(); } /* * PDMICARDREADERDOWN - interface */ static DECLCALLBACK(int) drvCardReaderDownConnect(PPDMICARDREADERDOWN pInterface, void *pvUser, const char *pcszCardReaderName, uint32_t u32ShareMode, uint32_t u32PreferredProtocols) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pcszCardReaderName:%s, pvUser:%p, u32ShareMode:%RX32, u32PreferredProtocols:%RX32\n", pcszCardReaderName, pvUser, u32ShareMode, u32PreferredProtocols)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdConnect, 5, pThis, pvUser, pcszCardReaderName, u32ShareMode, u32PreferredProtocols); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownDisconnect(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, u32Disposition:%RX32\n", pvUser, u32Disposition)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdDisconnect, 3, pThis, pvUser, u32Disposition); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownEstablishContext(PPDMICARDREADERDOWN pInterface) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER:\n")); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdEstablishContext, 1, pThis); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownReleaseContext(PPDMICARDREADERDOWN pInterface, void *pvUser) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p\n", pvUser)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); /* @todo Device calls this when the driver already destroyed. */ if (pThis->hReqQCardReaderCmd == NIL_RTREQQUEUE) { LogFlowFunc(("LEAVE: device already deleted.\n")); return VINF_SUCCESS; } int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdReleaseContext, 2, pThis, pvUser); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownStatus(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t cchReaderName, uint32_t cbAtrLen) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, cchReaderName:%d, cbAtrLen:%d\n", pvUser, cchReaderName, cbAtrLen)); NOREF(cchReaderName); NOREF(cbAtrLen); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdStatus, 2, pThis, pvUser); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownGetStatusChange(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Timeout, PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, u32Timeout:%d, cReaderStats:%d\n", pvUser, u32Timeout, cReaderStats)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdStatusChange, 5, pThis, pvUser, u32Timeout, paReaderStats, cReaderStats); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownBeginTransaction(PPDMICARDREADERDOWN pInterface, void *pvUser) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p\n", pvUser)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = VERR_NOT_SUPPORTED; AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownEndTransaction(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, u32Disposition:%RX32\n", pvUser, u32Disposition)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = VERR_NOT_SUPPORTED; AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownTransmit(PPDMICARDREADERDOWN pInterface, void *pvUser, const PDMICARDREADER_IO_REQUEST *pioSendRequest, const uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, pioSendRequest:%p, pu8SendBuffer:%p, cbSendBuffer:%d, cbRecvBuffer:%d\n", pvUser, pioSendRequest, pu8SendBuffer, cbSendBuffer, cbRecvBuffer)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); uint8_t *pu8SendBufferCopy = NULL; if ( pu8SendBuffer && cbSendBuffer) { pu8SendBufferCopy = (uint8_t *)RTMemDup(pu8SendBuffer, cbSendBuffer); if (!pu8SendBufferCopy) { return VERR_NO_MEMORY; } } PDMICARDREADER_IO_REQUEST *pioSendRequestCopy = NULL; if (pioSendRequest) { pioSendRequestCopy = (PDMICARDREADER_IO_REQUEST *)RTMemDup(pioSendRequest, pioSendRequest->cbPciLength); if (!pioSendRequestCopy) { RTMemFree(pu8SendBufferCopy); return VERR_NO_MEMORY; } } int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0,RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdTransmit, 6, pThis, pvUser, pioSendRequestCopy, pu8SendBufferCopy, cbSendBuffer, cbRecvBuffer); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownGetAttr(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32AttribId, uint32_t cbAttrib) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, u32AttribId:%RX32, cbAttrib:%d\n", pvUser, u32AttribId, cbAttrib)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdGetAttr, 4, pThis, pvUser, u32AttribId, cbAttrib); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownSetAttr(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32AttribId, const void *pvAttrib, uint32_t cbAttrib) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, u32AttribId:%RX32, pvAttrib:%p, cbAttrib:%d\n", pvUser, u32AttribId, pvAttrib, cbAttrib)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); void *pvAttribCopy = NULL; if ( pvAttrib && cbAttrib) { pvAttribCopy = RTMemDup(pvAttrib, cbAttrib); AssertPtrReturn(pvAttribCopy, VERR_NO_MEMORY); } int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdSetAttr, 5, pThis, pvUser, u32AttribId, pvAttribCopy, cbAttrib); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static DECLCALLBACK(int) drvCardReaderDownControl(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32ControlCode, const void *pvInBuffer, uint32_t cbInBuffer, uint32_t cbOutBuffer) { AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); LogFlowFunc(("ENTER: pvUser:%p, u32ControlCode:%RX32 pvInBuffer:%p, cbInBuffer:%d, cbOutBuffer:%d\n", pvUser, u32ControlCode, pvInBuffer, cbInBuffer, cbOutBuffer)); PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown); void *pvInBufferCopy = NULL; if ( pvInBuffer && cbInBuffer) { pvInBufferCopy = RTMemDup(pvInBuffer, cbInBuffer); AssertReturn(pvInBufferCopy, VERR_NO_MEMORY); } int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT, (PFNRT)drvCardReaderCmdControl, 6, pThis, pvUser, u32ControlCode, pvInBufferCopy, cbInBuffer, cbOutBuffer); AssertRC(rc); LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } /* * Cardreader driver thread routines */ static DECLCALLBACK(int) drvCardReaderThreadCmd(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) { int rc = VINF_SUCCESS; PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); LogFlowFunc(("ENTER: pDrvIns:%d, state %d\n", pDrvIns->iInstance, pThread->enmState)); if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) { LogFlowFunc(("LEAVE: INITIALIZING: VINF_SUCCESS\n")); return VINF_SUCCESS; } while (pThread->enmState == PDMTHREADSTATE_RUNNING) { rc = RTReqQueueProcess(pThis->hReqQCardReaderCmd, RT_INDEFINITE_WAIT); AssertMsg(rc == VWRN_STATE_CHANGED, ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n", rc)); } LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } static int drvCardReaderWakeupFunc(PUSBCARDREADER pThis) { NOREF(pThis); /* Returning a VINF_* will cause RTReqQueueProcess return. */ return VWRN_STATE_CHANGED; } static DECLCALLBACK(int) drvCardReaderThreadCmdWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) { LogFlowFunc(("ENTER: pDrvIns:%i\n", pDrvIns->iInstance)); PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); AssertReturn(pThis->hReqQCardReaderCmd != NIL_RTREQQUEUE, VERR_INVALID_STATE); PRTREQ pReq; int rc = RTReqQueueCall(pThis->hReqQCardReaderCmd, &pReq, 10000, (PFNRT)drvCardReaderWakeupFunc, 1, pThis); AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n", rc)); if (RT_SUCCESS(rc)) RTReqRelease(pReq); /* @todo handle VERR_TIMEOUT */ return rc; } /* * USB Card reader driver implementation. */ UsbCardReader::UsbCardReader(Console *console) : mpDrv(NULL), mParent(console), m_pRemote(NULL) { LogFlowFunc(("\n")); } UsbCardReader::~UsbCardReader() { LogFlowFunc(("mpDrv %p\n", mpDrv)); if (mpDrv) { mpDrv->pUsbCardReader = NULL; mpDrv = NULL; } } typedef struct UCRREMOTEREADER { bool fAvailable; char szReaderName[1024]; bool fHandle; VRDESCARDHANDLE hCard; } UCRREMOTEREADER; struct UCRREMOTE { UsbCardReader *pUsbCardReader; /* The remote identifiers. */ uint32_t u32ClientId; uint32_t u32DeviceId; bool fContext; VRDESCARDCONTEXT context; /* Possible a few readers. Currently only one. */ UCRREMOTEREADER reader; }; typedef struct UCRREQCTX { UCRREMOTE *pRemote; uint32_t u32Function; void *pvUser; union { struct { PDMICARDREADER_READERSTATE *paReaderStats; uint32_t cReaderStats; } GetStatusChange; struct { uint32_t u32AttrId; } GetAttrib; struct { uint32_t u32AttrId; } SetAttrib; struct { uint32_t u32ControlCode; } Control; } u; } UCRREQCTX; int UsbCardReader::vrdeSCardRequest(void *pvUser, uint32_t u32Function, const void *pvData, uint32_t cbData) { int rc = mParent->i_consoleVRDPServer()->SCardRequest(pvUser, u32Function, pvData, cbData); LogFlowFunc(("%d %Rrc\n", u32Function, rc)); return rc; } int UsbCardReader::VRDENotify(uint32_t u32Id, void *pvData, uint32_t cbData) { int rc = VINF_SUCCESS; switch (u32Id) { case VRDE_SCARD_NOTIFY_ATTACH: { VRDESCARDNOTIFYATTACH *p = (VRDESCARDNOTIFYATTACH *)pvData; Assert(cbData == sizeof(VRDESCARDNOTIFYATTACH)); LogFlowFunc(("[%d,%d]\n", p->u32ClientId, p->u32DeviceId)); /* Add this remote instance, which allow access to card readers attached to the client, to the list. * @todo currently only one device is allowed. */ if (m_pRemote) { AssertFailed(); rc = VERR_NOT_SUPPORTED; break; } UCRREMOTE *pRemote = (UCRREMOTE *)RTMemAllocZ(sizeof(UCRREMOTE)); if (pRemote == NULL) { rc = VERR_NO_MEMORY; break; } pRemote->pUsbCardReader = this; pRemote->u32ClientId = p->u32ClientId; pRemote->u32DeviceId = p->u32DeviceId; m_pRemote = pRemote; /* Try to establish a context. */ VRDESCARDESTABLISHCONTEXTREQ req; req.u32ClientId = m_pRemote->u32ClientId; req.u32DeviceId = m_pRemote->u32DeviceId; rc = vrdeSCardRequest(m_pRemote, VRDE_SCARD_FN_ESTABLISHCONTEXT, &req, sizeof(req)); LogFlowFunc(("sent ESTABLISHCONTEXT\n")); } break; case VRDE_SCARD_NOTIFY_DETACH: { VRDESCARDNOTIFYDETACH *p = (VRDESCARDNOTIFYDETACH *)pvData; Assert(cbData == sizeof(VRDESCARDNOTIFYDETACH)); /* @todo Just free. There should be no pending requests, because VRDP cancels them. */ RTMemFree(m_pRemote); m_pRemote = NULL; } break; default: rc = VERR_INVALID_PARAMETER; AssertFailed(); break; } return rc; } int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Function, void *pvData, uint32_t cbData) { int rc = VINF_SUCCESS; LogFlowFunc(("%Rrc %p %u %p %u\n", rcRequest, pvUser, u32Function, pvData, cbData)); switch (u32Function) { case VRDE_SCARD_FN_ESTABLISHCONTEXT: { Assert(cbData == sizeof(VRDESCARDESTABLISHCONTEXTRSP) || RT_FAILURE(rcRequest)); VRDESCARDESTABLISHCONTEXTRSP *pRsp = (VRDESCARDESTABLISHCONTEXTRSP *)pvData; UCRREMOTE *pRemote = (UCRREMOTE *)pvUser; /* Check if the context was created. */ Assert(!pRemote->fContext); if ( RT_SUCCESS(rcRequest) && pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { pRemote->fContext = true; pRemote->context = pRsp->Context; LogFlowFunc(("ESTABLISHCONTEXT success\n")); /* Now list readers attached to the remote client. */ VRDESCARDLISTREADERSREQ req; req.Context = pRemote->context; rc = vrdeSCardRequest(pRemote, VRDE_SCARD_FN_LISTREADERS, &req, sizeof(req)); } } break; case VRDE_SCARD_FN_LISTREADERS: { Assert(cbData == sizeof(VRDESCARDLISTREADERSRSP) || RT_FAILURE(rcRequest)); VRDESCARDLISTREADERSRSP *pRsp = (VRDESCARDLISTREADERSRSP *)pvData; UCRREMOTE *pRemote = (UCRREMOTE *)pvUser; Assert(pRemote->fContext); if ( RT_SUCCESS(rcRequest) && pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS && pRemote->fContext) { LogFlowFunc(("LISTREADERS: cReaders %d\n", pRsp->cReaders)); uint32_t i; for (i = 0; i < pRsp->cReaders; i++) { LogFlowFunc(("LISTREADERS: [%d] [%s]\n", i, pRsp->apszNames[i])); /* @todo only the first reader is supported. */ if (i != 0) { continue; } RTStrCopy(pRemote->reader.szReaderName, sizeof(pRemote->reader.szReaderName), pRsp->apszNames[i]); pRemote->reader.fHandle = false; pRemote->reader.fAvailable = true; } } } break; case VRDE_SCARD_FN_RELEASECONTEXT: { Assert(cbData == sizeof(VRDESCARDRELEASECONTEXTRSP) || RT_FAILURE(rcRequest)); VRDESCARDRELEASECONTEXTRSP *pRsp = (VRDESCARDRELEASECONTEXTRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("RELEASECONTEXT completed\n")); /* No notification is expected here by the caller. */ Assert(!m_pRemote->fContext); } break; case VRDE_SCARD_FN_GETSTATUSCHANGE: { Assert(cbData == sizeof(VRDESCARDGETSTATUSCHANGERSP) || RT_FAILURE(rcRequest)); VRDESCARDGETSTATUSCHANGERSP *pRsp = (VRDESCARDGETSTATUSCHANGERSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("GETSTATUSCHANGE\n")); uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { uint32_t i; for (i = 0; i < pRsp->cReaders; i++) { LogFlowFunc(("GETSTATUSCHANGE: [%d] %RX32\n", i, pRsp->aReaderStates[i].u32EventState)); /* @todo only the first reader is supported. */ if (i != 0) { continue; } if (i >= pCtx->u.GetStatusChange.cReaderStats) { continue; } pCtx->u.GetStatusChange.paReaderStats[i].u32EventState = pRsp->aReaderStates[i].u32EventState; pCtx->u.GetStatusChange.paReaderStats[i].cbAtr = pRsp->aReaderStates[i].u32AtrLength > 36? 36: pRsp->aReaderStates[i].u32AtrLength; memcpy(pCtx->u.GetStatusChange.paReaderStats[i].au8Atr, pRsp->aReaderStates[i].au8Atr, pCtx->u.GetStatusChange.paReaderStats[i].cbAtr); } } } mpDrv->pICardReaderUp->pfnSetStatusChange(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, pCtx->u.GetStatusChange.paReaderStats, pCtx->u.GetStatusChange.cReaderStats); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_CANCEL: { Assert(cbData == sizeof(VRDESCARDCANCELRSP) || RT_FAILURE(rcRequest)); VRDESCARDCANCELRSP *pRsp = (VRDESCARDCANCELRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("CANCEL\n")); } break; case VRDE_SCARD_FN_CONNECT: { Assert(cbData == sizeof(VRDESCARDCONNECTRSP) || RT_FAILURE(rcRequest)); VRDESCARDCONNECTRSP *pRsp = (VRDESCARDCONNECTRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("CONNECT\n")); uint32_t u32ActiveProtocol = 0; uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { u32ActiveProtocol = pRsp->u32ActiveProtocol; Assert(!m_pRemote->reader.fHandle); m_pRemote->reader.hCard = pRsp->hCard; m_pRemote->reader.fHandle = true; } } mpDrv->pICardReaderUp->pfnConnect(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, u32ActiveProtocol); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_RECONNECT: { Assert(cbData == sizeof(VRDESCARDRECONNECTRSP) || RT_FAILURE(rcRequest)); VRDESCARDRECONNECTRSP *pRsp = (VRDESCARDRECONNECTRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("RECONNECT\n")); } break; case VRDE_SCARD_FN_DISCONNECT: { Assert(cbData == sizeof(VRDESCARDDISCONNECTRSP) || RT_FAILURE(rcRequest)); VRDESCARDDISCONNECTRSP *pRsp = (VRDESCARDDISCONNECTRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("DISCONNECT\n")); Assert(!pCtx->pRemote->reader.fHandle); uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; } mpDrv->pICardReaderUp->pfnDisconnect(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_BEGINTRANSACTION: { Assert(cbData == sizeof(VRDESCARDBEGINTRANSACTIONRSP) || RT_FAILURE(rcRequest)); VRDESCARDBEGINTRANSACTIONRSP *pRsp = (VRDESCARDBEGINTRANSACTIONRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("BEGINTRANSACTION\n")); } break; case VRDE_SCARD_FN_ENDTRANSACTION: { Assert(cbData == sizeof(VRDESCARDENDTRANSACTIONRSP) || RT_FAILURE(rcRequest)); VRDESCARDENDTRANSACTIONRSP *pRsp = (VRDESCARDENDTRANSACTIONRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("ENDTRANSACTION\n")); } break; case VRDE_SCARD_FN_STATE: { Assert(cbData == sizeof(VRDESCARDSTATERSP) || RT_FAILURE(rcRequest)); VRDESCARDSTATERSP *pRsp = (VRDESCARDSTATERSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("STATE\n")); } break; case VRDE_SCARD_FN_STATUS: { Assert(cbData == sizeof(VRDESCARDSTATUSRSP) || RT_FAILURE(rcRequest)); VRDESCARDSTATUSRSP *pRsp = (VRDESCARDSTATUSRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("STATUS\n")); char *pszReaderName = NULL; uint32_t cchReaderName = 0; uint32_t u32CardState = 0; uint32_t u32Protocol = 0; uint32_t u32AtrLength = 0; uint8_t *pbAtr = NULL; uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { pszReaderName = pRsp->szReader; cchReaderName = (uint32_t)strlen(pRsp->szReader) + 1; u32CardState = pRsp->u32State; u32Protocol = pRsp->u32Protocol; u32AtrLength = pRsp->u32AtrLength; pbAtr = &pRsp->au8Atr[0]; } } mpDrv->pICardReaderUp->pfnStatus(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, pszReaderName, cchReaderName, u32CardState, u32Protocol, pbAtr, u32AtrLength); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_TRANSMIT: { Assert(cbData == sizeof(VRDESCARDTRANSMITRSP) || RT_FAILURE(rcRequest)); VRDESCARDTRANSMITRSP *pRsp = (VRDESCARDTRANSMITRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("TRANSMIT\n")); PDMICARDREADER_IO_REQUEST *pioRecvPci = NULL; uint8_t *pu8RecvBuffer = NULL; uint32_t cbRecvBuffer = 0; uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { pu8RecvBuffer = pRsp->pu8RecvBuffer; cbRecvBuffer = pRsp->u32RecvLength; /* @todo pioRecvPci */ } } mpDrv->pICardReaderUp->pfnTransmit(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, pioRecvPci, pu8RecvBuffer, cbRecvBuffer); RTMemFree(pioRecvPci); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_CONTROL: { Assert(cbData == sizeof(VRDESCARDCONTROLRSP) || RT_FAILURE(rcRequest)); VRDESCARDCONTROLRSP *pRsp = (VRDESCARDCONTROLRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("CONTROL\n")); uint8_t *pu8OutBuffer = NULL; uint32_t cbOutBuffer = 0; uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { pu8OutBuffer = pRsp->pu8OutBuffer; cbOutBuffer = pRsp->u32OutBufferSize; } } mpDrv->pICardReaderUp->pfnControl(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, pCtx->u.Control.u32ControlCode, pu8OutBuffer, cbOutBuffer); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_GETATTRIB: { Assert(cbData == sizeof(VRDESCARDGETATTRIBRSP) || RT_FAILURE(rcRequest)); VRDESCARDGETATTRIBRSP *pRsp = (VRDESCARDGETATTRIBRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("GETATTRIB\n")); uint8_t *pu8Attrib = NULL; uint32_t cbAttrib = 0; uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS) { pu8Attrib = pRsp->pu8Attr; cbAttrib = pRsp->u32AttrLength; } } mpDrv->pICardReaderUp->pfnGetAttrib(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, pCtx->u.GetAttrib.u32AttrId, pu8Attrib, cbAttrib); RTMemFree(pCtx); } break; case VRDE_SCARD_FN_SETATTRIB: { Assert(cbData == sizeof(VRDESCARDSETATTRIBRSP) || RT_FAILURE(rcRequest)); VRDESCARDSETATTRIBRSP *pRsp = (VRDESCARDSETATTRIBRSP *)pvData; UCRREQCTX *pCtx = (UCRREQCTX *)pvUser; Assert(pCtx->u32Function == u32Function); LogFlowFunc(("SETATTRIB\n")); uint32_t rcCard; if (RT_FAILURE(rcRequest)) { rcCard = VRDE_SCARD_E_NO_SMARTCARD; } else { rcCard = pRsp->u32ReturnCode; } mpDrv->pICardReaderUp->pfnSetAttrib(mpDrv->pICardReaderUp, pCtx->pvUser, rcCard, pCtx->u.SetAttrib.u32AttrId); RTMemFree(pCtx); } break; default: AssertFailed(); rc = VERR_INVALID_PARAMETER; break; } return rc; } int UsbCardReader::EstablishContext(struct USBCARDREADER *pDrv) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); /* The context here is a not a real device context. * The device can be detached at the moment, for example the VRDP client did not connect yet. */ return mpDrv->pICardReaderUp->pfnEstablishContext(mpDrv->pICardReaderUp, VRDE_SCARD_S_SUCCESS); } int UsbCardReader::ReleaseContext(struct USBCARDREADER *pDrv) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext) { /* Do nothing. */ } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { /* Do nothing. */ } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_RELEASECONTEXT; pCtx->pvUser = NULL; VRDESCARDRELEASECONTEXTREQ req; req.Context = m_pRemote->context; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_RELEASECONTEXT, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } else { m_pRemote->fContext = false; } } } return rc; } int UsbCardReader::GetStatusChange(struct USBCARDREADER *pDrv, void *pvUser, uint32_t u32Timeout, PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable) { rc = mpDrv->pICardReaderUp->pfnSetStatusChange(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, paReaderStats, cReaderStats); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rc = mpDrv->pICardReaderUp->pfnSetStatusChange(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_MEMORY, paReaderStats, cReaderStats); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_GETSTATUSCHANGE; pCtx->pvUser = pvUser; pCtx->u.GetStatusChange.paReaderStats = paReaderStats; pCtx->u.GetStatusChange.cReaderStats = cReaderStats; VRDESCARDGETSTATUSCHANGEREQ req; req.Context = m_pRemote->context; req.u32Timeout = u32Timeout; req.cReaders = 1; req.aReaderStates[0].pszReader = &m_pRemote->reader.szReaderName[0]; req.aReaderStates[0].u32CurrentState = paReaderStats[0].u32CurrentState; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_GETSTATUSCHANGE, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } } return rc; } int UsbCardReader::Connect(struct USBCARDREADER *pDrv, void *pvUser, const char *pszReaderName, uint32_t u32ShareMode, uint32_t u32PreferredProtocols) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable) { rc = mpDrv->pICardReaderUp->pfnConnect(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, VRDE_SCARD_PROTOCOL_T0); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rc = mpDrv->pICardReaderUp->pfnConnect(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_MEMORY, VRDE_SCARD_PROTOCOL_T0); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_CONNECT; pCtx->pvUser = pvUser; VRDESCARDCONNECTREQ req; req.Context = m_pRemote->context; req.pszReader = &m_pRemote->reader.szReaderName[0]; req.u32ShareMode = u32ShareMode; req.u32PreferredProtocols = u32PreferredProtocols; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_CONNECT, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } } return rc; } int UsbCardReader::Disconnect(struct USBCARDREADER *pDrv, void *pvUser, uint32_t u32Mode) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { rc = mpDrv->pICardReaderUp->pfnDisconnect(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rc = mpDrv->pICardReaderUp->pfnDisconnect(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_MEMORY); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_DISCONNECT; pCtx->pvUser = pvUser; VRDESCARDDISCONNECTREQ req; req.hCard = m_pRemote->reader.hCard; req.u32Disposition = u32Mode; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_DISCONNECT, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } else { m_pRemote->reader.fHandle = false; } } } return rc; } int UsbCardReader::Status(struct USBCARDREADER *pDrv, void *pvUser) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { rc = mpDrv->pICardReaderUp->pfnStatus(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_SMARTCARD, /* pszReaderName */ NULL, /* cchReaderName */ 0, /* u32CardState */ 0, /* u32Protocol */ 0, /* pu8Atr */ 0, /* cbAtr */ 0); } else { UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rc = mpDrv->pICardReaderUp->pfnStatus(mpDrv->pICardReaderUp, pvUser, VRDE_SCARD_E_NO_MEMORY, /* pszReaderName */ NULL, /* cchReaderName */ 0, /* u32CardState */ 0, /* u32Protocol */ 0, /* pu8Atr */ 0, /* cbAtr */ 0); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_STATUS; pCtx->pvUser = pvUser; VRDESCARDSTATUSREQ req; req.hCard = m_pRemote->reader.hCard; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_STATUS, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } } return rc; } int UsbCardReader::Transmit(struct USBCARDREADER *pDrv, void *pvUser, PDMICARDREADER_IO_REQUEST *pioSendRequest, uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; UCRREQCTX *pCtx = NULL; uint32_t rcSCard = VRDE_SCARD_S_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { rcSCard = VRDE_SCARD_E_NO_SMARTCARD; } if (rcSCard == VRDE_SCARD_S_SUCCESS) { if ( !pioSendRequest || ( pioSendRequest->cbPciLength < 2 * sizeof(uint32_t) || pioSendRequest->cbPciLength > 2 * sizeof(uint32_t) + VRDE_SCARD_MAX_PCI_DATA) ) { AssertFailed(); rcSCard = VRDE_SCARD_E_INVALID_PARAMETER; } } if (rcSCard == VRDE_SCARD_S_SUCCESS) { pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rcSCard = VRDE_SCARD_E_NO_MEMORY; } } if (rcSCard != VRDE_SCARD_S_SUCCESS) { Assert(pCtx == NULL); rc = pDrv->pICardReaderUp->pfnTransmit(pDrv->pICardReaderUp, pvUser, rcSCard, /* pioRecvPci */ NULL, /* pu8RecvBuffer */ NULL, /* cbRecvBuffer*/ 0); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_TRANSMIT; pCtx->pvUser = pvUser; VRDESCARDTRANSMITREQ req; req.hCard = m_pRemote->reader.hCard; req.ioSendPci.u32Protocol = pioSendRequest->u32Protocol; req.ioSendPci.u32PciLength = pioSendRequest->cbPciLength < 2 * sizeof(uint32_t)? 2 * sizeof(uint32_t): pioSendRequest->cbPciLength; Assert(pioSendRequest->cbPciLength <= VRDE_SCARD_MAX_PCI_DATA + 2 * sizeof(uint32_t)); memcpy(req.ioSendPci.au8PciData, (uint8_t *)pioSendRequest + 2 * sizeof(uint32_t), req.ioSendPci.u32PciLength - 2 * sizeof(uint32_t)); req.u32SendLength = cbSendBuffer; req.pu8SendBuffer = pu8SendBuffer; req.u32RecvLength = cbRecvBuffer; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_TRANSMIT, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } return rc; } int UsbCardReader::Control(struct USBCARDREADER *pDrv, void *pvUser, uint32_t u32ControlCode, uint8_t *pu8InBuffer, uint32_t cbInBuffer, uint32_t cbOutBuffer) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; UCRREQCTX *pCtx = NULL; uint32_t rcSCard = VRDE_SCARD_S_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { rcSCard = VRDE_SCARD_E_NO_SMARTCARD; } if (rcSCard == VRDE_SCARD_S_SUCCESS) { if ( cbInBuffer > _128K || cbOutBuffer > _128K) { AssertFailed(); rcSCard = VRDE_SCARD_E_INVALID_PARAMETER; } } if (rcSCard == VRDE_SCARD_S_SUCCESS) { pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rcSCard = VRDE_SCARD_E_NO_MEMORY; } } if (rcSCard != VRDE_SCARD_S_SUCCESS) { Assert(pCtx == NULL); rc = pDrv->pICardReaderUp->pfnControl(pDrv->pICardReaderUp, pvUser, rcSCard, u32ControlCode, /* pvOutBuffer */ NULL, /* cbOutBuffer*/ 0); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_CONTROL; pCtx->pvUser = pvUser; pCtx->u.Control.u32ControlCode = u32ControlCode; VRDESCARDCONTROLREQ req; req.hCard = m_pRemote->reader.hCard; req.u32ControlCode = u32ControlCode; req.u32InBufferSize = cbInBuffer; req.pu8InBuffer = pu8InBuffer; req.u32OutBufferSize = cbOutBuffer; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_CONTROL, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } return rc; } int UsbCardReader::GetAttrib(struct USBCARDREADER *pDrv, void *pvUser, uint32_t u32AttrId, uint32_t cbAttrib) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; UCRREQCTX *pCtx = NULL; uint32_t rcSCard = VRDE_SCARD_S_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { rcSCard = VRDE_SCARD_E_NO_SMARTCARD; } if (rcSCard == VRDE_SCARD_S_SUCCESS) { if (cbAttrib > _128K) { AssertFailed(); rcSCard = VRDE_SCARD_E_INVALID_PARAMETER; } } if (rcSCard == VRDE_SCARD_S_SUCCESS) { pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rcSCard = VRDE_SCARD_E_NO_MEMORY; } } if (rcSCard != VRDE_SCARD_S_SUCCESS) { Assert(pCtx == NULL); pDrv->pICardReaderUp->pfnGetAttrib(pDrv->pICardReaderUp, pvUser, rcSCard, u32AttrId, /* pvAttrib */ NULL, /* cbAttrib */ 0); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_GETATTRIB; pCtx->pvUser = pvUser; pCtx->u.GetAttrib.u32AttrId = u32AttrId; VRDESCARDGETATTRIBREQ req; req.hCard = m_pRemote->reader.hCard; req.u32AttrId = u32AttrId; req.u32AttrLen = cbAttrib; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_GETATTRIB, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } return rc; } int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv, void *pvUser, uint32_t u32AttrId, uint8_t *pu8Attrib, uint32_t cbAttrib) { AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED); int rc = VINF_SUCCESS; UCRREQCTX *pCtx = NULL; uint32_t rcSCard = VRDE_SCARD_S_SUCCESS; if ( !m_pRemote || !m_pRemote->fContext || !m_pRemote->reader.fAvailable || !m_pRemote->reader.fHandle) { rcSCard = VRDE_SCARD_E_NO_SMARTCARD; } if (rcSCard == VRDE_SCARD_S_SUCCESS) { if (cbAttrib > _128K) { AssertFailed(); rcSCard = VRDE_SCARD_E_INVALID_PARAMETER; } } if (rcSCard == VRDE_SCARD_S_SUCCESS) { pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX)); if (!pCtx) { rcSCard = VRDE_SCARD_E_NO_MEMORY; } } if (rcSCard != VRDE_SCARD_S_SUCCESS) { Assert(pCtx == NULL); pDrv->pICardReaderUp->pfnSetAttrib(pDrv->pICardReaderUp, pvUser, rcSCard, u32AttrId); } else { pCtx->pRemote = m_pRemote; pCtx->u32Function = VRDE_SCARD_FN_SETATTRIB; pCtx->pvUser = pvUser; pCtx->u.SetAttrib.u32AttrId = u32AttrId; VRDESCARDSETATTRIBREQ req; req.hCard = m_pRemote->reader.hCard; req.u32AttrId = u32AttrId; req.u32AttrLen = cbAttrib; req.pu8Attr = pu8Attrib; rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_SETATTRIB, &req, sizeof(req)); if (RT_FAILURE(rc)) { RTMemFree(pCtx); } } return rc; } /* * PDMDRVINS */ /* static */ DECLCALLBACK(void *) UsbCardReader::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID) { LogFlowFunc(("pInterface:%p, pszIID:%s\n", pInterface, pszIID)); PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); PDMIBASE_RETURN_INTERFACE(pszIID, PDMICARDREADERDOWN, &pThis->ICardReaderDown); return NULL; } /* static */ DECLCALLBACK(void) UsbCardReader::drvDestruct(PPDMDRVINS pDrvIns) { PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); LogFlowFunc(("iInstance/%d\n",pDrvIns->iInstance)); PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); /** @todo The driver is destroyed before the device. * So device calls ReleaseContext when there is no more driver. * Notify the device here so it can do cleanup or * do a cleanup now in the driver. */ if (pThis->hReqQCardReaderCmd != NIL_RTREQQUEUE) { int rc = RTReqQueueDestroy(pThis->hReqQCardReaderCmd); AssertRC(rc); pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE; } pThis->pUsbCardReader->mpDrv = NULL; pThis->pUsbCardReader = NULL; LogFlowFuncLeave(); } /* static */ DECLCALLBACK(int) UsbCardReader::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) { PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); LogFlowFunc(("iInstance/%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags)); PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER); pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE; if (!CFGMR3AreValuesValid(pCfg, "Object\0")) return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES; AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, ("Configuration error: Not possible to attach anything to this driver!\n"), VERR_PDM_DRVINS_NO_ATTACH); void *pv; int rc = CFGMR3QueryPtr(pCfg, "Object", &pv); AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc); pThis->pUsbCardReader = (UsbCardReader *)pv; pThis->pUsbCardReader->mpDrv = pThis; pThis->pDrvIns = pDrvIns; pDrvIns->IBase.pfnQueryInterface = UsbCardReader::drvQueryInterface; pThis->ICardReaderDown.pfnEstablishContext = drvCardReaderDownEstablishContext; pThis->ICardReaderDown.pfnReleaseContext = drvCardReaderDownReleaseContext; pThis->ICardReaderDown.pfnConnect = drvCardReaderDownConnect; pThis->ICardReaderDown.pfnDisconnect = drvCardReaderDownDisconnect; pThis->ICardReaderDown.pfnStatus = drvCardReaderDownStatus; pThis->ICardReaderDown.pfnGetStatusChange = drvCardReaderDownGetStatusChange; pThis->ICardReaderDown.pfnBeginTransaction = drvCardReaderDownBeginTransaction; pThis->ICardReaderDown.pfnEndTransaction = drvCardReaderDownEndTransaction; pThis->ICardReaderDown.pfnTransmit = drvCardReaderDownTransmit; pThis->ICardReaderDown.pfnGetAttr = drvCardReaderDownGetAttr; pThis->ICardReaderDown.pfnSetAttr = drvCardReaderDownSetAttr; pThis->ICardReaderDown.pfnControl = drvCardReaderDownControl; pThis->pICardReaderUp = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICARDREADERUP); AssertReturn(pThis->pICardReaderUp, VERR_PDM_MISSING_INTERFACE); /* Command Thread Synchronization primitives */ rc = RTReqQueueCreate(&pThis->hReqQCardReaderCmd); AssertLogRelRCReturn(rc, rc); rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThrCardReaderCmd, pThis, drvCardReaderThreadCmd /* worker routine */, drvCardReaderThreadCmdWakeup /* wakeup routine */, 128 * _1K, RTTHREADTYPE_IO, "UCRCMD"); if (RT_FAILURE(rc)) { RTReqQueueDestroy(pThis->hReqQCardReaderCmd); pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE; } LogFlowFunc(("LEAVE: %Rrc\n", rc)); return rc; } /* static */ const PDMDRVREG UsbCardReader::DrvReg = { /* u32Version */ PDM_DRVREG_VERSION, /* szName[32] */ "UsbCardReader", /* szRCMod[32] */ "", /* szR0Mod[32] */ "", /* pszDescription */ "Main Driver communicating with VRDE", /* fFlags */ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT, /* fClass */ PDM_DRVREG_CLASS_USB, /* cMaxInstances */ 1, /* cbInstance */ sizeof(USBCARDREADER), /* pfnConstruct */ UsbCardReader::drvConstruct, /* pfnDestruct */ UsbCardReader::drvDestruct, /* pfnRelocate */ NULL, /* pfnIOCtl */ NULL, /* pfnPowerOn */ NULL, /* pfnReset */ NULL, /* pfnSuspend */ NULL, /* pfnResume */ NULL, /* pfnAttach */ NULL, /* pfnDetach */ NULL, /* pfnPowerOff */ NULL, /* pfnSoftReset */ NULL, /* u32VersionEnd */ PDM_DRVREG_VERSION }; /* vi: set tabstop=4 shiftwidth=4 expandtab: */