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")); }