#include "smartcard.h" #include "usbreader.h" #pragma PAGEDCODE CSmartCard::CSmartCard() { debug = kernel->createDebug(); memory = kernel->createMemory(); irp = kernel->createIrp(); lock = kernel->createLock(); system = kernel->createSystem(); if(lock) lock->initializeSpinLock(&CardLock); poolingIrp = NULL; }; #pragma PAGEDCODE CSmartCard::~CSmartCard() { TRACE("Destroing SmartCard...\n"); if(memory) memory->dispose(); if(irp) irp->dispose(); if(lock) lock->dispose(); if(system) system->dispose(); if(debug) debug->dispose(); }; #pragma PAGEDCODE BOOL CSmartCard::smartCardConnect(CUSBReader* reader) { TRACE(" Connecting smartcard system...\n"); if(reader) { // Check if smartCard was already initialized... if(!reader->isSmartCardInitialized()) { PSMARTCARD_EXTENSION Smartcard; NTSTATUS Status; USHORT Len; if(isWin98()) {// At this time string should be already initialized Status = SmartcardCreateLink(&DosDeviceName,&reader->getDeviceName()->m_String); TRACE("Gemplus USB reader registered with name %ws, status %X\n",DosDeviceName.Buffer,Status); if(!NT_SUCCESS(Status)) { TRACE("#### Failed to create Device link! Status %X\n", Status); return FALSE; } } else { TRACE("Registering reader interface at system...\n"); if(!reader->registerDeviceInterface(&GUID_CLASS_SMARTCARD)) { TRACE("#### Failed to register device interface...\n"); return FALSE; } } Smartcard = reader->getCardExtention(); TRACE("*** Reader reports Smartcard 0x%x\n",Smartcard); this->reader = reader; memory->zero(Smartcard,sizeof(SMARTCARD_EXTENSION)); Smartcard->ReaderExtension = (PREADER_EXTENSION)reader; Smartcard->Version = SMCLIB_VERSION; // Read the name from reader object!!!!!!! Len = MAXIMUM_ATTR_STRING_LENGTH; reader->getVendorName(Smartcard->VendorAttr.VendorName.Buffer,&Len); Smartcard->VendorAttr.VendorName.Length = Len; TRACE(" VENDOR NAME - %s\n",Smartcard->VendorAttr.VendorName.Buffer); Len = MAXIMUM_ATTR_STRING_LENGTH; reader->getDeviceType(Smartcard->VendorAttr.IfdType.Buffer,&Len); Smartcard->VendorAttr.IfdType.Length = Len; TRACE(" DEVICE TYPE - %s\n",Smartcard->VendorAttr.IfdType.Buffer); // Clk frequency in KHz encoded as little endian integer Smartcard->ReaderCapabilities.CLKFrequency.Default = SC_IFD_DEFAULT_CLK_FREQUENCY; Smartcard->ReaderCapabilities.CLKFrequency.Max = SC_IFD_MAXIMUM_CLK_FREQUENCY; Smartcard->ReaderCapabilities.DataRate.Default = SC_IFD_DEFAULT_DATA_RATE; Smartcard->ReaderCapabilities.DataRate.Max = SC_IFD_MAXIMUM_DATA_RATE; // reader could support higher data rates Smartcard->ReaderCapabilities.DataRatesSupported.List = dataRatesSupported; Smartcard->ReaderCapabilities.DataRatesSupported.Entries = sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]); Smartcard->VendorAttr.IfdVersion.BuildNumber = 0; // store firmware revision in ifd version Smartcard->VendorAttr.IfdVersion.VersionMajor = 0x01; Smartcard->VendorAttr.IfdVersion.VersionMinor = 0x00; Smartcard->VendorAttr.IfdSerialNo.Length = 0; Smartcard->ReaderCapabilities.MaxIFSD = SC_IFD_MAXIMUM_IFSD; // Now setup information in our deviceExtension Smartcard->ReaderCapabilities.CurrentState = (ULONG) SCARD_UNKNOWN; // TODO: get reader type from reader object!!!!!!!!!!!!!! // Type of Reader - USB Smartcard->ReaderCapabilities.ReaderType = SCARD_READER_TYPE_USB; // This reader supports T=0 and T=1 Smartcard->ReaderCapabilities.SupportedProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; Smartcard->ReaderCapabilities.MechProperties = 0; Smartcard->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE; Smartcard->SmartcardReply.BufferSize = MIN_BUFFER_SIZE; Status = SmartcardInitialize(Smartcard); if(NT_SUCCESS(Status)) { // It looks like SmartcardInitialize() resets DeviceObject field, // So, we have to do it after the call. Smartcard->VendorAttr.UnitNo = reader->getDeviceNumber(); Smartcard->OsData->DeviceObject = reader->getSystemDeviceObject(); TRACE(" Registered device %d with DeviceObject 0x%x\n",Smartcard->VendorAttr.UnitNo,Smartcard->OsData->DeviceObject); // (note: RDF_CARD_EJECT and RDF_READER_SWALLOW are not supported) // Well... Actually I could define methods at smartcard object as // statics and make a link to them. It will work. // The reason I created extenal C linkage functions - to // separate smartcard system and our driver. // I think driver actually may not care about smartcard extention and all // settings required by smclib can be done inside our C wrappers and not // inside driver objects... Smartcard->ReaderFunction[RDF_TRANSMIT] = smartCard_Transmit; Smartcard->ReaderFunction[RDF_SET_PROTOCOL] = smartCard_SetProtocol; Smartcard->ReaderFunction[RDF_CARD_POWER] = smartCard_Power; Smartcard->ReaderFunction[RDF_CARD_TRACKING] = smartCard_Tracking; Smartcard->ReaderFunction[RDF_IOCTL_VENDOR] = smartCard_VendorIoctl; reader->setSmartCardInitialized(TRUE); TRACE(" ***** SmartCard system was initialized correctly! *****\n\n"); return TRUE; } else { TRACE(" ##### FAILED to initialize smartcard system...\n"); } } else { TRACE(" ##### Smartcard system already active...\n"); } } else { TRACE(" ###### Invalid reader object...\n"); } return FALSE; }; #pragma PAGEDCODE BOOL CSmartCard::smartCardStart() { return TRUE; }; #pragma PAGEDCODE VOID CSmartCard::smartCardDisconnect() { TRACE(" Disconnecting smartcard system...\n"); if(reader) { PSMARTCARD_EXTENSION Smartcard; Smartcard = reader->getCardExtention(); if(Smartcard->OsData && Smartcard->OsData->NotificationIrp) { KIRQL keIrql; PIRP poolingIrp = Smartcard->OsData->NotificationIrp; TRACE("====== COMPLETING NOTIFICATION IRP %8.8lX \n\n",poolingIrp); // Guard by spin lock! lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql); Smartcard->OsData->NotificationIrp = NULL; lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql); lock->acquireCancelSpinLock(&keIrql); irp->setCancelRoutine(poolingIrp, NULL); lock->releaseCancelSpinLock(keIrql); if (poolingIrp->Cancel) poolingIrp->IoStatus.Status = STATUS_CANCELLED; else poolingIrp->IoStatus.Status = STATUS_SUCCESS; poolingIrp->IoStatus.Information = 0; irp->completeRequest(poolingIrp, IO_NO_INCREMENT); } //Unregister the device if(isWin98()) { TRACE("****** Removing device object name %ws \n",DosDeviceName.Buffer); system->deleteSymbolicLink(&DosDeviceName); } else { TRACE("Setting reader interface state to FALSE...\n"); reader->unregisterDeviceInterface(reader->getDeviceInterfaceName()); } SmartcardExit(Smartcard); Smartcard->ReaderExtension = NULL; reader->setSmartCardInitialized(FALSE); reader = NULL; TRACE(" SmartCard system was disconnected...\n"); } }; // Declare Smclib system callbacks... #pragma LOCKEDCODE NTSTATUS smartCard_Transmit(PSMARTCARD_EXTENSION SmartcardExtension) { NTSTATUS Status = STATUS_SUCCESS;; BOOL Read = FALSE; CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension; PSCARD_CARD_CAPABILITIES cardCapabilities = &SmartcardExtension->CardCapabilities; ULONG selectedProtocol = cardCapabilities->Protocol.Selected; ULONG protocolRequested = ((PSCARD_IO_REQUEST) SmartcardExtension->OsData->CurrentIrp->AssociatedIrp.SystemBuffer)->dwProtocol; BYTE * pRequest = (BYTE *)SmartcardExtension->SmartcardRequest.Buffer; BYTE * pReply = (BYTE *)SmartcardExtension->SmartcardReply.Buffer; ULONG RequestLength = 0; ULONG ReplyLength = 0; PAGED_CODE(); DBG_PRINT ("smartCard_Transmit()\n"); if (!Reader || (selectedProtocol != protocolRequested)) { DBG_PRINT (" smartCard_Transmit requested with invalid device state...\n"); return (STATUS_INVALID_DEVICE_STATE); } if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE; __try { //Set the reply buffer length to 0. *SmartcardExtension->IoRequest.Information = 0; switch (selectedProtocol) { case SCARD_PROTOCOL_T0: Status = SmartcardT0Request(SmartcardExtension); RequestLength = SmartcardExtension->SmartcardRequest.BufferLength; DBG_PRINT("T0 PROTOCOL: request length %d\n",RequestLength); if (!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_Transmit: SmartcardT0Request reports error 0x%x...\n",Status); __leave; } if (SmartcardExtension->T0.Le > 0) { if (SmartcardExtension->T0.Le > SC_IFD_T0_MAXIMUM_LEX) { DBG_PRINT ("smartCard_Transmit:Expected length is too big - %d\n",SmartcardExtension->T0.Le); Status = STATUS_BUFFER_TOO_SMALL; __leave; } ReplyLength = SmartcardExtension->SmartcardReply.BufferSize; if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { __leave; } Status = Reader->reader_Read(pRequest,RequestLength,pReply,&ReplyLength); Reader->reader_set_Idle(); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_Transmit: reader_Read() reports error 0x%x\n",Status); __leave; } } else { if (SmartcardExtension->T0.Lc > SC_IFD_T0_MAXIMUM_LC) { DBG_PRINT ("smartCard_Transmit:Command length is too big - %d\n",SmartcardExtension->T0.Lc); Status = STATUS_BUFFER_TOO_SMALL; __leave; } ReplyLength = SmartcardExtension->SmartcardReply.BufferSize; if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_Transmit:Failed to get idle state...\n"); __leave; } if(!pRequest || ! RequestLength) { DBG_PRINT("\n Transmit: cardWrite() Buffer %x length %d\n",pRequest,RequestLength); } Status = Reader->reader_Write(pRequest,RequestLength,pReply,&ReplyLength); Reader->reader_set_Idle(); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_Transmit: reader_Write() reports error 0x%x\n",Status); __leave; } } SmartcardExtension->SmartcardReply.BufferLength = ReplyLength; DBG_PRINT ("T0 Reply length 0x%x\n",ReplyLength); if(NT_SUCCESS(Status)) { Status = SmartcardT0Reply(SmartcardExtension); } if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_Transmit: SmartcardT0Reply reports error 0x%x\n",Status); } break; case SCARD_PROTOCOL_T1: // Loop for the T=1 management if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_Transmit:Failed to get idle state...\n"); __leave; } do { // Tell the lib function how many bytes I need for the prologue SmartcardExtension->SmartcardRequest.BufferLength = 0; Status = SmartcardT1Request(SmartcardExtension); RequestLength = SmartcardExtension->SmartcardRequest.BufferLength; ReplyLength = SmartcardExtension->SmartcardReply.BufferSize; DBG_PRINT("T1 PROTOCOL: request, expected reply length %d, %d\n",RequestLength,ReplyLength); if (!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_Transmit: SmartcardT1Request reports error 0x%x...\n",Status); Reader->reader_set_Idle(); __leave; } Status = Reader->reader_translate_request(pRequest,RequestLength,pReply,&ReplyLength, cardCapabilities, SmartcardExtension->T1.Wtx); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_Transmit: reader_translate_request() reports error 0x%x\n",Status); //return Status; no let smartcard assign proper status } if (SmartcardExtension->T1.Wtx) { // Set the reader BWI to the default value Reader->setTransparentConfig(cardCapabilities,0); } // copy buffer(pass by ptr) n length SmartcardExtension->SmartcardReply.BufferLength = ReplyLength; Status = SmartcardT1Reply(SmartcardExtension); if ((Status != STATUS_MORE_PROCESSING_REQUIRED) && (Status != STATUS_SUCCESS) ) { DBG_PRINT ("smartCard_Transmit: SmartcardT1Reply reports error 0x%x\n",Status); } } while (Status == STATUS_MORE_PROCESSING_REQUIRED); Reader->reader_set_Idle(); break; default: Status = STATUS_DEVICE_PROTOCOL_ERROR; __leave; } }// Try block __finally { Reader->releaseRemoveLock(); } return Status; }; #pragma LOCKEDCODE NTSTATUS smartCard_VendorIoctl(PSMARTCARD_EXTENSION SmartcardExtension) { NTSTATUS Status = STATUS_SUCCESS;; CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension; ULONG ControlCode = SmartcardExtension->MajorIoControlCode; PUCHAR pRequest = (PUCHAR) SmartcardExtension->IoRequest.RequestBuffer; ULONG RequestLength = SmartcardExtension->IoRequest.RequestBufferLength; PUCHAR pReply = (PUCHAR)SmartcardExtension->IoRequest.ReplyBuffer; ULONG ReplyLength = SmartcardExtension->IoRequest.ReplyBufferLength; PAGED_CODE(); DBG_PRINT ("smartCard_VendorIoctl()\n"); if (!Reader) { DBG_PRINT ("smartCard_VendorIoctl: Reader is not ready...\n"); return (STATUS_INVALID_DEVICE_STATE); } if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE; *SmartcardExtension->IoRequest.Information = 0; __try { switch(ControlCode) { // For IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE and IOCTL_VENDOR_SMARTCARD_SET_ATTRIBUTE // Vendor attribut use by the device case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE: case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE: if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_VendorIoctl:Failed to get idle state...\n"); __leave; } Status = Reader->reader_VendorAttribute(ControlCode,pRequest,RequestLength,pReply,&ReplyLength); Reader->reader_set_Idle(); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_VendorIoctl: reader_Attibute reports error 0x%x ...\n", Status); ReplyLength = 0; } *SmartcardExtension->IoRequest.Information = ReplyLength; break; // For IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE // Send a GemCore command to the reader case IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE: if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_VendorIoctl:Failed to get idle state...\n"); __leave; } Status = Reader->reader_Ioctl(ControlCode,pRequest,RequestLength,pReply,&ReplyLength); Reader->reader_set_Idle(); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_VendorIoctl: cardIoctl reports error 0x%x ...\n", Status); ReplyLength = 0; } *SmartcardExtension->IoRequest.Information = ReplyLength; break; // For IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED // Change reader speed manually case IOCTL_SMARTCARD_VENDOR_SWITCH_SPEED: if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_VendorIoctl:Failed to get idle state...\n"); __leave; } Status = Reader->reader_SwitchSpeed(ControlCode,pRequest,RequestLength,pReply,&ReplyLength); Reader->reader_set_Idle(); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_VendorIoctl: reader_SwitchSpeed reports error 0x%x ...\n", Status); ReplyLength = 0; } else { // Set value inside CardCabilities BYTE NewTA1 = pRequest[0]; SmartcardExtension->CardCapabilities.Fl = NewTA1 >> 4; SmartcardExtension->CardCapabilities.Dl = NewTA1 & 0x0F; // Do not touch ClockRateConversion and BitRateAdjustment! } *SmartcardExtension->IoRequest.Information = ReplyLength; break; default: Status = STATUS_NOT_SUPPORTED; break; } } __finally { Reader->releaseRemoveLock(); } DBG_PRINT ("smartCard_VendorIoctl Exit Status=%x\n", Status); return Status; }; #pragma PAGEDCODE // Examine if ATR identifies a specific mode (presence of TA2). BOOLEAN CSmartCard::CheckSpecificMode(BYTE* ATR, DWORD ATRLength) { DWORD pos, len; // ATR[1] is T0. Examine precense of TD1. if (ATR[1] & 0x80) { // Find position of TD1. pos = 2; if (ATR[1] & 0x10) pos++; if (ATR[1] & 0x20) pos++; if (ATR[1] & 0x40) pos++; // Here ATR[pos] is TD1. Examine presence of TA2. if (ATR[pos] & 0x10) { // To be of any interest an ATR must contains at least // TS, T0, TA1, TD1, TA2 [+ T1 .. TK] [+ TCK] // Find the maximum length of uninteresting ATR. if (ATR[pos] & 0x0F) len = 5 + (ATR[1] & 0x0F); else len = 4 + (ATR[1] & 0x0F); // In protocol T=0 there is no TCK. if (ATRLength > len) // Interface bytes requires changes. { if ((ATR[pos+1] & 0x10) == 0) // TA2 asks to use interface bytes. { return TRUE; } } } } return FALSE; } // CheckSpecificMode #pragma LOCKEDCODE NTSTATUS smartCard_Power(PSMARTCARD_EXTENSION SmartcardExtension) { NTSTATUS Status = STATUS_SUCCESS;; CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension; //TO CHANGE LATER... ULONG ControlCode = SmartcardExtension->MinorIoControlCode; PUCHAR pReply = (PUCHAR)SmartcardExtension->IoRequest.ReplyBuffer; ULONG ReplyLength = SmartcardExtension->IoRequest.ReplyBufferLength; KIRQL oldirql; ULONG State; CSmartCard* smartcard = NULL; DBG_PRINT ("smartCard_Power()\n"); if (!Reader) { DBG_PRINT ("smartCard_ReaderPower(): Reader is not ready...\n"); return STATUS_INVALID_DEVICE_STATE; } if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE; smartcard = Reader->getSmartCard(); *SmartcardExtension->IoRequest.Information = 0; if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_Power:Failed to get idle state...\n"); Reader->releaseRemoveLock(); return Status; } Status = Reader->reader_Power(ControlCode,pReply,&ReplyLength, FALSE); Reader->reader_set_Idle(); switch(ControlCode) { case SCARD_POWER_DOWN: { if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_Power:Failed to get idle state...\n"); Reader->releaseRemoveLock(); return Status; } State = Reader->reader_UpdateCardState(); if(smartcard) { KeAcquireSpinLock(smartcard->getCardLock(), &oldirql); SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; SmartcardExtension->CardCapabilities.ATR.Length = 0; SmartcardExtension->ReaderCapabilities.CurrentState = State; KeReleaseSpinLock(smartcard->getCardLock(), oldirql); } Reader->reader_set_Idle(); if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_ReaderPower: cardPower down reports error 0x%x ...\n", Status); } Reader->releaseRemoveLock(); return Status; } break; case SCARD_COLD_RESET: case SCARD_WARM_RESET: if(!NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_ReaderPower: cardPower up reports error 0x%x ...\n", Status); *SmartcardExtension->IoRequest.Information = 0; KeAcquireSpinLock(smartcard->getCardLock(), &oldirql); SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; SmartcardExtension->CardCapabilities.ATR.Length = 0; if(Status==STATUS_NO_MEDIA) { DBG_PRINT("############# Reporting CARD ABSENT!... #############\n"); SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT; } KeReleaseSpinLock(smartcard->getCardLock(), oldirql); Reader->releaseRemoveLock(); return Status; } if(pReply && ReplyLength && (pReply[0]==0x3B || pReply[0]==0x3F) ) { if ((SmartcardExtension->SmartcardReply.BufferSize>=ReplyLength) && (sizeof(SmartcardExtension->CardCapabilities.ATR.Buffer)>=ReplyLength)) { DBG_PRINT("Setting SMCLIB info...\n"); // Set information... *SmartcardExtension->IoRequest.Information = ReplyLength; // Set reply... RtlCopyMemory(SmartcardExtension->SmartcardReply.Buffer,pReply,ReplyLength); SmartcardExtension->SmartcardReply.BufferLength = ReplyLength; // Set ATR... RtlCopyMemory(SmartcardExtension->CardCapabilities.ATR.Buffer,pReply,ReplyLength); SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR) ReplyLength; SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; // Parse the ATR string in order to check if it as valid // and to find out if the card uses invers convention Status = SmartcardUpdateCardCapabilities(SmartcardExtension); if(!NT_SUCCESS(Status)) { DBG_PRINT("UpdateCardCaps() reports error 0x%x\n", Status); Status = 0; } // Check if Specific mode is present in TA2 DBG_PRINT("=========== Checking specific mode....\n"); if(smartcard->CheckSpecificMode(SmartcardExtension->CardCapabilities.ATR.Buffer, SmartcardExtension->CardCapabilities.ATR.Length)) { // Use automatic protocol switching! if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { DBG_PRINT ("smartCard_Power:Failed to get idle state...\n"); Reader->releaseRemoveLock(); return Status; } Status = Reader->reader_Power(ControlCode,pReply,&ReplyLength, TRUE); Reader->reader_set_Idle(); } } else { // ERROR!!!!! Status = STATUS_BUFFER_TOO_SMALL; *SmartcardExtension->IoRequest.Information = 0; DBG_PRINT ("smartCard_ReaderPower: Failed to copy ATR because of short ATR or Reply buffer...\n"); } } else { //ERROR!!!! Status = STATUS_UNRECOGNIZED_MEDIA; *SmartcardExtension->IoRequest.Information = 0; DBG_PRINT ("smartCard_ReaderPower: Failed to get card ATR...\n"); KeAcquireSpinLock(smartcard->getCardLock(), &oldirql); SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; SmartcardExtension->CardCapabilities.ATR.Length = 0; KeReleaseSpinLock(smartcard->getCardLock(), oldirql); } Reader->releaseRemoveLock(); return Status; break; } Reader->releaseRemoveLock(); return STATUS_INVALID_PARAMETER; }; #pragma LOCKEDCODE NTSTATUS smartCard_SetProtocol(PSMARTCARD_EXTENSION SmartcardExtension) { NTSTATUS Status = STATUS_SUCCESS;; CUSBReader* Reader = (CUSBReader*) SmartcardExtension->ReaderExtension; ULONG ProtocolMask = SmartcardExtension->MinorIoControlCode; PAGED_CODE(); DBG_PRINT ("smartCard_SetProtocol()\n"); *SmartcardExtension->IoRequest.Information = 0; if (!Reader) { DBG_PRINT ("######## smartCard_SetProtocol: Reader is not ready...\n"); return (STATUS_INVALID_DEVICE_STATE); } if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE; if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T1) DBG_PRINT ("******* T1 PROTOCOL REQUESTED ******\n"); if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T0) DBG_PRINT ("******* T0 PROTOCOL REQUESTED ******\n"); // Check if the card is already in specific state // and if the caller wants to have the already selected protocol. // We return success if this is the case. if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC && (SmartcardExtension->CardCapabilities.Protocol.Selected & ProtocolMask)) { DBG_PRINT ("Requested protocol %d already was setted.\n",SmartcardExtension->CardCapabilities.Protocol.Selected); Reader->releaseRemoveLock(); return STATUS_SUCCESS; } if(!NT_SUCCESS(Status = Reader->reader_WaitForIdleAndBlock())) { Reader->releaseRemoveLock(); return Status; } do { // Select T=1 or T=0 and indicate that pts1 follows // What is the protocol selected DBG_PRINT ("Smartcard: SetProtocol Loop\n"); if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T1) { DBG_PRINT ("******* SETTING T1 PROTOCOL ******\n"); Status = Reader->reader_SetProtocol(SCARD_PROTOCOL_T1, PROTOCOL_MODE_MANUALLY); if(NT_SUCCESS(Status)) { SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1; DBG_PRINT ("******* T1 PROTOCOL WAS SET ******\n"); } } else if(SmartcardExtension->CardCapabilities.Protocol.Supported & ProtocolMask & SCARD_PROTOCOL_T0) { // T0 selection DBG_PRINT ("******* SETTING T0 PROTOCOL ******\n"); Status = Reader->reader_SetProtocol(SCARD_PROTOCOL_T0, PROTOCOL_MODE_MANUALLY); if(NT_SUCCESS(Status)) { SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0; DBG_PRINT ("******* T0 PROTOCOL WAS SET ******\n"); } } else { Status = STATUS_INVALID_DEVICE_REQUEST; DBG_PRINT ("smartCard_SetProtocol: BAD protocol selection...\n"); SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; // close only once Reader->reader_set_Idle(); Reader->releaseRemoveLock(); return Status; } // Fail to negociate PPS, try PTS_TYPE_DEFAULT if( ! NT_SUCCESS(Status)) { if (SmartcardExtension->CardCapabilities.PtsData.Type != PTS_TYPE_DEFAULT) { DBG_PRINT ("Smartcard: SetProtocol: PPS failed. Trying default parameters...\n"); // // The card did either NOT reply or it replied incorrectly // so try default values. // Set PtsData Type to Default and do a cold reset // SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT; Status = Reader->reader_SetProtocol(ProtocolMask, PROTOCOL_MODE_DEFAULT); if(NT_SUCCESS(Status)) { Status = SmartcardUpdateCardCapabilities(SmartcardExtension); } if(NT_SUCCESS(Status)) { DBG_PRINT ("Smartcard: SetProtocol PPS default succeed, TRY AGAIN\n"); Status = STATUS_MORE_PROCESSING_REQUIRED; } } } } while ( Status == STATUS_MORE_PROCESSING_REQUIRED ); if(NT_SUCCESS(Status)) { DBG_PRINT ("smartCard_SetProtocol: SUCCCESS Finish transaction\n"); // Now indicate that we're in specific mode // and return the selected protocol to the caller // SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC; *(PULONG) SmartcardExtension->IoRequest.ReplyBuffer = SmartcardExtension->CardCapabilities.Protocol.Selected; *SmartcardExtension->IoRequest.Information = sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected); } else { Status = STATUS_DEVICE_PROTOCOL_ERROR; // We failed to connect at any protocol. Just report error. DBG_PRINT ("smartCard_SetProtocol: Failed to set any protocol...\n"); SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; } // Unblock set protocol Reader->reader_set_Idle(); Reader->releaseRemoveLock(); return Status; }; // Callback function to cancel tracking Irp #pragma LOCKEDCODE NTSTATUS smartCard_CancelTracking(PDEVICE_OBJECT DeviceObject, PIRP Irp) { // OnCancelPendingIoctl CUSBReader* Reader = (CUSBReader*)DeviceObject->DeviceExtension; PIRP notificationIrp; CSmartCard* card = NULL; PSMARTCARD_EXTENSION SmartcardExtention = NULL; KIRQL ioIrql; KIRQL keIrql; DBG_PRINT ("######### SmartCard: Cancelling card tracking...\n"); DBG_PRINT ("######### SmartCard: DeviceObject reported - 0x%x, IRP - 0x%x\n",DeviceObject,Irp); DBG_PRINT ("######### SmartCard: Reader reported - 0x%x\n",Reader); if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE; notificationIrp = NULL; card = Reader->getSmartCard(); notificationIrp = card->getPoolingIrp(); SmartcardExtention = Reader->getCardExtention(); ASSERT(Irp == notificationIrp); IoReleaseCancelSpinLock(Irp->CancelIrql); DBG_PRINT("######### SmartCard: notificationIrp - 0x%x\n",Irp); KeAcquireSpinLock(&SmartcardExtention->OsData->SpinLock,&keIrql); notificationIrp = SmartcardExtention->OsData->NotificationIrp; SmartcardExtention->OsData->NotificationIrp = NULL; KeReleaseSpinLock(&SmartcardExtention->OsData->SpinLock,keIrql); if (notificationIrp) { DBG_PRINT("####### CancelTracking: Completing NotificationIrp %lxh\n",notificationIrp); IoAcquireCancelSpinLock(&ioIrql); IoSetCancelRoutine(notificationIrp, NULL); IoReleaseCancelSpinLock(ioIrql); // finish the request notificationIrp->IoStatus.Status = STATUS_CANCELLED; notificationIrp->IoStatus.Information = 0; IoCompleteRequest(notificationIrp, IO_NO_INCREMENT); } Reader->releaseRemoveLock(); return STATUS_CANCELLED; } #pragma LOCKEDCODE NTSTATUS smartCard_Tracking(PSMARTCARD_EXTENSION Smartcard) { KIRQL oldIrql; CUSBReader* Reader = (CUSBReader*) Smartcard->ReaderExtension; DBG_PRINT ("SmartCard: Card tracking...\n"); if (!Reader) return STATUS_INVALID_DEVICE_STATE; if (!NT_SUCCESS(Reader->acquireRemoveLock())) return STATUS_INVALID_DEVICE_STATE; if(Smartcard->MajorIoControlCode == IOCTL_SMARTCARD_IS_PRESENT) { Reader->setNotificationState(SCARD_SWALLOWED); DBG_PRINT ("SmartCard: WAITING FOR INSERTION!\n"); } else { Reader->setNotificationState(SCARD_ABSENT); DBG_PRINT ("SmartCard: WAITING FOR REMOVAL!\n"); } if(!Smartcard->OsData || !Smartcard->OsData->NotificationIrp) { DBG_PRINT ("SmartCard: ========== CARD TRACKING CALLED WITH ZERO IRP!!!!!\n"); Reader->releaseRemoveLock(); return STATUS_INVALID_DEVICE_STATE; } DBG_PRINT("######### SmartCard: POOLING IRP - %8.8lX \n",Smartcard->OsData->NotificationIrp); CSmartCard* card = Reader->getSmartCard(); IoAcquireCancelSpinLock(&oldIrql); IoSetCancelRoutine(Smartcard->OsData->NotificationIrp, smartCard_CancelTracking); IoReleaseCancelSpinLock(oldIrql); if(card) card->setPoolingIrp(Smartcard->OsData->NotificationIrp); Reader->releaseRemoveLock(); return STATUS_PENDING; }; #pragma PAGEDCODE VOID CSmartCard::completeCardTracking() { PSMARTCARD_EXTENSION Smartcard; ULONG CurrentState; ULONG ExpectedState; KIRQL ioIrql; KIRQL keIrql; PIRP poolingIrp; //DEBUG_START();//Force to debug even if thread disabled it... TRACE("SmartCard: completeCardTracking() ...\n"); Smartcard = reader->getCardExtention(); CurrentState = reader->getCardState(); ExpectedState = reader->getNotificationState(); TRACE("SMCLIB Card state is %x\n",Smartcard->ReaderCapabilities.CurrentState); TRACE("Current Card state is %x\n",CurrentState); TRACE("ExpectedState is %x\n",ExpectedState); if(Smartcard && Smartcard->OsData) { lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql); if(CurrentState < SCARD_SWALLOWED) { Smartcard->ReaderCapabilities.CurrentState = CurrentState; } else { if(Smartcard->ReaderCapabilities.CurrentState<=SCARD_SWALLOWED) { Smartcard->ReaderCapabilities.CurrentState = CurrentState; } } TRACE("NEW SMCLIB card state is %x\n",Smartcard->ReaderCapabilities.CurrentState); lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql); } poolingIrp = NULL; if((ExpectedState!= SCARD_UNKNOWN) && (ExpectedState == CurrentState)) { DEBUG_START();//Force to debug even if thread disabled it... TRACE("\n=======Expected state %d is reached=====\n\n",ExpectedState); // Desired state reached... if(Smartcard->OsData && Smartcard->OsData->NotificationIrp) { setPoolingIrp(NULL); reader->setNotificationState(SCARD_UNKNOWN); TRACE("====== COMPLETING NOTIFICATION =========\n"); // Finish requested notification!..... lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql); poolingIrp = Smartcard->OsData->NotificationIrp; lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql); if(poolingIrp) { TRACE("====== COMPLETING NOTIFICATION IRP %8.8lX \n\n",poolingIrp); lock->acquireCancelSpinLock(&ioIrql); irp->setCancelRoutine(poolingIrp, NULL); lock->releaseCancelSpinLock(ioIrql); if(poolingIrp->Cancel) poolingIrp->IoStatus.Status = STATUS_CANCELLED; else poolingIrp->IoStatus.Status = STATUS_SUCCESS; poolingIrp->IoStatus.Information = 0; lock->acquireSpinLock(&Smartcard->OsData->SpinLock, &keIrql); Smartcard->OsData->NotificationIrp = NULL; lock->releaseSpinLock(&Smartcard->OsData->SpinLock, keIrql); irp->completeRequest(poolingIrp,IO_NO_INCREMENT); } } } }