windows-nt/Source/XPSP1/NT/drivers/dot4/dot4usb/ioctl.c

409 lines
15 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/***************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
Dot4Usb.sys - Lower Filter Driver for Dot4.sys for USB connected
IEEE 1284.4 devices.
File Name:
Ioctl.c
Abstract:
Dispatch routines for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL
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) 2000 Microsoft Corporation. All Rights Reserved.
Revision History:
01/18/2000 : created
ToDo in this file:
- code review
Author(s):
Doug Fritz (DFritz)
Joby Lafky (JobyL)
****************************************************************************/
#include "pch.h"
/************************************************************************/
/* DispatchDeviceControl */
/************************************************************************/
//
// Routine Description:
//
// Dispatch routine for IRP_MJ_DEVICE_CONTROL
// - We don't currently handle any such requests but we may do
// so in the future. Pass any unhandled requests down the
// stack to the device below us.
//
// Arguments:
//
// DevObj - pointer to DeviceObject that is the target of the request
// Irp - pointer to device control IRP
//
// Return Value:
//
// NTSTATUS
//
/************************************************************************/
NTSTATUS
DispatchDeviceControl(
IN PDEVICE_OBJECT DevObj,
IN PIRP Irp
)
{
PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
NTSTATUS status;
ULONG info = 0;
TR_VERBOSE(("DispatchDeviceControl - enter"));
status = IoAcquireRemoveLock( &devExt->RemoveLock, Irp );
if( NT_SUCCESS(status) ) {
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
case IOCTL_PAR_QUERY_DEVICE_ID:
// ISSUE - 000901 - DFritz - these new IOCTLs need to do parameter validation to avoid AVs
{
const LONG minValidIdLength = sizeof("MFG:x;MDL:y;");
const ULONG bufSize = 1024;
PCHAR idBuffer = ExAllocatePool( NonPagedPool, bufSize );
LONG idLength;
if( idBuffer ) {
RtlZeroMemory( idBuffer, bufSize );
idLength = UsbGet1284Id( DevObj, idBuffer, bufSize-1 );
if( idLength < minValidIdLength ) {
status = STATUS_UNSUCCESSFUL;
} else if( (ULONG)idLength >= irpSp->Parameters.DeviceIoControl.OutputBufferLength ) {
status = STATUS_BUFFER_TOO_SMALL;
} else {
RtlZeroMemory( Irp->AssociatedIrp.SystemBuffer, idLength+1 );
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, idBuffer+2, idLength-2 );
info = idLength - 1;
status = STATUS_SUCCESS;
}
ExFreePool( idBuffer );
} else {
status = STATUS_NO_MEMORY;
}
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
break;
case IOCTL_PAR_QUERY_RAW_DEVICE_ID:
{
const LONG minValidIdLength = sizeof("MFG:x;MDL:y;");
const ULONG bufSize = 1024;
PCHAR idBuffer = ExAllocatePool( NonPagedPool, bufSize );
LONG idLength;
if( idBuffer ) {
RtlZeroMemory( idBuffer, bufSize );
idLength = UsbGet1284Id( DevObj, idBuffer, bufSize-1 );
if( idLength < minValidIdLength ) {
status = STATUS_UNSUCCESSFUL;
} else if( (ULONG)idLength >= irpSp->Parameters.DeviceIoControl.OutputBufferLength ) {
status = STATUS_BUFFER_TOO_SMALL;
} else {
RtlZeroMemory( Irp->AssociatedIrp.SystemBuffer, idLength+1 );
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, idBuffer, idLength);
info = idLength + 1;
status = STATUS_SUCCESS;
}
ExFreePool( idBuffer );
} else {
status = STATUS_NO_MEMORY;
}
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
break;
case IOCTL_PAR_QUERY_DEVICE_ID_SIZE:
{
const LONG minValidIdLength = sizeof("MFG:x;MDL:y;");
const ULONG bufSize = 1024;
PCHAR idBuffer = ExAllocatePool( NonPagedPool, bufSize );
LONG idLength;
if( idBuffer ) {
RtlZeroMemory( idBuffer, bufSize );
idLength = UsbGet1284Id( DevObj, idBuffer, bufSize-1 );
if( idLength < minValidIdLength ) {
status = STATUS_UNSUCCESSFUL;
} else if( sizeof(ULONG) < irpSp->Parameters.DeviceIoControl.OutputBufferLength ) {
status = STATUS_BUFFER_TOO_SMALL;
} else {
++idLength; // save room for terminating NULL
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &idLength, sizeof(ULONG));
info = sizeof(ULONG);
status = STATUS_SUCCESS;
}
ExFreePool( idBuffer );
} else {
status = STATUS_NO_MEMORY;
}
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = info;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
break;
case IOCTL_PAR_QUERY_LOCATION:
_snprintf( Irp->AssociatedIrp.SystemBuffer, 4, "USB" );
info = 4;
status = STATUS_SUCCESS;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
default:
// pass request down
IoSkipCurrentIrpStackLocation( Irp );
status = IoCallDriver( devExt->LowerDevObj, Irp );
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
}
} else {
// unable to acquire RemoveLock - FAIL request
Irp->IoStatus.Status = status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return status;
}
/************************************************************************/
/* DispatchInternalDeviceControl */
/************************************************************************/
//
// Routine Description:
//
// Dispatch routine for IRP_MJ_INTERNAL_DEVICE_CONTROL
// - We expect DataLink requests from dot4.sys driver above us. Any
// request that we don't handle is simply passed down the stack
// to the driver below us.
//
// Arguments:
//
// DevObj - pointer to DeviceObject that is the target of the request
// Irp - pointer to device control IRP
//
// Return Value:
//
// NTSTATUS
//
/************************************************************************/
NTSTATUS
DispatchInternalDeviceControl(
IN PDEVICE_OBJECT DevObj,
IN PIRP Irp
)
{
NTSTATUS status;
PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
TR_VERBOSE(("DispatchInternalDeviceControl - enter"));
status = IoAcquireRemoveLock( &devExt->RemoveLock, Irp );
if( NT_SUCCESS(status) ) {
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
BOOLEAN bCompleteIrp = FALSE;
KIRQL oldIrql;
switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
case IOCTL_INTERNAL_PARDOT3_CONNECT:
//
// Enter a "DataLink Connected" state with dot4.sys
//
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_CONNECT"));
KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
if( !devExt->IsDLConnected ) {
devExt->IsDLConnected = TRUE;
status = STATUS_SUCCESS;
} else {
// we believe that we are in a "datalink connected state" but obviously
// dot4.sys doesn't agree - suggest investigating further if we hit
// this assert
D4UAssert(FALSE);
status = STATUS_INVALID_DEVICE_REQUEST;
}
KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
bCompleteIrp = TRUE;
break;
case IOCTL_INTERNAL_PARDOT3_RESET:
//
// This IOCTL is specific to parallel and is a NOOP for a USB connection.
//
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_RESET"));
status = STATUS_SUCCESS;
bCompleteIrp = TRUE;
break;
case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
//
// Terminate the "DataLink Connected" state with dot4.sys and
// invalidate any Dot4Event since the event may be freed anytime
// after we complete this IRP.
//
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_DISCONNECT"));
UsbStopReadInterruptPipeLoop( DevObj );
KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
devExt->Dot4Event = NULL; // invalidate dot4's event, if any, so we stop signalling dot4
if( devExt->IsDLConnected ) {
devExt->IsDLConnected = FALSE;
} else {
// we believe that we are NOT in a "datalink connected state" but obviously
// dot4.sys doesn't agree - suggest investigating further if we hit
// this assert
D4UAssert(FALSE);
}
KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
status = STATUS_SUCCESS; // we always succeed this request since it is a disconnect
bCompleteIrp = TRUE;
break;
case IOCTL_INTERNAL_PARDOT3_SIGNAL:
//
// dot4.sys is giving us a pointer to an Event that it owns and dot4
// expects us to Signal this event whenever we detect that the device has
// data available to be read. We continue signalling this event on device
// data avail until we receive a disconnect IOCTL.
//
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_SIGNAL"));
KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
if( devExt->IsDLConnected ) {
if( !devExt->Dot4Event ) {
// our state indicates that it is OK to receive this request
if( irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PKEVENT) ) {
status = STATUS_INVALID_PARAMETER;
} else {
// save the pointer to the event in our device extension
PKEVENT Event;
RtlCopyMemory(&Event, Irp->AssociatedIrp.SystemBuffer, sizeof(PKEVENT));
devExt->Dot4Event = Event;
status = STATUS_SUCCESS;
}
} else {
// we already have an event and dot4.sys sent us another one? - bad driver - AV crash likely real soon now
D4UAssert(FALSE);
status = STATUS_INVALID_DEVICE_REQUEST;
}
} else {
// we're not in a datalink connected state - this is an invalid request
D4UAssert(FALSE);
status = STATUS_INVALID_DEVICE_REQUEST;
}
KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
if( NT_SUCCESS(status) && devExt->InterruptPipe ) {
status = UsbStartReadInterruptPipeLoop( DevObj );
}
bCompleteIrp = TRUE;
break;
default :
// unhandled request - pass it down the stack
IoSkipCurrentIrpStackLocation( Irp );
status = IoCallDriver( devExt->LowerDevObj, Irp );
bCompleteIrp = FALSE;
}
if( bCompleteIrp ) {
// we didn't pass this request down the stack, so complete it now
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
} else {
// unable to acquire RemoveLock - we're in the process of being removed - FAIL request
Irp->IoStatus.Status = status;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return status;
}