Kernel-Mode
NDIS Query Code Fragments

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.

New Code: PTExtend.h Module, NDIS_REQUEST_EX Structure

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;

 

Modified Code: PTExtend.h Module, OPEN_CONTEXT Structure

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;

 

Modified Code: Protocol.c Module, PtRequestComplete Function

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

 

New Code: PTExtend.c Module, DevQueryInformation Function

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

 

Modified Code: PTExtend.c Module, DevIoControl Function

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

 

New Code: PTExtend.c Module, DevRequestComplete Function

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