|
|
/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
devcaps.c
Abstract:
This module contains the implementation for the Microsoft Biometric Device Library
Environment:
Kernel mode only.
Notes:
Revision History:
- Created December 2002 by Reid Kuhn
--*/
#include <winerror.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <strsafe.h>
#include <wdm.h>
#include "bdlint.h"
#define PRODUCT_NOT_REQUESTED 0
#define PRODUCT_HANDLE_REQUESTED 1
#define PRODUCT_BLOCK_REQUESTED 2
NTSTATUS BDLRegisteredCancelGetNotificationIRP ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp );
//
// Supporting functions for checking ID's
//
//
BOOLEAN BDLCheckComponentId ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG ComponentId, OUT ULONG *pComponentIndex ) { ULONG i;
for (i = 0; i < pBDLExtension->DeviceCapabilities.NumComponents; i++) { if (pBDLExtension->DeviceCapabilities.rgComponents[i].ComponentId == ComponentId) { break; } }
if (i >= pBDLExtension->DeviceCapabilities.NumComponents) { return (FALSE); }
*pComponentIndex = i;
return (TRUE); }
BOOLEAN BDLCheckChannelId ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG ComponentIndex, IN ULONG ChannelId, OUT ULONG *pChannelIndex ) { ULONG i;
for (i = 0; i < pBDLExtension->DeviceCapabilities.rgComponents[ComponentIndex].NumChannels; i++) { if (pBDLExtension->DeviceCapabilities.rgComponents[ComponentIndex].rgChannels[i].ChannelId == ChannelId) { break; } }
if (i >= pBDLExtension->DeviceCapabilities.rgComponents[ComponentIndex].NumChannels) { return (FALSE); }
*pChannelIndex = i;
return (TRUE); }
BOOLEAN BDLCheckControlIdInArray ( IN BDL_CONTROL *rgControls, IN ULONG NumControls, IN ULONG ControlId, OUT BDL_CONTROL **ppBDLControl ) { ULONG i;
for (i = 0; i < NumControls; i++) { if (rgControls[i].ControlId == ControlId) { break; } }
if (i >= NumControls) { return (FALSE); }
*ppBDLControl = &(rgControls[i]); return (TRUE); }
BOOLEAN BDLCheckControlId ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG ComponentId, IN ULONG ChannelId, IN ULONG ControlId, OUT BDL_CONTROL **ppBDLControl ) { ULONG i, j;
*ppBDLControl = NULL;
//
// If ComponentId is 0 then it is a device level control
//
if (ComponentId == 0) { //
// Check device level control ID
//
if (BDLCheckControlIdInArray( pBDLExtension->DeviceCapabilities.rgControls, pBDLExtension->DeviceCapabilities.NumControls, ControlId, ppBDLControl) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCheckControlId: Bad Device level ControlId\n", __DATE__, __TIME__)) return (FALSE); } } else { //
// Check the ComponentId
//
if (BDLCheckComponentId(pBDLExtension, ComponentId, &i) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCheckControlId: Bad ComponentId\n", __DATE__, __TIME__)) return (FALSE); }
if (ChannelId == 0) { //
// Check Component level control ID
//
if (BDLCheckControlIdInArray( pBDLExtension->DeviceCapabilities.rgComponents[i].rgControls, pBDLExtension->DeviceCapabilities.rgComponents[i].NumControls, ControlId, ppBDLControl) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCheckControlId: Bad Component level ControlId\n", __DATE__, __TIME__)) return (FALSE); } } else { //
// Check channel ID
//
if (BDLCheckChannelId(pBDLExtension, i, ChannelId, &j) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCheckControlId: Bad ChannelId\n", __DATE__, __TIME__)) return (FALSE); }
//
// Check channel level control ID
//
if (BDLCheckControlIdInArray( pBDLExtension->DeviceCapabilities.rgComponents[i].rgChannels[j].rgControls, pBDLExtension->DeviceCapabilities.rgComponents[i].rgChannels[j].NumControls, ControlId, ppBDLControl) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLCheckControlId: Bad channel level ControlId\n", __DATE__, __TIME__)) return (FALSE); } } }
return (TRUE); }
NTSTATUS BDLIOCTL_Startup ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_Startup: Enter\n", __DATE__, __TIME__))
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bdsiFunctions.pfbdsiStartup( &(pBDLExtension->BdlExtenstion));
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_Startup: pfbdsiStartup failed with %lx\n", __DATE__, __TIME__, status)) }
//
// Set the number of bytes used
//
*pOutputBufferUsed = 0;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_Startup: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_Shutdown ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_Shutdown: Enter\n", __DATE__, __TIME__))
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bdsiFunctions.pfbdsiShutdown( &(pBDLExtension->BdlExtenstion));
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_Shutdown: pfbdsiShutdown failed with %lx\n", __DATE__, __TIME__, status)) }
//
// Set the number of bytes used
//
*pOutputBufferUsed = 0;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_Shutdown: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_GetDeviceInfo ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; ULONG RequiredOutputSize = 0; PUCHAR pv = pBuffer;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetDeviceInfo: Enter\n", __DATE__, __TIME__))
//
// Make sure there is enough space for the return buffer
//
RequiredOutputSize = SIZEOF_GETDEVICEINFO_OUTPUTBUFFER; if (RequiredOutputSize > OutputBufferLength) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetDeviceInfo: Output buffer is too small\n", __DATE__, __TIME__))
status = STATUS_BUFFER_TOO_SMALL; goto Return; }
//
// Write the device info to the output buffer
//
pv = pBuffer;
RtlCopyMemory( pv, &(pBDLExtension->wszSerialNumber[0]), sizeof(pBDLExtension->wszSerialNumber)); pv += sizeof(pBDLExtension->wszSerialNumber);
*((ULONG *) pv) = pBDLExtension->HWVersionMajor; pv += sizeof(ULONG); *((ULONG *) pv) = pBDLExtension->HWVersionMinor; pv += sizeof(ULONG); *((ULONG *) pv) = pBDLExtension->HWBuildNumber; pv += sizeof(ULONG); *((ULONG *) pv) = pBDLExtension->BDDVersionMajor; pv += sizeof(ULONG); *((ULONG *) pv) = pBDLExtension->BDDVersionMinor; pv += sizeof(ULONG); *((ULONG *) pv) = pBDLExtension->BDDBuildNumber; //
// Set the number of bytes used
//
*pOutputBufferUsed = RequiredOutputSize;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetDeviceInfo: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_DoChannel ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; ULONG NumProducts = 0; ULONG NumSourceLists = 0; ULONG NumSources = 0; PUCHAR pv = pBuffer; BDDI_PARAMS_DOCHANNEL bddiDoChannelParams; ULONG i, j, x, y; ULONG ProductCreationType; ULONG RequiredInputSize = 0; ULONG RequiredOutputSize = 0; HANDLE hCancelEvent = NULL; KIRQL irql; BOOLEAN fHandleListLocked = FALSE; BDDI_PARAMS_CLOSEHANDLE bddiCloseHandleParams; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_DoChannel: Enter\n", __DATE__, __TIME__))
//
// Initialize the DoChannelParams struct
//
RtlZeroMemory(&bddiDoChannelParams, sizeof(bddiDoChannelParams)); bddiDoChannelParams.Size = sizeof(bddiDoChannelParams); //
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
RequiredInputSize = SIZEOF_DOCHANNEL_INPUTBUFFER; if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad input buffer\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Get all of the minimum input parameters (put the ones that are used
// in the DoChannel call directly into the DoChannelParams struct
//
bddiDoChannelParams.ComponentId = *((ULONG *) pv); pv += sizeof(ULONG); bddiDoChannelParams.ChannelId = *((ULONG *) pv); pv += sizeof(ULONG); hCancelEvent = *((HANDLE *) pv); pv += sizeof(HANDLE); bddiDoChannelParams.hStateData = *((BDD_DATA_HANDLE *) pv); pv += sizeof(BDD_DATA_HANDLE); NumProducts = *((ULONG *) pv); pv += sizeof(ULONG); NumSourceLists = *((ULONG *) pv); pv += sizeof(ULONG);
//
// Check the size of the input buffer to make sure it is large enough
// so that we don't run off the end when getting the products array and
// sources lists array
//
// Note that this only checks based on each source list being 0 length,
// so we need to check again before getting each source list.
//
RequiredInputSize += (NumProducts * sizeof(ULONG)) + (NumSourceLists * sizeof(ULONG)); if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad input buffer\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Check the size of the output buffer to make sure it is large enough
// to accommodate the standard output + all the products
//
RequiredOutputSize = SIZEOF_DOCHANNEL_OUTPUTBUFFER + (sizeof(BDD_HANDLE) * NumProducts); if (OutputBufferLength < RequiredOutputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad input buffer\n", __DATE__, __TIME__))
status = STATUS_BUFFER_TOO_SMALL; goto ErrorReturn; } //
// Check the ComponentId and ChannelId
//
if (BDLCheckComponentId(pBDLExtension, bddiDoChannelParams.ComponentId, &i) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad ComponentId\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
if (BDLCheckChannelId(pBDLExtension, i, bddiDoChannelParams.ChannelId, &j) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad ChannelId\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Check to make sure the NumProducts and NumSourceLists are correct
//
if (NumProducts != pBDLExtension->DeviceCapabilities.rgComponents[i].rgChannels[j].NumProducts) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad number of Source Lists\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
if (NumSourceLists != pBDLExtension->DeviceCapabilities.rgComponents[i].rgChannels[j].NumSourceLists) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad number of Source Lists\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Allocate the space for the product pointer array then get each product
// request type from the input block
//
bddiDoChannelParams.rgpProducts = ExAllocatePoolWithTag( PagedPool, sizeof(PBDDI_ITEM) * NumProducts, BDL_ULONG_TAG);
RtlZeroMemory(bddiDoChannelParams.rgpProducts, sizeof(PBDDI_ITEM) * NumProducts);
for (x = 0; x < NumProducts; x++) { ProductCreationType = *((ULONG *) pv); pv += sizeof(ULONG);
switch (ProductCreationType) { case PRODUCT_NOT_REQUESTED:
bddiDoChannelParams.rgpProducts[x] = NULL;
break;
case PRODUCT_HANDLE_REQUESTED:
//
// Make sure the channel supports handle type return
//
if (!(BIO_ITEMTYPE_HANDLE & pBDLExtension->DeviceCapabilities.rgComponents[i].rgChannels[j].rgProducts[x].Flags)) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad product type request\n", __DATE__, __TIME__)) status = STATUS_INVALID_PARAMETER; goto ErrorReturn;
}
bddiDoChannelParams.rgpProducts[x] = ExAllocatePoolWithTag( PagedPool, sizeof(BDDI_ITEM), BDL_ULONG_TAG);
if (bddiDoChannelParams.rgpProducts[x] == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel:ExAllocatePoolWithTag failed\n", __DATE__, __TIME__)) status = STATUS_NO_MEMORY; goto ErrorReturn; }
bddiDoChannelParams.rgpProducts[x]->Type = BIO_ITEMTYPE_HANDLE; bddiDoChannelParams.rgpProducts[x]->Data.Handle = NULL;
break;
case PRODUCT_BLOCK_REQUESTED:
//
// Make sure the channel supports handle type return
//
if (!(BIO_ITEMTYPE_BLOCK & pBDLExtension->DeviceCapabilities.rgComponents[i].rgChannels[j].rgProducts[x].Flags)) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad product type request\n", __DATE__, __TIME__)) status = STATUS_INVALID_PARAMETER; goto ErrorReturn;
}
bddiDoChannelParams.rgpProducts[x] = ExAllocatePoolWithTag( PagedPool, sizeof(BDDI_ITEM), BDL_ULONG_TAG);
if (bddiDoChannelParams.rgpProducts[x] == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel:ExAllocatePoolWithTag failed\n", __DATE__, __TIME__)) status = STATUS_NO_MEMORY; goto ErrorReturn; }
bddiDoChannelParams.rgpProducts[x]->Type = BIO_ITEMTYPE_BLOCK; bddiDoChannelParams.rgpProducts[x]->Data.Block.pBuffer = NULL; bddiDoChannelParams.rgpProducts[x]->Data.Block.cBuffer = 0;
break;
default:
BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad Product Request\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; break; } }
//
// Allocate space for the source lists
//
bddiDoChannelParams.rgSourceLists = ExAllocatePoolWithTag( PagedPool, sizeof(BDDI_SOURCELIST) * NumSourceLists, BDL_ULONG_TAG);
RtlZeroMemory(bddiDoChannelParams.rgSourceLists, sizeof(BDDI_SOURCELIST) * NumSourceLists);
//
// We are going to start messing with the handle list, so lock it
//
BDLLockHandleList(pBDLExtension, &irql); fHandleListLocked = TRUE;
//
// Get each source list from input buffer
//
for (x = 0; x < NumSourceLists; x++) { NumSources = *((ULONG *) pv); pv += sizeof(ULONG);
//
// Check the size of the input buffer to make sure it is large enough
// so that we don't run off the end when getting this source lists
//
RequiredInputSize += NumSources * sizeof(BDD_HANDLE); if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad input buffer\n", __DATE__, __TIME__)) status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Allocate the array of sources and then get each source in the list
//
bddiDoChannelParams.rgSourceLists[x].rgpSources = ExAllocatePoolWithTag( PagedPool, sizeof(PBDDI_ITEM) * NumSources, BDL_ULONG_TAG);
if (bddiDoChannelParams.rgpProducts[x] == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel:ExAllocatePoolWithTag failed\n", __DATE__, __TIME__)) status = STATUS_NO_MEMORY; goto ErrorReturn; }
bddiDoChannelParams.rgSourceLists[x].NumSources = NumSources;
for (y = 0; y < NumSources; y++) { bddiDoChannelParams.rgSourceLists[x].rgpSources[y] = *((BDD_HANDLE *) pv); pv += sizeof(BDD_HANDLE);
if (BDLValidateHandleIsInList( &(pBDLExtension->HandleList), bddiDoChannelParams.rgSourceLists[x].rgpSources[y]) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: Bad input handle\n", __DATE__, __TIME__)) status = STATUS_INVALID_PARAMETER; goto ErrorReturn; } } } //
// If there is a cancel event then get the kernel mode event pointer
// from the user mode event handle
//
if (hCancelEvent != NULL) { status = ObReferenceObjectByHandle( hCancelEvent, EVENT_QUERY_STATE | EVENT_MODIFY_STATE, NULL, KernelMode, &(bddiDoChannelParams.CancelEvent), NULL); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: ObReferenceObjectByHandle failed with %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; } }
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiDoChannel( &(pBDLExtension->BdlExtenstion), &bddiDoChannelParams);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: pfbddiDoChannel failed with %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; }
//
// Write the output data to the output buffer
//
pv = pBuffer;
*((ULONG *) pv) = bddiDoChannelParams.BIOReturnCode; pv += sizeof(ULONG); *((BDD_DATA_HANDLE *) pv) = bddiDoChannelParams.hStateData; pv += sizeof(BDD_DATA_HANDLE);
//
// Add all the product handles to the output buffer and to the handle list
//
for (x = 0; x < NumProducts; x++) { *((BDD_HANDLE *) pv) = bddiDoChannelParams.rgpProducts[x]; pv += sizeof(BDD_HANDLE); if (bddiDoChannelParams.rgpProducts[x] != NULL) { status = BDLAddHandleToList( &(pBDLExtension->HandleList), bddiDoChannelParams.rgpProducts[x]);
if (status != STATUS_SUCCESS) { //
// Remove the handles that were already added to the handle list
//
for (y = 0; y < x; y++) { BDLRemoveHandleFromList( &(pBDLExtension->HandleList), bddiDoChannelParams.rgpProducts[y]); } BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_DoChannel: BDLAddHandleToList failed with %lx\n", __DATE__, __TIME__, status)) goto ErrorReturn; } } }
*pOutputBufferUsed = RequiredOutputSize; Return:
if (fHandleListLocked == TRUE) { BDLReleaseHandleList(pBDLExtension, irql); }
if (bddiDoChannelParams.rgpProducts != NULL) { ExFreePoolWithTag(bddiDoChannelParams.rgpProducts, BDL_ULONG_TAG); }
if (bddiDoChannelParams.rgSourceLists != NULL) { for (x = 0; x < NumSourceLists; x++) { if (bddiDoChannelParams.rgSourceLists[x].rgpSources != NULL) { ExFreePoolWithTag(bddiDoChannelParams.rgSourceLists[x].rgpSources, BDL_ULONG_TAG); } }
ExFreePoolWithTag(bddiDoChannelParams.rgSourceLists, BDL_ULONG_TAG); }
if (bddiDoChannelParams.CancelEvent != NULL) { ObDereferenceObject(bddiDoChannelParams.CancelEvent); }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_DoChannel: Leave\n", __DATE__, __TIME__))
return (status);
ErrorReturn:
for (x = 0; x < NumProducts; x++) { if (bddiDoChannelParams.rgpProducts[x] != NULL) { if (bddiDoChannelParams.rgpProducts[x]->Type == BIO_ITEMTYPE_HANDLE) { if (bddiDoChannelParams.rgpProducts[x]->Data.Handle != NULL) { bddiCloseHandleParams.Size = sizeof(bddiCloseHandleParams); bddiCloseHandleParams.hData = bddiDoChannelParams.rgpProducts[x]->Data.Handle; pBDLExtension->pDriverExtension->bddiFunctions.pfbddiCloseHandle( &(pBDLExtension->BdlExtenstion), &bddiCloseHandleParams); } } else { if (bddiDoChannelParams.rgpProducts[x]->Data.Block.pBuffer != NULL) { bdliFree(bddiDoChannelParams.rgpProducts[x]->Data.Block.pBuffer); } }
ExFreePoolWithTag(bddiDoChannelParams.rgpProducts[x], BDL_ULONG_TAG); } }
goto Return; }
NTSTATUS BDLIOCTL_GetControl ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; ULONG RequiredOutputSize = 0; BDDI_PARAMS_GETCONTROL bddiGetControlParams; PUCHAR pv = pBuffer; ULONG i, j; BDL_CONTROL *pBDLControl = NULL;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetControl: Enter\n", __DATE__, __TIME__))
//
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
if (InpuBufferLength < SIZEOF_GETCONTROL_INPUTBUFFER) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetControl: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Make sure there is enough space for the return buffer
//
RequiredOutputSize = SIZEOF_GETCONTROL_OUTPUTBUFFER; if (RequiredOutputSize > OutputBufferLength) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetControl: Output buffer is too small\n", __DATE__, __TIME__))
status = STATUS_BUFFER_TOO_SMALL; goto Return; }
//
// Initialize the BDD struct
//
RtlZeroMemory(&bddiGetControlParams, sizeof(bddiGetControlParams)); bddiGetControlParams.Size = sizeof(bddiGetControlParams);
//
// Get the input parameters from the buffer
//
bddiGetControlParams.ComponentId = *((ULONG *) pv); pv += sizeof(ULONG); bddiGetControlParams.ChannelId = *((ULONG *) pv); pv += sizeof(ULONG); bddiGetControlParams.ControlId = *((ULONG *) pv);
//
// Check control ID
//
if (BDLCheckControlId( pBDLExtension, bddiGetControlParams.ComponentId, bddiGetControlParams.ChannelId, bddiGetControlParams.ControlId, &pBDLControl) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetControl: Bad ControlId\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiGetControl( &(pBDLExtension->BdlExtenstion), &bddiGetControlParams);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetControl: pfbddiGetControl failed with %lx\n", __DATE__, __TIME__, status))
goto Return; } //
// Write the output info to the output buffer
//
pv = pBuffer;
*((ULONG *) pv) = bddiGetControlParams.Value; pv += sizeof(ULONG);
RtlCopyMemory(pv, bddiGetControlParams.wszString, sizeof(bddiGetControlParams.wszString));
//
// Set the number of bytes used
//
*pOutputBufferUsed = RequiredOutputSize;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetControl: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_SetControl ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; BDDI_PARAMS_SETCONTROL bddiSetControlParams; PUCHAR pv = pBuffer; ULONG i, j; BDL_CONTROL *pBDLControl = NULL;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_SetControl: Enter\n", __DATE__, __TIME__))
//
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
if (InpuBufferLength < SIZEOF_SETCONTROL_INPUTBUFFER) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_SetControl: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Initialize the BDD struct
//
RtlZeroMemory(&bddiSetControlParams, sizeof(bddiSetControlParams)); bddiSetControlParams.Size = sizeof(bddiSetControlParams);
//
// Get the input parameters from the buffer
//
bddiSetControlParams.ComponentId = *((ULONG *) pv); pv += sizeof(ULONG); bddiSetControlParams.ChannelId = *((ULONG *) pv); pv += sizeof(ULONG); bddiSetControlParams.ControlId = *((ULONG *) pv); pv += sizeof(ULONG); bddiSetControlParams.Value = *((ULONG *) pv); pv += sizeof(ULONG); RtlCopyMemory( &(bddiSetControlParams.wszString[0]), pv, sizeof(bddiSetControlParams.wszString));
//
// Check control ID
//
if (BDLCheckControlId( pBDLExtension, bddiSetControlParams.ComponentId, bddiSetControlParams.ChannelId, bddiSetControlParams.ControlId, &pBDLControl) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_SetControl: Bad ControlId\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// First make sure this isn't a read only value, then validate the
// actual value
//
if (pBDLControl->Flags & BIO_CONTROL_FLAG_READONLY) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_SetControl: trying to set a read only control\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; } if ((bddiSetControlParams.Value < pBDLControl->NumericMinimum) || (bddiSetControlParams.Value > pBDLControl->NumericMaximum) || (((bddiSetControlParams.Value - pBDLControl->NumericMinimum) % pBDLControl->NumericDivisor) != 0 )) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_SetControl: trying to set an invalid value\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; } //
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiSetControl( &(pBDLExtension->BdlExtenstion), &bddiSetControlParams);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_SetControl: pfbddiSetControl failed with %lx\n", __DATE__, __TIME__, status))
goto Return; } //
// Set the number of bytes used
//
*pOutputBufferUsed = 0;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_SetControl: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_CreateHandleFromData ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; ULONG RequiredOutputSize = 0; BDDI_PARAMS_CREATEHANDLE_FROMDATA bddiCreateHandleFromDataParams; PUCHAR pv = pBuffer; ULONG RequiredInputSize = 0; ULONG fTempHandle; BDDI_ITEM *pNewItem = NULL; KIRQL irql;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: Enter\n", __DATE__, __TIME__))
//
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
RequiredInputSize = SIZEOF_CREATEHANDLEFROMDATA_INPUTBUFFER; if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Make sure there is enough space for the return buffer
//
RequiredOutputSize = SIZEOF_CREATEHANDLEFROMDATA_OUTPUTBUFFER; if (RequiredOutputSize > OutputBufferLength) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: Output buffer is too small\n", __DATE__, __TIME__))
status = STATUS_BUFFER_TOO_SMALL; goto ErrorReturn; }
//
// Initialize the BDD struct
//
RtlZeroMemory(&bddiCreateHandleFromDataParams, sizeof(bddiCreateHandleFromDataParams)); bddiCreateHandleFromDataParams.Size = sizeof(bddiCreateHandleFromDataParams);
//
// Get the input parameters from the buffer
//
RtlCopyMemory(&(bddiCreateHandleFromDataParams.guidFormatId), pv, sizeof(GUID)); pv += sizeof(GUID); fTempHandle = *((ULONG *) pv); pv += sizeof(ULONG); bddiCreateHandleFromDataParams.cBuffer = *((ULONG *) pv); pv += sizeof(ULONG); bddiCreateHandleFromDataParams.pBuffer = pv;
//
// Check to make sure size of pBuffer isn't too large
//
RequiredInputSize += bddiCreateHandleFromDataParams.cBuffer; if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto ErrorReturn; }
//
// Create the new item
//
pNewItem = ExAllocatePoolWithTag(PagedPool, sizeof(BDDI_ITEM), BDL_ULONG_TAG);
if (pNewItem == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: ExAllocatePoolWithTag failed\n", __DATE__, __TIME__))
status = STATUS_NO_MEMORY; goto ErrorReturn; }
//
// If this is a temp handle then create it locally, otherwise call the BDD
//
if (fTempHandle) { pNewItem->Type = BIO_ITEMTYPE_BLOCK; pNewItem->Data.Block.pBuffer = bdliAlloc( &(pBDLExtension->BdlExtenstion), bddiCreateHandleFromDataParams.cBuffer, 0);
if (pNewItem->Data.Block.pBuffer == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: bdliAlloc failed\n", __DATE__, __TIME__)) status = STATUS_NO_MEMORY; goto ErrorReturn; }
pNewItem->Data.Block.cBuffer = bddiCreateHandleFromDataParams.cBuffer;
RtlCopyMemory( pNewItem->Data.Block.pBuffer, pv, bddiCreateHandleFromDataParams.cBuffer); } else { pNewItem->Type = BIO_ITEMTYPE_HANDLE;
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiCreateHandleFromData( &(pBDLExtension->BdlExtenstion), &bddiCreateHandleFromDataParams); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: pfbddiCreateHandleFromData failed with %lx\n", __DATE__, __TIME__, status)) goto ErrorReturn; }
pNewItem->Data.Handle = bddiCreateHandleFromDataParams.hData; }
//
// Add this handle to the list
//
BDLLockHandleList(pBDLExtension, &irql); status = BDLAddHandleToList(&(pBDLExtension->HandleList), pNewItem); BDLReleaseHandleList(pBDLExtension, irql);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: BDLAddHandleToList failed with %lx\n", __DATE__, __TIME__, status))
goto ErrorReturn; } //
// Write the output info to the output buffer
//
pv = pBuffer;
*((BDD_HANDLE *) pv) = pNewItem; //
// Set the number of bytes used
//
*pOutputBufferUsed = RequiredOutputSize;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_CreateHandleFromData: Leave\n", __DATE__, __TIME__))
return (status);
ErrorReturn:
if (pNewItem != NULL) { if ((pNewItem->Type == BIO_ITEMTYPE_BLOCK) && (pNewItem->Data.Block.pBuffer != NULL)) { bdliFree(pNewItem->Data.Block.pBuffer); } ExFreePoolWithTag(pNewItem, BDL_ULONG_TAG); }
goto Return; }
NTSTATUS BDLIOCTL_CloseHandle ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; BDDI_PARAMS_CLOSEHANDLE bddiCloseHandleParams; ULONG RequiredInputSize = 0; KIRQL irql; BDDI_ITEM *pBDDIItem = NULL; BOOLEAN fItemInList = FALSE;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_CloseHandle: Enter\n", __DATE__, __TIME__))
//
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
RequiredInputSize = SIZEOF_CLOSEHANDLE_INPUTBUFFER; if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CloseHandle: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Initialize the BDD struct
//
RtlZeroMemory(&bddiCloseHandleParams, sizeof(bddiCloseHandleParams)); bddiCloseHandleParams.Size = sizeof(bddiCloseHandleParams);
//
// Get the input parameters from the buffer
//
pBDDIItem = *((BDD_HANDLE *) pBuffer); //
// Validate the handle is in the list
//
BDLLockHandleList(pBDLExtension, &irql); fItemInList = BDLRemoveHandleFromList(&(pBDLExtension->HandleList), pBDDIItem); BDLReleaseHandleList(pBDLExtension, irql);
if (fItemInList == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CloseHandle: Bad handle\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; } //
// If this is a local handle then just clean it up, otherwise call the BDD
//
if (pBDDIItem->Type == BIO_ITEMTYPE_BLOCK) { bdliFree(pBDDIItem->Data.Block.pBuffer); } else { bddiCloseHandleParams.hData = pBDDIItem->Data.Handle;
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiCloseHandle( &(pBDLExtension->BdlExtenstion), &bddiCloseHandleParams); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_CloseHandle: pfbddiCloseHandle failed with %lx\n", __DATE__, __TIME__, status)) goto Return; } } ExFreePoolWithTag(pBDDIItem, BDL_ULONG_TAG); //
// Set the number of bytes used
//
*pOutputBufferUsed = 0;
Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_CloseHandle: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_GetDataFromHandle ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; ULONG RequiredOutputSize = 0; BDDI_PARAMS_GETDATA_FROMHANDLE bddiGetDataFromHandleParams; BDDI_PARAMS_CLOSEHANDLE bddiCloseHandleParams; PUCHAR pv = pBuffer; ULONG RequiredInputSize = 0; ULONG RemainingBufferSize = 0; KIRQL irql; BDDI_ITEM *pBDDIItem = NULL; BOOLEAN fItemInList = FALSE; BOOLEAN fCloseHandle = FALSE;
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetDataFromHandle: Enter\n", __DATE__, __TIME__))
//
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
RequiredInputSize = SIZEOF_GETDATAFROMHANDLE_INPUTBUFFER; if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetDataFromHandle: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Make sure there is enough space for the return buffer
//
RequiredOutputSize = SIZEOF_GETDATAFROMHANDLE_OUTPUTBUFFER; if (RequiredOutputSize > OutputBufferLength) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetDataFromHandle: Output buffer is too small\n", __DATE__, __TIME__))
status = STATUS_BUFFER_TOO_SMALL; goto Return; }
//
// Calculate the size remaining in the output buffer
//
RemainingBufferSize = OutputBufferLength - RequiredOutputSize;
//
// Initialize the BDD struct
//
RtlZeroMemory(&bddiGetDataFromHandleParams, sizeof(bddiGetDataFromHandleParams)); bddiGetDataFromHandleParams.Size = sizeof(bddiGetDataFromHandleParams);
//
// Get the input parameters from the buffer
//
pBDDIItem = *((BDD_HANDLE *) pv); pv += sizeof(BDD_HANDLE); if (*((ULONG *) pv) == 1) { fCloseHandle = TRUE; } { fCloseHandle = FALSE; } //
// Validate the handle is in the list
//
BDLLockHandleList(pBDLExtension, &irql); if (fCloseHandle) { fItemInList = BDLRemoveHandleFromList(&(pBDLExtension->HandleList), pBDDIItem); } else { fItemInList = BDLValidateHandleIsInList(&(pBDLExtension->HandleList), pBDDIItem); } BDLReleaseHandleList(pBDLExtension, irql);
if (fItemInList == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetDataFromHandle: Bad handle\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
pv = pBuffer; //
// If this is a local handle then just hand back the data, otherwise call the BDD
//
if (pBDDIItem->Type == BIO_ITEMTYPE_BLOCK) { //
// See if the output buffer is large enough
//
if (pBDDIItem->Data.Block.cBuffer > RemainingBufferSize) { bddiGetDataFromHandleParams.pBuffer = NULL; bddiGetDataFromHandleParams.BIOReturnCode = BIO_BUFFER_TOO_SMALL; } else { //
// Set the output buffer to be the IOCTL output buffer + the offset
// of the other output params which preceed the output data buffer
//
bddiGetDataFromHandleParams.pBuffer = pv + RequiredOutputSize;
//
// Copy the data
//
RtlCopyMemory( bddiGetDataFromHandleParams.pBuffer, pBDDIItem->Data.Block.pBuffer, pBDDIItem->Data.Block.cBuffer);
bddiGetDataFromHandleParams.BIOReturnCode = ERROR_SUCCESS; }
bddiGetDataFromHandleParams.cBuffer = pBDDIItem->Data.Block.cBuffer;
if (fCloseHandle) { bdliFree(pBDDIItem->Data.Block.pBuffer); } } else { bddiGetDataFromHandleParams.hData = pBDDIItem->Data.Handle; bddiGetDataFromHandleParams.cBuffer = RemainingBufferSize;
if (RemainingBufferSize == 0) { bddiGetDataFromHandleParams.pBuffer = NULL; } else { //
// Set the output buffer to be the IOCTL output buffer + the offset
// of the other output params which preceed the output data buffer
//
bddiGetDataFromHandleParams.pBuffer = pv + RequiredOutputSize; }
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiGetDataFromHandle( &(pBDLExtension->BdlExtenstion), &bddiGetDataFromHandleParams); if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetDataFromHandle: pfbddiCloseHandle failed with %lx\n", __DATE__, __TIME__, status)) goto Return; }
if (fCloseHandle) { RtlZeroMemory(&bddiCloseHandleParams, sizeof(bddiCloseHandleParams)); bddiCloseHandleParams.Size = sizeof(bddiCloseHandleParams);
bddiCloseHandleParams.hData = pBDDIItem->Data.Handle;
//
// Call the BDD to close the handle - don't check the return status because
// we really don't want to fail the operation if just closing the handle fails
//
pBDLExtension->pDriverExtension->bddiFunctions.pfbddiCloseHandle( &(pBDLExtension->BdlExtenstion), &bddiCloseHandleParams); } } if (fCloseHandle) { ExFreePoolWithTag(pBDDIItem, BDL_ULONG_TAG); } //
// Write the return info to the output buffer
//
pv = pBuffer;
*((ULONG *) pv) = bddiGetDataFromHandleParams.BIOReturnCode; pv += sizeof(ULONG); *((ULONG *) pv) = bddiGetDataFromHandleParams.cBuffer; //
// Set the number of bytes used
//
*pOutputBufferUsed = RequiredOutputSize;
if (bddiGetDataFromHandleParams.pBuffer != NULL) { *pOutputBufferUsed += bddiGetDataFromHandleParams.cBuffer; } Return:
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetDataFromHandle: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_RegisterNotify ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; BDDI_PARAMS_REGISTERNOTIFY bddiRegisterNotifyParams; PUCHAR pv = pBuffer; ULONG RequiredInputSize = 0; BDL_CONTROL *pBDLControl = NULL; KIRQL irql, OldIrql; PLIST_ENTRY pRegistrationListEntry = NULL; PLIST_ENTRY pControlChangeEntry = NULL; BDL_CONTROL_CHANGE_REGISTRATION *pControlChangeRegistration = NULL; BDL_IOCTL_CONTROL_CHANGE_ITEM *pControlChangeItem = NULL; BOOLEAN fLockAcquired = FALSE; BOOLEAN fRegistrationFound = FALSE; PLIST_ENTRY pTemp = NULL; PIRP pIrpToComplete = NULL; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_RegisterNotify: Enter\n", __DATE__, __TIME__)) //
// Make sure the input buffer is at least the minimum size (see BDDIOCTL
// spec for details)
//
RequiredInputSize = SIZEOF_REGISTERNOTIFY_INPUTBUFFER; if (InpuBufferLength < RequiredInputSize) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: Bad input buffer size\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Initialize the BDD struct
//
RtlZeroMemory(&bddiRegisterNotifyParams, sizeof(bddiRegisterNotifyParams)); bddiRegisterNotifyParams.Size = sizeof(bddiRegisterNotifyParams);
//
// Get the input parameters from the buffer
//
bddiRegisterNotifyParams.fRegister = *((ULONG *) pv) == 1; pv += sizeof(ULONG); bddiRegisterNotifyParams.ComponentId = *((ULONG *) pv); pv += sizeof(ULONG); bddiRegisterNotifyParams.ChannelId = *((ULONG *) pv); pv += sizeof(ULONG); bddiRegisterNotifyParams.ControlId = *((ULONG *) pv);
//
// Check control ID
//
if (BDLCheckControlId( pBDLExtension, bddiRegisterNotifyParams.ComponentId, bddiRegisterNotifyParams.ChannelId, bddiRegisterNotifyParams.ControlId, &pBDLControl) == FALSE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: Bad ControlId\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Make sure this is an async control
//
if (!(pBDLControl->Flags | BIO_CONTROL_FLAG_ASYNCHRONOUS)) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: trying to register for a non async control\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Note that we must raise the irql to dispatch level because we are synchronizing
// with a dispatch routine (BDLControlChangeDpc) that adds items to the queue at
// dispatch level
//
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), &irql); fLockAcquired = TRUE;
//
// Check to see if this notification registration exists (must exist for unregister, must not
// exist for register).
//
pRegistrationListEntry = pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList.Flink;
while (pRegistrationListEntry->Flink != pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList.Flink) { pControlChangeRegistration = CONTAINING_RECORD( pRegistrationListEntry, BDL_CONTROL_CHANGE_REGISTRATION, ListEntry);
if ((pControlChangeRegistration->ComponentId == bddiRegisterNotifyParams.ComponentId) && (pControlChangeRegistration->ChannelId == bddiRegisterNotifyParams.ChannelId) && (pControlChangeRegistration->ControlId == bddiRegisterNotifyParams.ControlId)) { fRegistrationFound = TRUE;
//
// The notification registration does exist, so if this is a register call then fail
//
if (bddiRegisterNotifyParams.fRegister == TRUE) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: trying to re-register\n", __DATE__, __TIME__)) status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Remove the notification registration from the list
//
RemoveEntryList(pRegistrationListEntry); ExFreePoolWithTag(pControlChangeRegistration, BDL_ULONG_TAG);
//
// Remove any pending notifications for the control which is being unregistered
//
pControlChangeEntry = pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue.Flink;
while (pControlChangeEntry->Flink != pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue.Flink) { pControlChangeItem = CONTAINING_RECORD( pControlChangeEntry, BDL_IOCTL_CONTROL_CHANGE_ITEM, ListEntry);
pTemp = pControlChangeEntry; pControlChangeEntry = pControlChangeEntry->Flink;
if ((pControlChangeItem->ComponentId == bddiRegisterNotifyParams.ComponentId) && (pControlChangeItem->ChannelId == bddiRegisterNotifyParams.ChannelId) && (pControlChangeItem->ControlId == bddiRegisterNotifyParams.ControlId)) { RemoveEntryList(pTemp); ExFreePoolWithTag(pControlChangeItem, BDL_ULONG_TAG); } }
//
// If the last notification registration just got removed, then complete
// the pending get notification IRP (if one exists) after releasing the lock.
//
if (IsListEmpty(&(pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList)) && (pBDLExtension->ControlChangeStruct.pIrp != NULL)) { pIrpToComplete = pBDLExtension->ControlChangeStruct.pIrp; pBDLExtension->ControlChangeStruct.pIrp = NULL; }
break; }
pRegistrationListEntry = pRegistrationListEntry->Flink; }
//
// If the registration was not found, and this is an unregister, return an error
//
if ((fRegistrationFound == FALSE) && (bddiRegisterNotifyParams.fRegister == FALSE)) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: trying to re-register\n", __DATE__, __TIME__))
status = STATUS_INVALID_PARAMETER; goto Return; }
//
// Add the notification to the list if this is a registration
//
if (bddiRegisterNotifyParams.fRegister == TRUE) { pControlChangeRegistration = ExAllocatePoolWithTag( PagedPool, sizeof(BDL_CONTROL_CHANGE_REGISTRATION), BDL_ULONG_TAG); if (pControlChangeRegistration == NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: ExAllocatePoolWithTag failed\n", __DATE__, __TIME__)) status = STATUS_NO_MEMORY; goto Return; }
pControlChangeRegistration->ComponentId = bddiRegisterNotifyParams.ComponentId; pControlChangeRegistration->ChannelId = bddiRegisterNotifyParams.ChannelId; pControlChangeRegistration->ControlId = bddiRegisterNotifyParams.ControlId; InsertHeadList( &(pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList), &(pControlChangeRegistration->ListEntry)); }
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql); fLockAcquired = FALSE;
if (pIrpToComplete != NULL) { pIrpToComplete->IoStatus.Information = 0; pIrpToComplete->IoStatus.Status = STATUS_NO_MORE_ENTRIES; IoCompleteRequest(pIrpToComplete, IO_NO_INCREMENT); }
//
// Call the BDD
//
status = pBDLExtension->pDriverExtension->bddiFunctions.pfbddiRegisterNotify( &(pBDLExtension->BdlExtenstion), &bddiRegisterNotifyParams);
if (status != STATUS_SUCCESS) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_RegisterNotify: pfbddiRegisterNotify failed with %lx\n", __DATE__, __TIME__, status))
//
// FIX FIX - if this fails and it is a register then we need to remove the
// registration from the list of registrations... since it was already added
// above.
//
ASSERT(0);
goto Return; }
//
// Set the number of bytes used
//
*pOutputBufferUsed = 0;
Return:
if (fLockAcquired == TRUE) { KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql); }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_RegisterNotify: Leave\n", __DATE__, __TIME__))
return (status); }
NTSTATUS BDLIOCTL_GetNotification ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension, IN ULONG InpuBufferLength, IN ULONG OutputBufferLength, IN PVOID pBuffer, IN PIRP pIrp, OUT ULONG *pOutputBufferUsed ) { NTSTATUS status = STATUS_SUCCESS; ULONG RequiredOutputSize = 0; PUCHAR pv = pBuffer; KIRQL irql, OldIrql; PLIST_ENTRY pListEntry = NULL; BDL_IOCTL_CONTROL_CHANGE_ITEM *pControlChangeItem = NULL; BOOLEAN fLockAcquired = FALSE; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetNotification: Enter\n", __DATE__, __TIME__)) //
// Make sure there is enough space for the return buffer
//
RequiredOutputSize = SIZEOF_GETNOTIFICATION_OUTPUTBUFFER;
if (RequiredOutputSize > OutputBufferLength) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetNotification: Output buffer is too small\n", __DATE__, __TIME__))
status = STATUS_BUFFER_TOO_SMALL; goto Return; }
//
// Lock the notification queue and see if there are any outstanding notifications.
// Note that we must raise the irql to dispatch level because we are synchronizing
// with a DPC routine (BDLControlChangeDpc) that adds items to the queue at
// dispatch level
//
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), &irql); fLockAcquired = TRUE;
//
// If there is already an IRP posted then that is a bug in the BSP
//
if (pBDLExtension->ControlChangeStruct.pIrp != NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetNotification: Output buffer is too small\n", __DATE__, __TIME__))
status = STATUS_INVALID_DEVICE_STATE; goto Return; }
if (IsListEmpty(&(pBDLExtension->ControlChangeStruct.ControlChangeRegistrationList))) { //
// There are no change notifications registered, so complete the IRP with the
// special status that indicates that
//
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetNotification: ControlChangeRegistrationList empty\n", __DATE__, __TIME__))
status = STATUS_NO_MORE_ENTRIES; goto Return; } else if (IsListEmpty(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue))) { //
// There are currently no control changes in the list, so just save this Irp
// and return STATUS_PENDING
//
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetNotification: ControlChanges empty\n", __DATE__, __TIME__))
//
// Set up the cancel routine for this IRP
//
if (IoSetCancelRoutine(pIrp, BDLRegisteredCancelGetNotificationIRP) != NULL) { BDLDebug( BDL_DEBUG_ERROR, ("%s %s: BDL!BDLIOCTL_GetNotification: pCancel was not NULL\n", __DATE__, __TIME__)) }
pBDLExtension->ControlChangeStruct.pIrp = pIrp; status = STATUS_PENDING; goto Return; } else { //
// Grab the first control change item in the queue
//
pListEntry = RemoveHeadList(&(pBDLExtension->ControlChangeStruct.IOCTLControlChangeQueue)); pControlChangeItem = CONTAINING_RECORD(pListEntry, BDL_IOCTL_CONTROL_CHANGE_ITEM, ListEntry); }
KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql); fLockAcquired = FALSE;
//
// We are here because there is currently a control change to report, so write the return
// info to the output buffer
//
pv = pBuffer;
*((ULONG *) pv) = pControlChangeItem->ComponentId; pv += sizeof(ULONG); *((ULONG *) pv) = pControlChangeItem->ChannelId; pv += sizeof(ULONG); *((ULONG *) pv) = pControlChangeItem->ControlId; pv += sizeof(ULONG); *((ULONG *) pv) = pControlChangeItem->Value;
//
// Free up the change item
//
ExFreePoolWithTag(pControlChangeItem, BDL_ULONG_TAG); //
// Set the number of bytes used
//
*pOutputBufferUsed = RequiredOutputSize;
Return:
if (fLockAcquired) { KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql); }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLIOCTL_GetNotification: Leave\n", __DATE__, __TIME__))
return (status); }
VOID BDLCancelGetNotificationIRP ( IN PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension ) { PIRP pIrpToCancel = NULL; KIRQL irql, OldIrql; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCancelGetNotificationIRP: Enter\n", __DATE__, __TIME__))
//
// Remove the GetNotification IRP from the the ControlChangeStruct.
// Need to make sure the IRP is still there, since theoretically we
// could be trying to complete it at the same time it is cancelled.
//
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KeAcquireSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), &irql); if (pBDLExtension->ControlChangeStruct.pIrp != NULL) { pIrpToCancel = pBDLExtension->ControlChangeStruct.pIrp; pBDLExtension->ControlChangeStruct.pIrp = NULL; } KeReleaseSpinLock(&(pBDLExtension->ControlChangeStruct.ControlChangeLock), irql); KeLowerIrql(OldIrql);
//
// Complete the GetNotification IRP as cancelled
//
if (pIrpToCancel != NULL) { pIrpToCancel->IoStatus.Information = 0; pIrpToCancel->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(pIrpToCancel, IO_NO_INCREMENT); }
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLCancelGetNotificationIRP: Leave\n", __DATE__, __TIME__)) }
NTSTATUS BDLRegisteredCancelGetNotificationIRP ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) { PBDL_INTERNAL_DEVICE_EXTENSION pBDLExtension = pDeviceObject->DeviceExtension; BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLRegisteredCancelGetNotificationIRP: Enter\n", __DATE__, __TIME__))
ASSERT(pIrp == pBDLExtension->ControlChangeStruct.pIrp);
//
// Since this function is called already holding the CancelSpinLock
// we need to release it
//
IoReleaseCancelSpinLock(pIrp->CancelIrql);
//
// Cancel the IRP
//
BDLCancelGetNotificationIRP(pBDLExtension);
BDLDebug( BDL_DEBUG_TRACE, ("%s %s: BDL!BDLRegisteredCancelGetNotificationIRP: Leave\n", __DATE__, __TIME__))
return (STATUS_CANCELLED); }
|