You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
760 lines
17 KiB
760 lines
17 KiB
/***************************************************************************
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|