Copyright © 2003 by Printing Communications Assoc., Inc. (PCAUSA). All rights reserved
These are kernel-mode functions and structures associated with making a NdisRequest to query information on an open Win32 PassThru adapter handle.
The NDIS_REQUEST_EX structure is a container structure that encapsulates a NDIS_REQUEST structure and additional fields that provide a second level of indirection for request completion processing.
The key additional fields that are contained in the NDIS_REQUEST_EX structure are:
typedef struct _NDIS_REQUEST_EX NDIS_REQUEST_EX, *PNDIS_REQUEST_EX;
typedef VOID (*LOCAL_REQUEST_COMPLETE_HANDLER)( IN PADAPT pAdapt, IN PNDIS_REQUEST_EX pLocalRequest, IN NDIS_STATUS Status );
typedef
struct _NDIS_REQUEST_EX
{
NDIS_REQUEST Request;
LOCAL_REQUEST_COMPLETE_HANDLER RequestCompleteHandler;
PVOID RequestContext;
NDIS_STATUS RequestStatus;
NDIS_EVENT RequestEvent;
}
NDIS_REQUEST_EX, *PNDIS_REQUEST_EX;
We modify the OPEN_CONTEXT structure to add a NDIS_REQUEST_EX member variable. We also modify the DevAllocateOpenContext function to initialize the LocalRequest variable (specifically, to initialize the RequestEvent variable).
typedef
struct _OPEN_CONTEXT
{
ULONG RefCount;
NDIS_SPIN_LOCK Lock;
BOOLEAN bAdapterClosed;
PADAPT pAdapt;
NDIS_REQUEST_EX LocalRequest; } OPEN_CONTEXT, *POPEN_CONTEXT;
Here we make a simple test on the NdisRequest pointer. If the request is initiated from the miniport pass-through, then the original baseline request completion code is executed. If the request did not originate from the miniport, then the NDIS_REQUEST_EX structure contains a pointer to a second-level completion function that will be called to complete the request.
VOID
PtRequestComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status
)
{
PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
NDIS_OID Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid;
// BEGIN_PTUSERIO
//
// Handle Local NDIS Requests
// --------------------------
// Here we handle NDIS requests that do not originate from the miniport.
//
// Typically, these are requests that were initiated from user-mode but
// could also be requests initiated autonomously by the NDIS IM driver.
//
if( NdisRequest != &(pAdapt->Request) )
{
PNDIS_REQUEST_EX pLocalRequest = (PNDIS_REQUEST_EX )NdisRequest;
(*pLocalRequest->RequestCompleteHandler )( pAdapt, pLocalRequest, Status );
return; } // END_PTUSERIO
//
// Since our request is not outstanding anymore
//
ASSERT(pAdapt->OutstandingRequests == TRUE);
...
}
The DevIoControl dispatcher calls the DevQueryinformation function to do the work related to making a NdisRequest to query information on a PassThru adapter handle.
NTSTATUS
DevQueryInformation(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp,
IN BOOLEAN bUseVirtualName
)
{
PIO_STACK_LOCATION pIrpSp;
NTSTATUS NtStatus = STATUS_SUCCESS;
ULONG BytesReturned = 0;
PUCHAR ioBuffer = NULL;
ULONG inputBufferLength;
ULONG outputBufferLength;
NDIS_OID Oid;
PADAPT pAdapt;
POPEN_CONTEXT pOpenContext;
PNDIS_REQUEST_EX pLocalRequest;
NDIS_STATUS NdisStatus;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
ioBuffer = pIrp->AssociatedIrp.SystemBuffer; inputBufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength; outputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
pOpenContext = pIrpSp->FileObject->FsContext;
if( !pOpenContext )
{
NtStatus = STATUS_INVALID_HANDLE;
goto CompleteTheIRP;
}
pAdapt = pOpenContext->pAdapt;
if( !pAdapt )
{
NtStatus = STATUS_INVALID_HANDLE;
goto CompleteTheIRP;
}
//
// Sanity Check On Input Buffer/OID
//
if( inputBufferLength != sizeof( NDIS_OID ) )
{
NtStatus = STATUS_INVALID_PARAMETER;
goto CompleteTheIRP;
}
Oid = *(PNDIS_OID )ioBuffer;
// // Fail Open If Unbind Is In Progress // NdisAcquireSpinLock(&pAdapt->Lock);
if( pAdapt->UnbindingInProcess )
{
NdisReleaseSpinLock(&pAdapt->Lock);
NtStatus = STATUS_INVALID_DEVICE_STATE;
goto CompleteTheIRP;
}
//
// All other queries are failed, if the miniport is not at D0,
//
if (pAdapt->MPDeviceState > NdisDeviceStateD0)
{
NdisReleaseSpinLock(&pAdapt->Lock);
NtStatus = STATUS_INVALID_DEVICE_STATE;
goto CompleteTheIRP;
}
//
// This is in the process of powering down the system, always fail the request
//
if (pAdapt->StandingBy == TRUE)
{
NdisReleaseSpinLock(&pAdapt->Lock);
NtStatus = STATUS_INVALID_DEVICE_STATE;
goto CompleteTheIRP;
}
NdisReleaseSpinLock(&pAdapt->Lock);
// // Now (Finally) Make The NDIS Request... //
// // May need to add ref counts to adapt and open context. Also, bump // a counter of outstanding requests... //
DevRefOpenContext( pOpenContext );
pLocalRequest = &pOpenContext->LocalRequest;
pLocalRequest->Request.RequestType = NdisRequestQueryInformation; pLocalRequest->Request.DATA.QUERY_INFORMATION.Oid = Oid; pLocalRequest->Request.DATA.QUERY_INFORMATION.InformationBuffer = ioBuffer; pLocalRequest->Request.DATA.QUERY_INFORMATION.InformationBufferLength = outputBufferLength; pLocalRequest->Request.DATA.QUERY_INFORMATION.BytesNeeded = 0; pLocalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten = 0;
pLocalRequest->RequestCompleteHandler = DevRequestComplete; pLocalRequest->RequestContext = pOpenContext;
NdisResetEvent( &pLocalRequest->RequestEvent );
NdisRequest(
&NdisStatus,
pAdapt->BindingHandle,
(PNDIS_REQUEST )pLocalRequest
);
if( NdisStatus != NDIS_STATUS_PENDING )
{
DevRequestComplete( pAdapt, pLocalRequest, NdisStatus );
}
NdisWaitEvent( &pLocalRequest->RequestEvent, 0 );
NdisStatus = pLocalRequest->RequestStatus;
if( NdisStatus == NDIS_STATUS_SUCCESS )
{
BytesReturned = pLocalRequest->Request.DATA.QUERY_INFORMATION.BytesWritten;
if( BytesReturned > outputBufferLength )
{
BytesReturned = outputBufferLength;
}
NtStatus = STATUS_SUCCESS;
}
else
{
NDIS_STATUS_TO_NT_STATUS( NdisStatus, &NtStatus);
}
DevDerefOpenContext( pOpenContext );
// // Complete The IRP // CompleteTheIRP:
pIrp->IoStatus.Information = BytesReturned; pIrp->IoStatus.Status = NtStatus; IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return NtStatus; }
In DevIoControl we add a call to dispatch IOCTL_PTUSERIO_QUERY_INFORMATION (defined in IOCommon.h) to the DevQueryInformation handler
NTSTATUS
DevIoControl(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
{
PIO_STACK_LOCATION pIrpSp;
NTSTATUS NtStatus = STATUS_SUCCESS;
ULONG BytesReturned = 0;
ULONG FunctionCode;
PUCHAR ioBuffer = NULL;
ULONG inputBufferLength;
ULONG outputBufferLength;
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
ioBuffer = pIrp->AssociatedIrp.SystemBuffer;
inputBufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
FunctionCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
switch (FunctionCode)
{
case IOCTL_PTUSERIO_ENUMERATE:
return( DevEnumerateBindings(
pDeviceObject,
pIrp
)
);
case IOCTL_PTUSERIO_OPEN_ADAPTER:
return( DevOpenAdapter(
pDeviceObject,
pIrp,
FALSE // Is Lower Adapter
)
);
case IOCTL_PTUSERIO_QUERY_INFORMATION:
return( DevQueryInformation(
pDeviceObject,
pIrp,
FALSE // Is Lower Adapter
)
);
case IOCTL_PTUSERIO_SET_INFORMATION:
default:
NtStatus = STATUS_NOT_SUPPORTED;
break;
}
if (NtStatus != STATUS_PENDING)
{
pIrp->IoStatus.Information = BytesReturned;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
return NtStatus;
}
This is the second-level NdisRequest completion handler called from PtRequestComplete for completion of non-local requests.
VOID
DevRequestComplete(
IN PADAPT pAdapt,
IN PNDIS_REQUEST_EX pLocalRequest,
IN NDIS_STATUS Status
)
{
POPEN_CONTEXT pOpenContext;
DBGPRINT(("<== Pt DevRequestComplete\n"));
pOpenContext = (POPEN_CONTEXT )pLocalRequest->RequestContext;
pLocalRequest->RequestStatus = Status;
NdisSetEvent( &pLocalRequest->RequestEvent );
DBGPRINT(("<== Pt DevRequestComplete\n"));
}