/*************************************************************************** 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; }