Windows2003-3790/drivers/smartcrd/scutil/scutil.c
2020-09-30 16:53:55 +02:00

761 lines
17 KiB
C

/***************************************************************************
Copyright (c) 2002 Microsoft Corporation
Module Name:
SCUTIL.C
Abstract:
Routines for Smartcard Driver Utility Library
Environment:
Kernel Mode Only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
Revision History:
05/14/2002 : created
Authors:
Randy Aull
****************************************************************************/
#include "pch.h"
VOID
IncIoCount(
PSCUTIL_EXTENSION pExt
)
{
ULONG count;
count = InterlockedIncrement(&pExt->IoCount);
KeClearEvent(&pExt->OkToStop);
}
VOID
DecIoCount(
PSCUTIL_EXTENSION pExt
)
{
ULONG count;
count = InterlockedDecrement(&pExt->IoCount);
if (count == 0) {
KeSetEvent(&pExt->OkToStop,
0,
FALSE);
}
}
VOID
StartIoctls(
PSCUTIL_EXTENSION pExt
)
{
LIST_ENTRY head;
InterlockedExchange(&pExt->IoctlQueueState,
PASS_IOCTLS);
pExt->RestartIoctls = TRUE;
// Now drain the queued list
InitializeListHead(&head);
IrpList_Drain(&pExt->PendingIrpQueue,
&head);
while (!IsListEmpty(&head)) {
PLIST_ENTRY ple;
PIRP pIrp;
ple = RemoveHeadList(&head);
pIrp = CONTAINING_RECORD(ple, IRP, Tail.Overlay.ListEntry);
IncIoCount(pExt);
SmartcardDeviceControl(pExt->SmartcardExtension,
pIrp);
DecIoCount(pExt);
IoReleaseRemoveLock(pExt->RemoveLock,
pIrp);
}
}
VOID
StopIoctls(
PSCUTIL_EXTENSION pExt
)
{
InterlockedExchange(&pExt->IoctlQueueState,
QUEUE_IOCTLS);
}
VOID
FailIoctls(
PSCUTIL_EXTENSION pExt
)
{
LIST_ENTRY head;
InterlockedExchange(&pExt->IoctlQueueState,
FAIL_IOCTLS);
InitializeListHead(&head);
IrpList_Drain(&pExt->PendingIrpQueue,
&head);
while (!IsListEmpty(&head)) {
PLIST_ENTRY ple;
PIRP pIrp;
ple = RemoveHeadList(&head);
pIrp = CONTAINING_RECORD(ple, IRP, Tail.Overlay.ListEntry);
IoReleaseRemoveLock(pExt->RemoveLock,
pIrp);
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest(pIrp,
IO_NO_INCREMENT);
}
}
QUEUE_STATE
GetIoctlQueueState(
PSCUTIL_EXTENSION pExt
)
{
return InterlockedCompareExchange(&pExt->IoctlQueueState,
PASS_IOCTLS,
INVALID_STATE);
}
NTSTATUS
ScUtil_SystemControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
forwards IRP_MJ_SYSTEM_CONTROL
Arguments:
Return Value:
--*/
{
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
NTSTATUS status = STATUS_SUCCESS;
__try
{
SmartcardDebug( DEBUG_TRACE, ("ScUtilSystemControl Enter\n"));
IoSkipCurrentIrpStackLocation(Irp);
status = IoCallDriver(pExt->LowerDeviceObject, Irp);
}
__finally
{
SmartcardDebug( DEBUG_TRACE, ("ScUtilSystemControl Exit : 0x%x\n",status ));
}
return status;
}
NTSTATUS
OnRequestComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PKEVENT Event
)
/*++
Routine Description:
Completion routine for UsbScForwardAndWait
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
__try
{
SmartcardDebug( DEBUG_TRACE, ("OnRequestComplete Enter\n"));
KeSetEvent(Event,
0,
FALSE);
status = STATUS_MORE_PROCESSING_REQUIRED;
}
__finally
{
SmartcardDebug( DEBUG_TRACE, ("OnRequestComplete Exit : 0x%x\n",status ));
}
return status;
}
NTSTATUS
ScUtil_ForwardAndWait(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
Sends an irp down the stack and waits for its completion.
Arguments:
Return Value:
--*/
{
KEVENT event;
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
NTSTATUS status = STATUS_UNSUCCESSFUL;
__try
{
SmartcardDebug( DEBUG_TRACE, ("ScUtilForwardAndWait Enter\n"));
KeInitializeEvent(&event,
NotificationEvent,
FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) OnRequestComplete,
(PVOID) &event,
TRUE,
TRUE,
TRUE);
ASSERT(pExt->LowerDeviceObject);
IoCallDriver(pExt->LowerDeviceObject,
Irp);
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
status = Irp->IoStatus.Status;
}
__finally
{
SmartcardDebug( DEBUG_TRACE, ("ScUtilForwardAndWait Exit : 0x%x\n",status));
}
return status;
}
NTSTATUS
ScUtil_Cancel(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
NTSTATUS status = STATUS_SUCCESS;
KIRQL irql;
__try
{
SmartcardDebug( DEBUG_TRACE, ("ScUtil_Cancel Enter\n"));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_CANCELLED;
KeAcquireSpinLock(&pExt->SmartcardExtension->OsData->SpinLock,
&irql);
pExt->SmartcardExtension->OsData->NotificationIrp = NULL;
KeReleaseSpinLock(&pExt->SmartcardExtension->OsData->SpinLock,
irql);
IoReleaseCancelSpinLock(Irp->CancelIrql);
IoReleaseRemoveLock(pExt->RemoveLock,
Irp);
IoCompleteRequest(
Irp,
IO_NO_INCREMENT);
}
__finally
{
SmartcardDebug( DEBUG_TRACE, ("ScUtil_Cancel Exit : 0x%x\n",status ));
}
return status;
}
NTSTATUS
ScUtil_CancelTrackingIrp(
PSCUTIL_EXTENSION pExt
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSMARTCARD_EXTENSION pSmartcardExtension = pExt->SmartcardExtension;
PIRP notificationIrp = NULL;
KIRQL irql;
KIRQL cancelIrql;
__try
{
SmartcardDebug(DEBUG_TRACE,
("Enter: ScUtil_CancelTrackingIrp\n"));
IoAcquireCancelSpinLock(&cancelIrql);
// cancel pending notification irps
KeAcquireSpinLock(&pSmartcardExtension->OsData->SpinLock,
&irql);
if ( pSmartcardExtension->OsData->NotificationIrp ) {
// reset the cancel function so that it won't be called anymore
IoSetCancelRoutine(pSmartcardExtension->OsData->NotificationIrp,
NULL);
pSmartcardExtension->OsData->NotificationIrp->CancelIrql = cancelIrql;
notificationIrp = pSmartcardExtension->OsData->NotificationIrp;
pSmartcardExtension->OsData->NotificationIrp = NULL;
}
KeReleaseSpinLock(&pSmartcardExtension->OsData->SpinLock,
irql);
if (notificationIrp) {
IoSetCancelRoutine(notificationIrp,
NULL);
}
IoReleaseCancelSpinLock(cancelIrql);
if (notificationIrp) {
notificationIrp->IoStatus.Information = 0;
notificationIrp->IoStatus.Status = STATUS_CANCELLED;
status = STATUS_CANCELLED;
IoReleaseRemoveLock(pExt->RemoveLock,
notificationIrp);
IoCompleteRequest(notificationIrp,
IO_NO_INCREMENT);
}
}
__finally
{
SmartcardDebug(DEBUG_TRACE,
("Exit: ScUtil_CancelTrackingIrp (0x%x)\n", status));
}
return status;
}
NTSTATUS
ScUtil_Initialize(
SCUTIL_HANDLE *UtilHandle,
PDEVICE_OBJECT PhysicalDeviceObject,
PDEVICE_OBJECT LowerDeviceObject,
PSMARTCARD_EXTENSION SmartcardExtension,
PIO_REMOVE_LOCK RemoveLock,
PNP_CALLBACK StartDevice,
PNP_CALLBACK StopDevice,
PNP_CALLBACK RemoveDevice,
PNP_CALLBACK FreeResources,
POWER_CALLBACK SetPowerState
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSCUTIL_EXTENSION pExt = (PSCUTIL_EXTENSION) ExAllocatePool(NonPagedPool,
sizeof(SCUTIL_EXTENSION));
*UtilHandle = pExt;
PAGED_CODE();
__try
{
SmartcardDebug(DEBUG_TRACE,
("Enter: ScUtil_Initialize\n"));
pExt->LowerDeviceObject = LowerDeviceObject;
pExt->PhysicalDeviceObject = PhysicalDeviceObject;
pExt->SmartcardExtension = SmartcardExtension;
pExt->RemoveLock = RemoveLock;
pExt->StartDevice = StartDevice;
pExt->StopDevice = StopDevice;
pExt->RemoveDevice = RemoveDevice;
pExt->FreeResources = FreeResources;
pExt->SetPowerState = SetPowerState;
IoInitializeRemoveLock(RemoveLock,
'LUCS',
0,
20);
KeInitializeEvent(&pExt->OkToStop,
NotificationEvent,
TRUE);
pExt->IoCount = 0;
pExt->ReaderOpen = 0;
pExt->PowerState = PowerDeviceUnspecified;
IrpList_Init(&pExt->PendingIrpQueue,
IrpList_CancelRoutine,
NULL);
pExt->RestartIoctls = FALSE;
SetPnPState(pExt,
DEVICE_STATE_INITIALIZED);
// register our new device
status = IoRegisterDeviceInterface(PhysicalDeviceObject,
&SmartCardReaderGuid,
NULL,
&pExt->DeviceName);
}
__finally
{
SmartcardDebug(DEBUG_TRACE,
("Exit: ScUtil_Initialize (0x%x)\n", status));
}
return status;
}
NTSTATUS
ScUtil_DeviceIOControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
QUEUE_STATE state;
BOOLEAN complete = FALSE;
ASSERT(pExt);
__try
{
SmartcardDebug(DEBUG_TRACE,
("Enter: ScUtil_DeviceIOControl\n"));
status = IoAcquireRemoveLock(pExt->RemoveLock,
Irp);
if (!NT_SUCCESS(status)) {
// the device has been removed. Fail the call
status = STATUS_DEVICE_REMOVED;
complete = TRUE;
__leave;
}
state = GetIoctlQueueState(pExt);
if ( state == QUEUE_IOCTLS) {
//
// Need to queue Irp
//
status = IrpList_EnqueueEx(&pExt->PendingIrpQueue,
Irp,
TRUE);
if (!NT_SUCCESS(status)) {
// the irp couldn't be queued.
IoReleaseRemoveLock(pExt->RemoveLock,
Irp);
complete = TRUE;
}
__leave;
} else if (state == FAIL_IOCTLS) {
status = STATUS_DEVICE_REMOVED;
complete = TRUE;
__leave;
}
IncIoCount(pExt);
status = SmartcardDeviceControl(pExt->SmartcardExtension,
Irp);
IoReleaseRemoveLock(pExt->RemoveLock,
Irp);
DecIoCount(pExt);
}
__finally
{
if (complete) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
SmartcardDebug(DEBUG_TRACE,
("Exit: ScUtil_DeviceIOControl (0x%x)\n", status));
}
return status;
}
NTSTATUS
ScUtil_Cleanup(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
PSMARTCARD_EXTENSION pSmartcardExtension = pExt->SmartcardExtension;
KIRQL cancelIrql;
ASSERT(pExt);
__try
{
SmartcardDebug(DEBUG_TRACE,
("Enter: ScUtil_Cleanup\n"));
ScUtil_CancelTrackingIrp(pExt);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp,
IO_NO_INCREMENT);
status = STATUS_SUCCESS;
}
__finally
{
SmartcardDebug(DEBUG_TRACE,
("Exit: ScUtil_Cleanup (0x%x)\n", status));
}
return status;
}
NTSTATUS
ScUtil_UnloadDriver(
PDRIVER_OBJECT DriverObject
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PAGED_CODE();
__try
{
SmartcardDebug(DEBUG_TRACE,
("Enter: ScUtil_UnloadDriver\n"));
}
__finally
{
SmartcardDebug(DEBUG_TRACE,
("Exit: ScUtil_UnloadDriver (0x%x)\n", status));
}
return status;
}
NTSTATUS
ScUtil_CreateClose(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSCUTIL_EXTENSION pExt = *((PSCUTIL_EXTENSION*) DeviceObject->DeviceExtension);
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(pExt);
PAGED_CODE();
__try
{
SmartcardDebug(DEBUG_TRACE,
("Enter: ScUtil_CreateClose\n"));
if ( pIrpStack->MajorFunction == IRP_MJ_CREATE ) {
status = IoAcquireRemoveLock(pExt->RemoveLock,
DeviceObject);
if (!NT_SUCCESS(status)) {
status = STATUS_DEVICE_REMOVED;
__leave;
}
// test if the device has been opened already
if ( InterlockedCompareExchange(&pExt->ReaderOpen,
1,
0) == 0 ) {
//
//
} else {
// the device is already in use
status = STATUS_UNSUCCESSFUL;
// release the lock
IoReleaseRemoveLock(pExt->RemoveLock,
DeviceObject);
}
} else {
if (InterlockedCompareExchange(&pExt->ReaderOpen,
0,
1) == 1) {
IoReleaseRemoveLock(pExt->RemoveLock,
DeviceObject);
}
}
}
__finally
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
SmartcardDebug(DEBUG_TRACE,
("Exit: ScUtil_CreateClose (0x%x)\n", status));
}
return status;
}