Ejemplo n.º 1
0
VOID
NdisprotCancelRead(
    IN PDEVICE_OBJECT               pDeviceObject,
    IN PIRP                         pIrp
    )
/*++

Routine Description:

    Cancel a pending read IRP. We unlink the IRP from the open context
    queue and complete it.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - IRP to be cancelled

Return Value:

    None

--*/
{
    PNDISPROT_OPEN_CONTEXT       pOpenContext;

    UNREFERENCED_PARAMETER(pDeviceObject);

    IoReleaseCancelSpinLock(pIrp->CancelIrql);

    pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
    NPROT_STRUCT_ASSERT(pOpenContext, oc);

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

    NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
    pOpenContext->PendedReadCount--;


    NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

    DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %p\n", pOpenContext, pIrp));
    pIrp->IoStatus.Status = STATUS_CANCELLED;
    pIrp->IoStatus.Information = 0;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    NPROT_DEREF_OPEN(pOpenContext); // Cancel removed pended Read

}
Ejemplo n.º 2
0
VOID
NdisProtSendComplete(
    IN NDIS_HANDLE                  ProtocolBindingContext,
    IN PNDIS_PACKET                 pNdisPacket,
    IN NDIS_STATUS                  Status
)
/*++

Routine Description:

    NDIS entry point called to signify completion of a packet send.
    We pick up and complete the Write IRP corresponding to this packet.

    NDIS 5.1:

Arguments:

    ProtocolBindingContext - pointer to open context
    pNdisPacket - packet that completed send
    Status - status of send

Return Value:

    None

--*/
{
    PIRP                        pIrp;
    PIO_STACK_LOCATION          pIrpSp;
    PNDISPROT_OPEN_CONTEXT       pOpenContext;

    pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
    NPROT_STRUCT_ASSERT(pOpenContext, oc);

    pIrp = NPROT_IRP_FROM_SEND_PKT(pNdisPacket);

    if (pOpenContext->bRunningOnWin9x)
    {
        //
        //  We would have attached our own NDIS_BUFFER. Take it out
        //  and free it.
        //
#ifndef NDIS51
        PNDIS_BUFFER                pNdisBuffer;
        PVOID                       VirtualAddr;
        UINT                        BufferLength;
        UINT                        TotalLength;
#endif

#ifdef NDIS51
        NPROT_ASSERT(FALSE); // NDIS 5.1 not on Win9X!
#else
        NdisGetFirstBufferFromPacket(
            pNdisPacket,
            &pNdisBuffer,
            &VirtualAddr,
            &BufferLength,
            &TotalLength);

        NPROT_ASSERT(pNdisBuffer != NULL);
        NdisFreeBuffer(pNdisBuffer);
#endif
    }


#ifdef NDIS51
    IoSetCancelRoutine(pIrp, NULL);

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

    NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);

    NPROT_RELEASE_LOCK(&pOpenContext->Lock);
#endif

    //
    //  We are done with the NDIS_PACKET:
    //
    NPROT_DEREF_SEND_PKT(pNdisPacket);

    //
    //  Complete the Write IRP with the right status.
    //
    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    if (Status == NDIS_STATUS_SUCCESS)
    {
        pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length;
        pIrp->IoStatus.Status = STATUS_SUCCESS;
    }
    else
    {
        pIrp->IoStatus.Information = 0;
        pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
    }

    DEBUGP(DL_INFO, ("SendComplete: packet %p/IRP %p/Length %d "
                     "completed with status %x\n",
                     pNdisPacket, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status));

    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    NdisInterlockedDecrement((PLONG)&pOpenContext->PendedSendCount);

    NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP
}
Ejemplo n.º 3
0
NTSTATUS
NdisProtWrite(
    IN PDEVICE_OBJECT       pDeviceObject,
    IN PIRP                 pIrp
)
/*++

Routine Description:

    Dispatch routine to handle IRP_MJ_WRITE.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - Pointer to request packet

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION      pIrpSp;
    ULONG                   DataLength;
    NTSTATUS                NtStatus;
    NDIS_STATUS             Status;
    PNDISPROT_OPEN_CONTEXT   pOpenContext;
    PNDIS_PACKET            pNdisPacket;
    PNDIS_BUFFER            pNdisBuffer;
    NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
#ifdef NDIS51
    PVOID                   CancelId;
#endif

    UNREFERENCED_PARAMETER(pDeviceObject);

    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;

    pNdisPacket = NULL;

    do
    {
        if (pOpenContext == NULL)
        {
            DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
                             pIrpSp->FileObject));
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        if (pIrp->MdlAddress == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }
        //
        // Try to get a virtual address for the MDL.
        //

        pEthHeader = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);

        if (pEthHeader == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
                              " IRP %p, MDL %p\n",
                              pIrp, pIrp->MdlAddress));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Sanity-check the length.
        //
        DataLength = MmGetMdlByteCount(pIrp->MdlAddress);
        if (DataLength < sizeof(NDISPROT_ETH_HEADER))
        {
            DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
                             DataLength));
            NtStatus = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER)))
        {
            DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
                             " larger than max frame size (%d)\n",
                             pOpenContext, DataLength, pOpenContext->MaxFrameSize));

            NtStatus = STATUS_INVALID_BUFFER_SIZE;
            break;
        }

        //
        // To prevent applications from sending packets with spoofed
        // mac address, we will do the following check to make sure the source
        // address in the packet is same as the current MAC address of the NIC.
        //
        if ((pIrp->RequestorMode == UserMode) &&
                !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
        {
            DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

            DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
                              " or in low power state\n", pOpenContext));

            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        //
        //  Allocate a send packet.
        //
        NPROT_ASSERT(pOpenContext->SendPacketPool != NULL);
        NdisAllocatePacket(
            &Status,
            &pNdisPacket,
            pOpenContext->SendPacketPool);

        if (Status != NDIS_STATUS_SUCCESS)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

            DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send pkt\n",
                              pOpenContext));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        //  Allocate a send buffer if necessary.
        //
        if (pOpenContext->bRunningOnWin9x)
        {
            NdisAllocateBuffer(
                &Status,
                &pNdisBuffer,
                pOpenContext->SendBufferPool,
                pEthHeader,
                DataLength);

            if (Status != NDIS_STATUS_SUCCESS)
            {
                NPROT_RELEASE_LOCK(&pOpenContext->Lock);

                NdisFreePacket(pNdisPacket);

                DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send buf\n",
                                  pOpenContext));
                NtStatus = STATUS_INSUFFICIENT_RESOURCES;
                break;
            }
        }
        else
        {
            pNdisBuffer = pIrp->MdlAddress;
        }

        NdisInterlockedIncrement((PLONG)&pOpenContext->PendedSendCount);

        NPROT_REF_OPEN(pOpenContext);  // pended send

        IoMarkIrpPending(pIrp);

        //
        //  Initialize the packet ref count. This packet will be freed
        //  when this count goes to zero.
        //
        NPROT_SEND_PKT_RSVD(pNdisPacket)->RefCount = 1;

#ifdef NDIS51

        //
        //  NDIS 5.1 supports cancelling sends. We set up a cancel ID on
        //  each send packet (which maps to a Write IRP), and save the
        //  packet pointer in the IRP. If the IRP gets cancelled, we use
        //  NdisCancelSendPackets() to cancel the packet.
        //

        CancelId = NPROT_GET_NEXT_CANCEL_ID();
        NDIS_SET_PACKET_CANCEL_ID(pNdisPacket, CancelId);
        pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
        pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNdisPacket;

        NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);

        IoSetCancelRoutine(pIrp, NdisProtCancelWrite);

#endif // NDIS51

        NPROT_RELEASE_LOCK(&pOpenContext->Lock);

        //
        //  Set a back pointer from the packet to the IRP.
        //
        NPROT_IRP_FROM_SEND_PKT(pNdisPacket) = pIrp;

        NtStatus = STATUS_PENDING;

        pNdisBuffer->Next = NULL;
        NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);

#if SEND_DBG
        {
            PUCHAR      pData;

            pData = MmGetSystemAddressForMdlSafe(pNdisBuffer, NormalPagePriority);
            NPROT_ASSERT(pEthHeader == pData);

            DEBUGP(DL_VERY_LOUD,
                   ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
                    pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));

            DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
        }
#endif // SEND_DBG

        NdisSendPackets(pOpenContext->BindingHandle, &pNdisPacket, 1);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        pIrp->IoStatus.Status = NtStatus;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    }

    return (NtStatus);
}
Ejemplo n.º 4
0
VOID
NdisProtCancelWrite(
    IN PDEVICE_OBJECT               pDeviceObject,
    IN PIRP                         pIrp
)
/*++

Routine Description:

    Cancel a pending write IRP. This routine attempt to cancel the NDIS send.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - IRP to be cancelled

Return Value:

    None

--*/
{
    PNDISPROT_OPEN_CONTEXT       pOpenContext;
    PLIST_ENTRY                 pIrpEntry;
    PNDIS_PACKET                pNdisPacket;

    UNREFERENCED_PARAMETER(pDeviceObject);

    IoReleaseCancelSpinLock(pIrp->CancelIrql);

    //
    //  The NDIS packet representing this Write IRP.
    //
    pNdisPacket = NULL;

    pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
    NPROT_STRUCT_ASSERT(pOpenContext, oc);

    //
    //  Try to locate the IRP in the pended write queue. The send completion
    //  routine may be running and might have removed it from there.
    //
    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

    for (pIrpEntry = pOpenContext->PendedWrites.Flink;
            pIrpEntry != &pOpenContext->PendedWrites;
            pIrpEntry = pIrpEntry->Flink)
    {
        if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
        {
            pNdisPacket = (PNDIS_PACKET) pIrp->Tail.Overlay.DriverContext[1];

            //
            //  Place a reference on this packet so that it won't get
            //  freed/reused until we are done with it.
            //
            NPROT_REF_SEND_PKT(pNdisPacket);
            break;
        }
    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock);

    if (pNdisPacket != NULL)
    {
        //
        //  Either the send completion routine hasn't run, or we got a peak
        //  at the IRP/packet before it had a chance to take it out of the
        //  pending IRP queue.
        //
        //  We do not complete the IRP here - note that we didn't dequeue it
        //  above. This is because we always want the send complete routine to
        //  complete the IRP. And this in turn is because the packet that was
        //  prepared from the IRP has a buffer chain pointing to data associated
        //  with this IRP. Therefore we cannot complete the IRP before the driver
        //  below us is done with the data it pointed to.
        //

        //
        //  Request NDIS to cancel this send. The result of this call is that
        //  our SendComplete handler will be called (if not already called).
        //
        DEBUGP(DL_INFO, ("CancelWrite: cancelling pkt %p on Open %p\n",
                         pNdisPacket, pOpenContext));
        NdisCancelSendPackets(
            pOpenContext->BindingHandle,
            NDIS_GET_PACKET_CANCEL_ID(pNdisPacket)
        );

        //
        //  It is now safe to remove the reference we had placed on the packet.
        //
        NPROT_DEREF_SEND_PKT(pNdisPacket);
    }
    //
    //  else the send completion routine has already picked up this IRP.
    //
}
Ejemplo n.º 5
0
VOID
ndisprotQueueReceiveNetBufferList(
    IN PNDISPROT_OPEN_CONTEXT        pOpenContext,
    IN PNET_BUFFER_LIST              pRcvNetBufList,
    IN BOOLEAN                       DispatchLevel
    )
/*++

Routine Description:

    Queue up a received net buffer list on the open context structure.
    If the queue size goes beyond a water mark, discard a Net Buffer list
    at the head of the queue.

    Finally, run the queue service routine.

Arguments:

    pOpenContext - pointer to open context
    pRcvPacket - the received packet
    DipatchLevel - the irql level

Return Value:

    None

--*/
{
    PLIST_ENTRY        pEnt;
    PLIST_ENTRY        pDiscardEnt;
    PNET_BUFFER_LIST   pDiscardNetBufList;

    do
    {

        NPROT_REF_OPEN(pOpenContext);    // queued rcv net buffer list

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);

        if ((pOpenContext->State == NdisprotPaused)
            || (pOpenContext->State == NdisprotPausing))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);

            ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, DispatchLevel);
            break;
        }

        //
        //  Check if the binding is in the proper state to receive
        //  this net buffer list.
        //
        if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE) &&
            (pOpenContext->PowerState == NetDeviceStateD0))
        {

            //
            // Queue the net buffer list
            //
            pEnt = NPROT_RCV_NBL_TO_LIST_ENTRY(pRcvNetBufList);
            NPROT_INSERT_TAIL_LIST(&pOpenContext->RecvNetBufListQueue, pEnt);
            NPROT_RCV_NBL_FROM_LIST_ENTRY(pEnt) = pRcvNetBufList;
            pOpenContext->RecvNetBufListCount++;

            DEBUGP(DL_VERY_LOUD, ("QueueReceiveNetBufferList: open %p,"
                    " queued nbl %p, queue size %d\n",
                    pOpenContext, pRcvNetBufList, pOpenContext->RecvNetBufListCount));

        }
        else
        {
            //
            //  Received this net buffer list when the binding is going away.
            //  Drop this.
            //
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);

            ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList, DispatchLevel);

            NPROT_DEREF_OPEN(pOpenContext);  // dropped rcv packet - bad state
            break;
        }


        //
        //  Trim the queue if it has grown too big.
        //
        if (pOpenContext->RecvNetBufListCount > MAX_RECV_QUEUE_SIZE)
        {
            //
            //  Remove the head of the queue.
            //
            pDiscardEnt = pOpenContext->RecvNetBufListQueue.Flink;
            NPROT_REMOVE_ENTRY_LIST(pDiscardEnt);

            pOpenContext->RecvNetBufListCount --;

            NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);

            pDiscardNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pDiscardEnt);

            NPROT_RCV_NBL_FROM_LIST_ENTRY(pDiscardEnt) = NULL;

            ndisprotFreeReceiveNetBufferList(pOpenContext, pDiscardNetBufList, DispatchLevel);

            NPROT_DEREF_OPEN(pOpenContext);  // dropped rcv packet - queue too long

            DEBUGP(DL_INFO, ("QueueReceiveNetBufferList: open %p queue"
                    " too long, discarded  %p\n",
                    pOpenContext, pDiscardNetBufList));
        }
        else
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
        }

        //
        //  Run the receive queue service routine now.
        //
        ndisprotServiceReads(pOpenContext);
    }
    while (FALSE);
}
Ejemplo n.º 6
0
NTSTATUS
NdisprotRead(
    IN PDEVICE_OBJECT       pDeviceObject,
    IN PIRP                 pIrp
    )
/*++

Routine Description:

    Dispatch routine to handle IRP_MJ_READ.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - Pointer to request packet

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION      pIrpSp;
    NTSTATUS                NtStatus;
    PNDISPROT_OPEN_CONTEXT   pOpenContext;

    UNREFERENCED_PARAMETER(pDeviceObject);

    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;

    do
    {
        //
        // Validate!
        //
        if (pOpenContext == NULL)
        {
            DEBUGP(DL_FATAL, ("Read: NULL FsContext on FileObject %p\n",
                        pIrpSp->FileObject));
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        if (pIrp->MdlAddress == NULL)
        {
            DEBUGP(DL_FATAL, ("Read: NULL MDL address on IRP %p\n", pIrp));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        // Try to get a virtual address for the MDL.
        //
        if (MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority) == NULL)
        {
            DEBUGP(DL_FATAL, ("Read: MmGetSystemAddr failed for IRP %p, MDL %p\n",
                    pIrp, pIrp->MdlAddress));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        IoSetCancelRoutine(pIrp, NdisprotCancelRead);

        if (pIrp->Cancel &&
            IoSetCancelRoutine(pIrp, NULL))
        {

            //
            // IRP has been canceled but the I/O manager did not manage to call our cancel routine. This
            // code is safe referencing the Irp->Cancel field without locks because of the memory barriers
            // in the interlocked exchange sequences used by IoSetCancelRoutine.
            //

            NtStatus = STATUS_CANCELLED;

            // IRP should be completed after releasing the lock

        }
        else
        {

            //
            //  Add this IRP to the list of pended Read IRPs
            //
            NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry);
            pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;

            NPROT_REF_OPEN(pOpenContext);  // pended read IRP
            pOpenContext->PendedReadCount++;
            IoMarkIrpPending(pIrp);


            NtStatus = STATUS_PENDING;
        }

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
        //
        //  Run the service routine for reads.
        //
        ndisprotServiceReads(pOpenContext);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        NPROT_ASSERT(NtStatus != STATUS_SUCCESS);
        pIrp->IoStatus.Information = 0;
        pIrp->IoStatus.Status = NtStatus;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    }

    return (NtStatus);
}
Ejemplo n.º 7
0
VOID
ndisprotServiceReads(
    IN PNDISPROT_OPEN_CONTEXT        pOpenContext
    )
/*++

Routine Description:

    Utility routine to copy received data into user buffers and
    complete READ IRPs.

Arguments:

    pOpenContext - pointer to open context

Return Value:

    None

--*/
{
    PIRP                pIrp = NULL;
    PLIST_ENTRY         pIrpEntry;
    PNET_BUFFER_LIST    pRcvNetBufList;
    PLIST_ENTRY         pRcvNetBufListEntry;
    PUCHAR              pSrc, pDst;
    ULONG               BytesRemaining; // at pDst
    PMDL                pMdl;
    ULONG               BytesAvailable;
    BOOLEAN             FoundPendingIrp = FALSE;
    ULONG               SrcTotalLength = 0; // Source NetBuffer DataLenght
    ULONG               Offset = 0;         // CurrentMdlOffset
    ULONG               BytesToCopy = 0;

    DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
            pOpenContext, pOpenContext->Flags));

    NPROT_REF_OPEN(pOpenContext);  // temp ref - service reads

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

    while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
           !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvNetBufListQueue))
    {
        FoundPendingIrp = FALSE;

        //
        //  Get the first pended Read IRP
        //
        pIrpEntry = pOpenContext->PendedReads.Flink;
        while (pIrpEntry != &pOpenContext->PendedReads)
        {
            pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);

            //
            //  Check to see if it is being cancelled.
            //
            if (IoSetCancelRoutine(pIrp, NULL))
            {
                //
                //  It isn't being cancelled, and can't be cancelled henceforth.
                //
                NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
                FoundPendingIrp = TRUE;
                break;

                //
                //  NOTE: we decrement PendedReadCount way below in the
                //  while loop, to avoid letting through a thread trying
                //  to unbind.
                //
            }
            else
            {
                //
                //  The IRP is being cancelled; let the cancel routine handle it.
                //
                DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
                        pOpenContext, pIrp));

                pIrpEntry = pIrpEntry->Flink;
            }
        }

        if (FoundPendingIrp == FALSE)
        {
            break;
        }
        //
        //  Get the first queued receive packet
        //
        pRcvNetBufListEntry = pOpenContext->RecvNetBufListQueue.Flink;
        NPROT_REMOVE_ENTRY_LIST(pRcvNetBufListEntry);

        pOpenContext->RecvNetBufListCount --;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        NPROT_DEREF_OPEN(pOpenContext);  // Service: dequeue rcv packet

        pRcvNetBufList = NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry);
        NPROT_ASSERT(pRcvNetBufList != NULL);
        _Analysis_assume_(pRcvNetBufList != NULL);
        NPROT_RCV_NBL_FROM_LIST_ENTRY(pRcvNetBufListEntry) = NULL;

        //
        //  Copy as much data as possible from the receive packet to
        //  the IRP MDL.
        //
        
        pDst = NULL;
        NdisQueryMdl(pIrp->MdlAddress, &pDst, &BytesRemaining, NormalPagePriority);
        NPROT_ASSERT(pDst != NULL);  // since it was already mapped
        _Analysis_assume_(pDst != NULL);

        pMdl = NET_BUFFER_CURRENT_MDL(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        //
        // Copy the data in the received packet into the buffer provided by the client.
        // If the length of the receive packet is greater than length of the given buffer,
        // we just copy as many bytes as we can. Once the buffer is full, we just discard
        // the rest of the data, and complete the IRP sucessfully even we only did a partial copy.
        //

        SrcTotalLength = NET_BUFFER_DATA_LENGTH(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));
        Offset = NET_BUFFER_CURRENT_MDL_OFFSET(NET_BUFFER_LIST_FIRST_NB(pRcvNetBufList));

        while (BytesRemaining && (pMdl != NULL) && SrcTotalLength)
        {
            pSrc = NULL;
            NdisQueryMdl(pMdl, &pSrc, &BytesAvailable, NormalPagePriority);

            if (pSrc == NULL)
            {
                DEBUGP(DL_FATAL,
                    ("ServiceReads: Open %p, NdisQueryMdl failed for MDL %p\n",
                            pOpenContext, pMdl));
                break;
            }

            NPROT_ASSERT(BytesAvailable > Offset);

            BytesToCopy = MIN(BytesAvailable - Offset, BytesRemaining);
            BytesToCopy = MIN(BytesToCopy, SrcTotalLength);

            NPROT_COPY_MEM(pDst, pSrc + Offset, BytesToCopy);
            BytesRemaining -= BytesToCopy;
            pDst += BytesToCopy;
            SrcTotalLength -= BytesToCopy;

            //
            // CurrentMdlOffset is used only for the first Mdl processed. For the remaining Mdls, it is 0.
            //
            Offset = 0;

            NdisGetNextMdl(pMdl, &pMdl);
        }

        //
        //  Complete the IRP.
        //
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;

        DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
            pOpenContext, pIrp, (ULONG)pIrp->IoStatus.Information));

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        ndisprotFreeReceiveNetBufferList(pOpenContext, pRcvNetBufList,FALSE);


        NPROT_DEREF_OPEN(pOpenContext);    // took out pended Read

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);
        pOpenContext->PendedReadCount--;

    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

    NPROT_DEREF_OPEN(pOpenContext);    // temp ref - service reads
}
Ejemplo n.º 8
0
VOID
NdisprotCancelWrite(
    IN PDEVICE_OBJECT               pDeviceObject,
    IN PIRP                         pIrp
    )
/*++

Routine Description:

    Cancel a pending write IRP. This routine attempt to cancel the NDIS send.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - IRP to be cancelled

Return Value:

    None

--*/
{
    PNDISPROT_OPEN_CONTEXT       pOpenContext;
    PLIST_ENTRY                  pIrpEntry;
    BOOLEAN                      FoundIrp = FALSE;

    UNREFERENCED_PARAMETER(pDeviceObject);
        
    pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
    if (pOpenContext == NULL)
    {
        //
        // The IRP is going to be completed from send complete function
        //
        IoReleaseCancelSpinLock(pIrp->CancelIrql);
        return;
    }
   
    NPROT_REF_OPEN(pOpenContext);
    IoReleaseCancelSpinLock(pIrp->CancelIrql);
    
    NPROT_STRUCT_ASSERT(pOpenContext, oc);

    //
    //  Try to locate the IRP in the pended write queue. The send completion
    //  routine may be running and might have removed it from there.
    //
    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

    for (pIrpEntry = pOpenContext->PendedWrites.Flink;
         pIrpEntry != &pOpenContext->PendedWrites;
         pIrpEntry = pIrpEntry->Flink)
    {
        if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
        {
            FoundIrp = TRUE;
            break;
        }
    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

    if (FoundIrp)    
    {
        PVOID              CancelId;

        CancelId = pIrp->Tail.Overlay.DriverContext[2];
        //
        //  Either the send completion routine hasn't run, or we got a peak
        //  at the IRP/netbufferlist before it had a chance to take it out of the
        //  pending IRP queue.
        //
        //  We do not complete the IRP here - note that we didn't dequeue it
        //  above. This is because we always want the send complete routine to
        //  complete the IRP. And this in turn is because the NetBufferlist that was
        //  prepared from the IRP has a buffer chain pointing to data associated
        //  with this IRP. Therefore we cannot complete the IRP before the driver
        //  below us is done with the data it pointed to.
        //

        //
        //  Request NDIS to cancel this send. The result of this call is that
        //  our SendComplete handler will be called (if not already called).
        //
        DEBUGP(DL_INFO, ("CancelWrite: cancelling nbl %p on Open %p\n",
            pIrp->Tail.Overlay.DriverContext[1], pOpenContext));
        
        NdisCancelSendNetBufferLists(
                pOpenContext->BindingHandle,
                CancelId);
        
    }
    //
    //  else the send completion routine has already picked up this IRP.
    //
    NPROT_DEREF_OPEN(pOpenContext);
}
Ejemplo n.º 9
0
NTSTATUS
ndisprotOpenDevice(
    IN PUCHAR                   pDeviceName,
    IN ULONG                    DeviceNameLength,
    IN PFILE_OBJECT             pFileObject,
    OUT PNDISPROT_OPEN_CONTEXT * ppOpenContext
    )
/*++

Routine Description:

    Helper routine called to process IOCTL_NDISPROT_OPEN_DEVICE. Check if
    there is a binding to the specified device, and is not associated with
    a file object already. If so, make an association between the binding
    and this file object.

Arguments:

    pDeviceName - pointer to device name string
    DeviceNameLength - length of above
    pFileObject - pointer to file object being associated with the device binding

Return Value:

    Status is returned.
--*/
{
    PNDISPROT_OPEN_CONTEXT   pOpenContext;
    NTSTATUS                NtStatus;
    ULONG                   PacketFilter;
    NDIS_STATUS             NdisStatus;
    ULONG                   BytesProcessed;
    PNDISPROT_OPEN_CONTEXT   pCurrentOpenContext = NULL;

    pOpenContext = NULL;

    do
    {
        pOpenContext = ndisprotLookupDevice(
                        pDeviceName,
                        DeviceNameLength
                        );

        if (pOpenContext == NULL)
        {
            DEBUGP(DL_WARN, ("ndisprotOpenDevice: couldn't find device\n"));
            NtStatus = STATUS_OBJECT_NAME_NOT_FOUND;
            break;
        }

        //
        //  else ndisprotLookupDevice would have addref'ed the open.
        //
        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NUIOO_OPEN_FLAGS, NUIOO_OPEN_IDLE))
        {
            NPROT_ASSERT(pOpenContext->pFileObject != NULL);

            DEBUGP(DL_WARN, ("ndisprotOpenDevice: Open %p/%x already associated"
                " with another FileObject %p\n", 
                pOpenContext, pOpenContext->Flags, pOpenContext->pFileObject));
            
            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

            NPROT_DEREF_OPEN(pOpenContext); // ndisprotOpenDevice failure
            NtStatus = STATUS_DEVICE_BUSY;
            break;
        }
        //
        // This InterlockedXXX function performs an atomic operation: First it compare
        // pFileObject->FsContext with NULL, if they are equal, the function puts  pOpenContext
        // into FsContext, and return NULL. Otherwise, it return pFileObject->FsContext without
        // changing anything.
        // 
            
        if ((pCurrentOpenContext = InterlockedCompareExchangePointer (& (pFileObject->FsContext), pOpenContext, NULL)) != NULL)
        {
            //
            // pFileObject->FsContext already is used by other open
            //
            DEBUGP(DL_WARN, ("ndisprotOpenDevice: FileObject %p already associated"
                " with another Open %p/%x\n", 
                pFileObject, pCurrentOpenContext, pCurrentOpenContext->Flags));  //BUG
            
            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

            NPROT_DEREF_OPEN(pOpenContext); // ndisprotOpenDevice failure
            NtStatus = STATUS_INVALID_DEVICE_REQUEST;
            break;
        }

        pOpenContext->pFileObject = pFileObject;

        NPROT_SET_FLAGS(pOpenContext->Flags, NUIOO_OPEN_FLAGS, NUIOO_OPEN_ACTIVE);

        NPROT_RELEASE_LOCK(&pOpenContext->Lock);

        //
        //  Set the packet filter now.
        //
        PacketFilter = NUIOO_PACKET_FILTER;
        NdisStatus = ndisprotValidateOpenAndDoRequest(
                        pOpenContext,
                        NdisRequestSetInformation,
                        OID_GEN_CURRENT_PACKET_FILTER,
                        &PacketFilter,
                        sizeof(PacketFilter),
                        &BytesProcessed,
                        TRUE    // Do wait for power on
                        );
    
        if (NdisStatus != NDIS_STATUS_SUCCESS)
        {
            DEBUGP(DL_WARN, ("openDevice: Open %p: set packet filter (%x) failed: %x\n",
                    pOpenContext, PacketFilter, NdisStatus));

            //
            //  Undo all that we did above.
            //
            NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
            //
            // Need to set pFileObject->FsContext to NULL again, so others can open a device
            // for this file object later
            //
            pCurrentOpenContext = InterlockedCompareExchangePointer (& (pFileObject->FsContext), NULL, pOpenContext);
            
     
            NPROT_ASSERT(pCurrentOpenContext == pOpenContext);
            
            NPROT_SET_FLAGS(pOpenContext->Flags, NUIOO_OPEN_FLAGS, NUIOO_OPEN_IDLE);
            pOpenContext->pFileObject = NULL;

            NPROT_RELEASE_LOCK(&pOpenContext->Lock);

            NPROT_DEREF_OPEN(pOpenContext); // ndisprotOpenDevice failure

            NDIS_STATUS_TO_NT_STATUS(NdisStatus, &NtStatus);
            break;
        }

        *ppOpenContext = pOpenContext;
        
        NtStatus = STATUS_SUCCESS;
    }
    while (FALSE);

    return (NtStatus);
}
Ejemplo n.º 10
0
NTSTATUS
NdisProtCleanup(
    IN PDEVICE_OBJECT   pDeviceObject,
    IN PIRP             pIrp
    )
/*++

Routine Description:

    This is the dispatch routine for handling IRP_MJ_CLEANUP.

Arguments:

    pDeviceObject - Pointer to the device object.

    pIrp - Pointer to the request packet.

Return Value:

    Status is returned.

--*/
{
    PIO_STACK_LOCATION      pIrpSp;
    NTSTATUS                NtStatus;
    NDIS_STATUS             NdisStatus;
    PNDISPROT_OPEN_CONTEXT   pOpenContext;
    ULONG                   PacketFilter;
    ULONG                   BytesProcessed;

    
    UNREFERENCED_PARAMETER(pDeviceObject);
	
    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;

    DEBUGP(DL_VERY_LOUD, ("Cleanup: FileObject %p, Open %p\n",
        pIrpSp->FileObject, pOpenContext));

    if (pOpenContext != NULL)
    {
        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        //
        //  Mark this endpoint.
        //
        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

        NPROT_SET_FLAGS(pOpenContext->Flags, NUIOO_OPEN_FLAGS, NUIOO_OPEN_IDLE);
        pOpenContext->pFileObject = NULL;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock);

        //
        //  Set the packet filter to 0, telling NDIS that we aren't
        //  interested in any more receives.
        //
        PacketFilter = 0;
        NdisStatus = ndisprotValidateOpenAndDoRequest(
                        pOpenContext,
                        NdisRequestSetInformation,
                        OID_GEN_CURRENT_PACKET_FILTER,
                        &PacketFilter,
                        sizeof(PacketFilter),
                        &BytesProcessed,
                        FALSE   // Don't wait for device to be powered on
                        );
    
        if (NdisStatus != NDIS_STATUS_SUCCESS)
        {
            DEBUGP(DL_INFO, ("Cleanup: Open %p, set packet filter (%x) failed: %x\n",
                    pOpenContext, PacketFilter, NdisStatus));
            //
            //  Ignore the result. If this failed, we may continue
            //  to get indicated receives, which will be handled
            //  appropriately.
            //
            NdisStatus = NDIS_STATUS_SUCCESS;
        }

        //
        //  Cancel any pending reads.
        //
        ndisprotCancelPendingReads(pOpenContext);
        //
        // Clean up the receive packet queue
        //
        ndisprotFlushReceiveQueue(pOpenContext);
    }

    NtStatus = STATUS_SUCCESS;

    pIrp->IoStatus.Information = 0;
    pIrp->IoStatus.Status = NtStatus;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    DEBUGP(DL_INFO, ("Cleanup: OpenContext %p\n", pOpenContext));

    return (NtStatus);
}
Ejemplo n.º 11
0
VOID
ndisprotServiceReads(
    IN PNDISPROT_OPEN_CONTEXT        pOpenContext
    )
/*++

Routine Description:

    Utility routine to copy received data into user buffers and
    complete READ IRPs.

Arguments:

    pOpenContext - pointer to open context

Return Value:

    None

--*/
{
    PIRP                pIrp = NULL;
    PLIST_ENTRY         pIrpEntry;
    PNDIS_PACKET        pRcvPacket;
    PLIST_ENTRY         pRcvPacketEntry;
    PUCHAR              pSrc, pDst;
    ULONG               BytesRemaining; // at pDst
    PNDIS_BUFFER        pNdisBuffer;
    ULONG               BytesAvailable;
    BOOLEAN             FoundPendingIrp;

    DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
            pOpenContext, pOpenContext->Flags));

    NPROT_REF_OPEN(pOpenContext);  // temp ref - service reads

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

    while (!NPROT_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
           !NPROT_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
    {
        FoundPendingIrp = FALSE;
        //
        //  Get the first pended Read IRP
        //
        pIrpEntry = pOpenContext->PendedReads.Flink;
        while (pIrpEntry != &pOpenContext->PendedReads)
        {
            pIrp = CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry);

            //
            //  Check to see if it is being cancelled.
            //
            if (IoSetCancelRoutine(pIrp, NULL))
            {
                //
                //  It isn't being cancelled, and can't be cancelled henceforth.
                //
                NPROT_REMOVE_ENTRY_LIST(pIrpEntry);
                FoundPendingIrp = TRUE;
                break;

                //
                //  NOTE: we decrement PendedReadCount way below in the
                //  while loop, to avoid letting through a thread trying
                //  to unbind.
                //
            }
            else
            {
                //
                //  The IRP is being cancelled; let the cancel routine handle it.
                //
                DEBUGP(DL_INFO, ("ServiceReads: open %p, skipping cancelled IRP %p\n",
                        pOpenContext, pIrp));
                pIrpEntry = pIrpEntry->Flink;

            }
        }
        //
        // If no pending IRP
        //
        if (FoundPendingIrp == FALSE)
        {
            break;
        }
        //
        //  Get the first queued receive packet
        //
        pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
        NPROT_REMOVE_ENTRY_LIST(pRcvPacketEntry);

        pOpenContext->RecvPktCount --;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock);

        NPROT_DEREF_OPEN(pOpenContext);  // Service: dequeue rcv packet

        pRcvPacket = NPROT_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);

        //
        //  Copy as much data as possible from the receive packet to
        //  the IRP MDL.
        //
        pDst = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
        __analysis_assume(pDst);
        NPROT_ASSERT(pDst != NULL);  // since it was already mapped
        BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress);

        pNdisBuffer = NDIS_PACKET_FIRST_NDIS_BUFFER(pRcvPacket);

        //
        // Copy the data in the received packet into the buffer provided by the client.
        // If the length of the receive packet is greater than length of the given buffer, 
        // we just copy as many bytes as we can. Once the buffer is full, we just discard 
        // the rest of the data, and complete the IRP sucessfully even we only did a partial copy.
        // 
        while (BytesRemaining && (pNdisBuffer != NULL))
        {
#ifndef WIN9X
            NdisQueryBufferSafe(pNdisBuffer, &pSrc, &BytesAvailable, NormalPagePriority);

            if (pSrc == NULL) 
            {
                DEBUGP(DL_FATAL,
                    ("ServiceReads: Open %p, QueryBuffer failed for buffer %p\n",
                            pOpenContext, pNdisBuffer));
                break;
            }
#else
            NdisQueryBuffer(pNdisBuffer, &pSrc, &BytesAvailable);
#endif

            if (BytesAvailable)
            {
                ULONG       BytesToCopy = MIN(BytesAvailable, BytesRemaining);

                NPROT_COPY_MEM(pDst, pSrc, BytesToCopy);
                BytesRemaining -= BytesToCopy;
                pDst += BytesToCopy;
            }

            NdisGetNextBuffer(pNdisBuffer, &pNdisBuffer);
        }

        //
        //  Complete the IRP.
        //
        pIrp->IoStatus.Status = STATUS_SUCCESS;
        pIrp->IoStatus.Information = MmGetMdlByteCount(pIrp->MdlAddress) - BytesRemaining;

        DEBUGP(DL_INFO, ("ServiceReads: Open %p, IRP %p completed with %d bytes\n",
            pOpenContext, pIrp, pIrp->IoStatus.Information));

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        //
        //  Free up the receive packet - back to the miniport if it
        //  belongs to it, else reclaim it (local copy).
        //
        if (NdisGetPoolFromPacket(pRcvPacket) != pOpenContext->RecvPacketPool)
        {
            NdisReturnPackets(&pRcvPacket, 1);
        }
        else
        {
            ndisprotFreeReceivePacket(pOpenContext, pRcvPacket);
        }

        NPROT_DEREF_OPEN(pOpenContext);    // took out pended Read

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);
        pOpenContext->PendedReadCount--;

    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock);

    NPROT_DEREF_OPEN(pOpenContext);    // temp ref - service reads
}
Ejemplo n.º 12
0
VOID
NdisProtCancelRead(
    IN PDEVICE_OBJECT               pDeviceObject,
    IN PIRP                         pIrp
    )
/*++

Routine Description:

    Cancel a pending read IRP. We unlink the IRP from the open context
    queue and complete it.

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - IRP to be cancelled

Return Value:

    None

--*/
{
    PNDISPROT_OPEN_CONTEXT       pOpenContext;
    PLIST_ENTRY                 pIrpEntry;
    BOOLEAN                     Found;

    UNREFERENCED_PARAMETER(pDeviceObject);
    
    IoReleaseCancelSpinLock(pIrp->CancelIrql);

    Found = FALSE;

    pOpenContext = (PNDISPROT_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
    NPROT_STRUCT_ASSERT(pOpenContext, oc);

    NPROT_ACQUIRE_LOCK(&pOpenContext->Lock);

    //
    //  Locate the IRP in the pended read queue and remove it if found.
    //
    for (pIrpEntry = pOpenContext->PendedReads.Flink;
         pIrpEntry != &pOpenContext->PendedReads;
         pIrpEntry = pIrpEntry->Flink)
    {
        if (pIrp == CONTAINING_RECORD(pIrpEntry, IRP, Tail.Overlay.ListEntry))
        {
            NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
            pOpenContext->PendedReadCount--;
            Found = TRUE;
            break;
        }
    }

    NPROT_RELEASE_LOCK(&pOpenContext->Lock);

    if (Found)
    {
        DEBUGP(DL_INFO, ("CancelRead: Open %p, IRP %p\n", pOpenContext, pIrp));
        pIrp->IoStatus.Status = STATUS_CANCELLED;
        pIrp->IoStatus.Information = 0;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        NPROT_DEREF_OPEN(pOpenContext); // Cancel removed pended Read
    }
}
Ejemplo n.º 13
0
VOID
NdisprotSendComplete(
    IN NDIS_HANDLE                  ProtocolBindingContext,
    IN PNET_BUFFER_LIST             pNetBufferList,
    IN ULONG                        SendCompleteFlags
    )
/*++

Routine Description:

    NDIS entry point called to signify completion of a packet send.
    We pick up and complete the Write IRP corresponding to this packet.

Arguments:

    ProtocolBindingContext - pointer to open context
    pNetBufferList - NetBufferList that completed send
    SendCompleteFlags - Specifies if the caller is at DISPATCH level

Return Value:

    None

--*/
{
    PIRP                        pIrp;
    PIO_STACK_LOCATION          pIrpSp;
    PNDISPROT_OPEN_CONTEXT      pOpenContext;
    PNET_BUFFER_LIST            CurrNetBufferList = NULL;
    PNET_BUFFER_LIST            NextNetBufferList;
    NDIS_STATUS                 CompletionStatus;
    BOOLEAN                     DispatchLevel;

    pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
    NPROT_STRUCT_ASSERT(pOpenContext, oc);
    DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);

    for (CurrNetBufferList = pNetBufferList;
            CurrNetBufferList != NULL;
            CurrNetBufferList = NextNetBufferList)
    {
        NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList);
        
        pIrp = NPROT_IRP_FROM_SEND_NBL(CurrNetBufferList);

        IoAcquireCancelSpinLock(&pIrp->CancelIrql);
        IoSetCancelRoutine(pIrp, NULL);
        pIrp->Tail.Overlay.DriverContext[0] = NULL;
        pIrp->Tail.Overlay.DriverContext[1] = NULL;
        IoReleaseCancelSpinLock(pIrp->CancelIrql);

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);

        NPROT_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);
        
        CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList);
        
        
        //
        //  We are done with the NDIS_PACKET:
        //
        NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel);

        //
        //  Complete the Write IRP with the right status.
        //
        pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
        if (CompletionStatus == NDIS_STATUS_SUCCESS)
        {
            pIrp->IoStatus.Information = pIrpSp->Parameters.Write.Length;
            pIrp->IoStatus.Status = STATUS_SUCCESS;
        }
        else
        {
            pIrp->IoStatus.Information = 0;
            pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
        }

        DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d "
                        "completed with status %x\n",
                        CurrNetBufferList, pIrp, pIrp->IoStatus.Information, pIrp->IoStatus.Status));

        IoCompleteRequest(pIrp, IO_NO_INCREMENT);

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);
        pOpenContext->PendedSendCount--;

        if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING))
                && (pOpenContext->PendedSendCount == 0))
        {
            ASSERT(pOpenContext->ClosingEvent != NULL);
            NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent);
            pOpenContext->ClosingEvent = NULL;
        }
        NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);

        NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP
    }
    
}
Ejemplo n.º 14
0
NTSTATUS
NdisprotWrite(
    IN PDEVICE_OBJECT       pDeviceObject,
    IN PIRP                 pIrp
    )
/*++

Routine Description:

    Dispatch routine to handle IRP_MJ_WRITE. 

Arguments:

    pDeviceObject - pointer to our device object
    pIrp - Pointer to request packet

Return Value:

    NT status code.

--*/
{
    PIO_STACK_LOCATION      pIrpSp;
    ULONG                   DataLength;
    NTSTATUS                NtStatus;
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    PNET_BUFFER_LIST        pNetBufferList;
    PMDL                    pMdl;
    NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
    PVOID                   CancelId;
    ULONG                   SendFlags = 0;

    UNREFERENCED_PARAMETER(pDeviceObject);

    pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
    pOpenContext = pIrpSp->FileObject->FsContext;


    do
    {
        if (pOpenContext == NULL)
        {
            DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
                pIrpSp->FileObject));
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }
               
        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        if (pIrp->MdlAddress == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: NULL MDL address on IRP %p\n", pIrp));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }

        //
        // Try to get a virtual address for the MDL.
        //
        
        pEthHeader = NULL;
        NdisQueryMdl(pIrp->MdlAddress, &pEthHeader, &DataLength, NormalPagePriority);

        if (pEthHeader == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
                    " IRP %p, MDL %p\n",
                    pIrp, pIrp->MdlAddress));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Sanity-check the length.
        //
        if (DataLength < sizeof(NDISPROT_ETH_HEADER))
        {
            DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
                DataLength));
            NtStatus = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER)))
        {
            DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
                    " larger than max frame size (%d)\n",
                    pOpenContext, DataLength, pOpenContext->MaxFrameSize));

            NtStatus = STATUS_INVALID_BUFFER_SIZE;
            break;
        }

        if (pEthHeader->EthType != Globals.EthType)
        {
            DEBUGP(DL_WARN, ("Write: Failing send with EthType %x\n",
                pEthHeader->EthType));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }
       
        if (!NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
        {
            DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }
        

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
            " or in low power state\n", pOpenContext));

            NtStatus = STATUS_INVALID_HANDLE;
            break;
        } 

        if (pOpenContext->State != NdisprotRunning  ||
            pOpenContext->PowerState != NetDeviceStateD0)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
            
            DEBUGP(DL_INFO, ("Device is not ready.\n"));
            NtStatus = STATUS_UNSUCCESSFUL;
            break;
        }


        pMdl = pIrp->MdlAddress;
        NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL);
        pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
                                pOpenContext->SendNetBufferListPool,
                                sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta
                                0,           // back fill size
                                pMdl,
                                0,          // Data offset
                                DataLength);
        
        if (pNetBufferList == NULL)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
            
            DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n",
                    pOpenContext));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        pOpenContext->PendedSendCount++;

        NPROT_REF_OPEN(pOpenContext);  // pended send

        IoMarkIrpPending(pIrp);

        //
        //  Initialize the NetBufferList ref count. This NetBufferList will be freed
        //  when this count goes to zero.
        //
        NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1;

        //
        //  We set up a cancel ID on each send NetBufferList (which maps to a Write IRP), 
        //  and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use
        //  NdisCancelSendNetBufferLists() to cancel the NetBufferList.
        //
       
        CancelId = NPROT_GET_NEXT_CANCEL_ID();
        NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId);
        pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
        pIrp->Tail.Overlay.DriverContext[1] = (PVOID)pNetBufferList;
        pIrp->Tail.Overlay.DriverContext[2] = CancelId;

        NPROT_INSERT_TAIL_LIST(&pOpenContext->PendedWrites, &pIrp->Tail.Overlay.ListEntry);

        IoSetCancelRoutine(pIrp, NdisprotCancelWrite);


        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        //
        //  Set a back pointer from the packet to the IRP.
        //
        NPROT_IRP_FROM_SEND_NBL(pNetBufferList) = pIrp;

        NtStatus = STATUS_PENDING;


#if SEND_DBG
        {
            PUCHAR      pData;

            pData = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
            NPROT_ASSERT(pEthHeader == pData);

            DEBUGP(DL_VERY_LOUD, 
                ("Write: MDL %p, MdlFlags %x, SystemAddr %p, %d bytes\n",
                    pIrp->MdlAddress, pIrp->MdlAddress->MdlFlags, pData, DataLength));

            DEBUGPDUMP(DL_VERY_LOUD, pData, MIN(DataLength, 48));
        }
#endif // SEND_DBG

        pNetBufferList->SourceHandle = pOpenContext->BindingHandle;
        ASSERT (NDIS_MDL_LINKAGE(pMdl) == NULL);
        
        SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;

        NdisSendNetBufferLists(        
                        pOpenContext->BindingHandle,
                        pNetBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        SendFlags);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        pIrp->IoStatus.Status = NtStatus;
        IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    }

    return (NtStatus);
}
Ejemplo n.º 15
0
VOID
NdisProtEvtIoWrite(
    IN WDFQUEUE         Queue,
    IN WDFREQUEST       Request,
    IN size_t           Length
    )
/*++

Routine Description:

    Dispatch routine to handle Request_MJ_WRITE.

Arguments:

    Queue - Default queue handle
    Request - Handle to the read/write request
    Lenght - Length of the data buffer associated with the request.
                 The default property of the queue is to not dispatch
                 zero lenght read & write requests to the driver and
                 complete is with status success. So we will never get
                 a zero length request.

Return Value:

    VOID

--*/
{
    ULONG                   DataLength;
    NTSTATUS                NtStatus;
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    PNET_BUFFER_LIST        pNetBufferList;
    NDISPROT_ETH_HEADER UNALIGNED *pEthHeader;
    PVOID                   CancelId;
    ULONG                   SendFlags = 0;
    PMDL                    pMdl = NULL;
    WDFFILEOBJECT           fileObject;
    PREQUEST_CONTEXT        reqContext;
    WDF_OBJECT_ATTRIBUTES   attributes;

    UNREFERENCED_PARAMETER(Queue);

    fileObject = WdfRequestGetFileObject(Request);
    pOpenContext = GetFileObjectContext(fileObject)->OpenContext;

    do
    {
        //
        // Create a context to track the length of transfer and NDIS packet
        // associated with this request.
        //
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT);

        NtStatus = WdfObjectAllocateContext(Request, &attributes, &reqContext);
        if(!NT_SUCCESS(NtStatus)){
            DEBUGP(DL_WARN, ("Write: WdfObjectAllocateContext failed: %x\n", NtStatus));
            NtStatus = STATUS_INVALID_HANDLE;
            break;

        }

        reqContext->Length = (ULONG) Length;

        if (pOpenContext == NULL)
        {
            DEBUGP(DL_WARN, ("Write: FileObject %p not yet associated with a device\n",
                fileObject));
            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        NtStatus = WdfRequestRetrieveInputWdmMdl(Request, &pMdl);
        if (!NT_SUCCESS(NtStatus))
        {
            DEBUGP(DL_FATAL, ("Write: WdfRequestRetrieveInputWdmMdl failed %x\n", NtStatus));
            break;
        }

        //
        // Try to get a virtual address for the MDL.
        //
        pEthHeader = MmGetSystemAddressForMdlSafe(pMdl, NormalPagePriority | MdlMappingNoExecute);

        if (pEthHeader == NULL)
        {
            DEBUGP(DL_FATAL, ("Write: MmGetSystemAddr failed for"
                    " Request %p, MDL %p\n",
                    Request, pMdl));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        //
        // Sanity-check the length.
        //
        DataLength = MmGetMdlByteCount(pMdl);
        if (DataLength < sizeof(NDISPROT_ETH_HEADER))
        {
            DEBUGP(DL_WARN, ("Write: too small to be a valid packet (%d bytes)\n",
                DataLength));
            NtStatus = STATUS_BUFFER_TOO_SMALL;
            break;
        }

        if (DataLength > (pOpenContext->MaxFrameSize + sizeof(NDISPROT_ETH_HEADER)))
        {
            DEBUGP(DL_WARN, ("Write: Open %p: data length (%d)"
                    " larger than max frame size (%d)\n",
                    pOpenContext, DataLength, pOpenContext->MaxFrameSize));

            NtStatus = STATUS_INVALID_BUFFER_SIZE;
            break;
        }

        //
        // To prevent applications from sending packets with spoofed
        // mac address, we will do the following check to make sure the source
        // address in the packet is same as the current MAC address of the NIC.
        //
        if ((WdfRequestGetRequestorMode(Request) == UserMode) &&
            !NPROT_MEM_CMP(pEthHeader->SrcAddr, pOpenContext->CurrentAddress, NPROT_MAC_ADDR_LEN))
        {
            DEBUGP(DL_WARN, ("Write: Failing with invalid Source address"));
            NtStatus = STATUS_INVALID_PARAMETER;
            break;
        }

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        if (!NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_FATAL, ("Write: Open %p is not bound"
            " or in low power state\n", pOpenContext));

            NtStatus = STATUS_INVALID_HANDLE;
            break;
        }

        if ((pOpenContext->State == NdisprotPaused)
            || (pOpenContext->State == NdisprotPausing))
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_INFO, ("Device is paused.\n"));
            NtStatus = STATUS_UNSUCCESSFUL;
            break;
        }

        NPROT_ASSERT(pOpenContext->SendNetBufferListPool != NULL);
        pNetBufferList = NdisAllocateNetBufferAndNetBufferList(
                                pOpenContext->SendNetBufferListPool,
                                sizeof(NPROT_SEND_NETBUFLIST_RSVD), //Request control offset delta
                                0,           // back fill size
                                pMdl,
                                0,          // Data offset
                                DataLength);

        if (pNetBufferList == NULL)
        {
            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            DEBUGP(DL_FATAL, ("Write: open %p, failed to alloc send net buffer list\n",
                    pOpenContext));
            NtStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }
        pOpenContext->PendedSendCount++;

        NPROT_REF_OPEN(pOpenContext);  // pended send

        //
        //  Initialize the NetBufferList ref count. This NetBufferList will be freed
        //  when this count goes to zero.
        //
        NPROT_SEND_NBL_RSVD(pNetBufferList)->RefCount = 1;

        //
        //  We set up a cancel ID on each send NetBufferList (which maps to a Write IRP),
        //  and save the NetBufferList pointer in the IRP. If the IRP gets cancelled, we use
        //  NdisCancelSendNetBufferLists() to cancel the NetBufferList.
        //
        //  Note that this sample code does not implement the cancellation logic. An actual
        //  driver may find value in implementing this.
        //

        CancelId = NPROT_GET_NEXT_CANCEL_ID();
        NDIS_SET_NET_BUFFER_LIST_CANCEL_ID(pNetBufferList, CancelId);
        reqContext->NetBufferList = (PVOID)pNetBufferList;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        //
        //  Set a back pointer from the packet to the IRP.
        //
        NPROT_REQUEST_FROM_SEND_NBL(pNetBufferList) = Request;

        NtStatus = STATUS_PENDING;

        pNetBufferList->SourceHandle = pOpenContext->BindingHandle;
        NPROT_ASSERT (pMdl->Next == NULL);

        SendFlags |= NDIS_SEND_FLAGS_CHECK_FOR_LOOPBACK;

        NdisSendNetBufferLists(
                        pOpenContext->BindingHandle,
                        pNetBufferList,
                        NDIS_DEFAULT_PORT_NUMBER,
                        SendFlags);

    }
    while (FALSE);

    if (NtStatus != STATUS_PENDING)
    {
        WdfRequestComplete(Request, NtStatus);
    }

    return;
}
Ejemplo n.º 16
0
VOID
NdisprotSendComplete(
    IN NDIS_HANDLE                  ProtocolBindingContext,
    IN PNET_BUFFER_LIST             pNetBufferList,
    IN ULONG                        SendCompleteFlags
    )
/*++

Routine Description:

    NDIS entry point called to signify completion of a packet send.
    We pick up and complete the Write IRP corresponding to this packet.

Arguments:

    ProtocolBindingContext - pointer to open context
    pNetBufferList - NetBufferList that completed send
    SendCompleteFlags - Specifies if the caller is at DISPATCH level

Return Value:

    None

--*/
{
    PNDISPROT_OPEN_CONTEXT      pOpenContext;
    PNET_BUFFER_LIST            CurrNetBufferList = NULL;
    PNET_BUFFER_LIST            NextNetBufferList;
    NDIS_STATUS                 CompletionStatus;
    BOOLEAN                     DispatchLevel;
    WDFREQUEST                  request;
    PREQUEST_CONTEXT            reqContext;


    pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
    NPROT_STRUCT_ASSERT(pOpenContext, oc);
    DispatchLevel = NDIS_TEST_SEND_AT_DISPATCH_LEVEL(SendCompleteFlags);


    for (CurrNetBufferList = pNetBufferList;
            CurrNetBufferList != NULL;
            CurrNetBufferList = NextNetBufferList)
    {
        NextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(CurrNetBufferList);

        request = NPROT_REQUEST_FROM_SEND_NBL(CurrNetBufferList);
        reqContext = GetRequestContext(request);
        CompletionStatus = NET_BUFFER_LIST_STATUS(CurrNetBufferList);

        DEBUGP(DL_INFO, ("SendComplete: NetBufferList %p/IRP %p/Length %d "
                        "completed with status %x\n",
                        CurrNetBufferList, request, reqContext->Length,
                        CompletionStatus));

		//
        //  We are done with the NDIS_PACKET:
        //
        NPROT_DEREF_SEND_NBL(CurrNetBufferList, DispatchLevel);
        CurrNetBufferList = NULL;

        if (CompletionStatus == NDIS_STATUS_SUCCESS)
        {
            WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, reqContext->Length);
         }
        else
        {
            WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0);
        }

        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, DispatchLevel);
        pOpenContext->PendedSendCount--;

        if ((NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_CLOSING))
                && (pOpenContext->PendedSendCount == 0))
        {
            NPROT_ASSERT(pOpenContext->ClosingEvent != NULL);
            NPROT_SIGNAL_EVENT(pOpenContext->ClosingEvent);
            pOpenContext->ClosingEvent = NULL;
        }
        NPROT_RELEASE_LOCK(&pOpenContext->Lock, DispatchLevel);

        NPROT_DEREF_OPEN(pOpenContext); // send complete - dequeued send IRP
    }

}
Ejemplo n.º 17
0
VOID
NdisProtEvtFileCleanup(
    IN WDFFILEOBJECT    FileObject
    )
/*++

Routine Description:

   EvtFileCleanup is called when the handle represented by the FileObject
   is closed. This callback is invoked in the context of the thread that
   closed the handle.

Arguments:

    FileObject - Pointer to fileobject that represents the open handle.

Return Value:

   VOID

--*/
{
    NTSTATUS                NtStatus;
    NDIS_STATUS             NdisStatus;
    PNDISPROT_OPEN_CONTEXT  pOpenContext;
    ULONG                   PacketFilter;
    ULONG                   BytesProcessed;
    PFILE_OBJECT_CONTEXT    fileContext;

    fileContext = GetFileObjectContext(FileObject);

    pOpenContext = fileContext->OpenContext;

    DEBUGP(DL_VERY_LOUD, ("Cleanup: FileObject %p, Open %p\n",
                                FileObject, pOpenContext));

    if (pOpenContext != NULL)
    {
        NPROT_STRUCT_ASSERT(pOpenContext, oc);

        //
        //  Mark this endpoint.
        //
        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        NPROT_SET_FLAGS(pOpenContext->Flags, NPROTO_OPEN_FLAGS, NPROTO_OPEN_IDLE);
        pOpenContext->pFileObject = NULL;

        NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

        //
        //  Set the packet filter to 0, telling NDIS that we aren't
        //  interested in any more receives.
        //
        PacketFilter = 0;
        NdisStatus = ndisprotValidateOpenAndDoRequest(
                        pOpenContext,
                        NdisRequestSetInformation,
                        OID_GEN_CURRENT_PACKET_FILTER,
                        &PacketFilter,
                        sizeof(PacketFilter),
                        &BytesProcessed,
                        FALSE   // Don't wait for device to be powered on
                        );

        if (NdisStatus != NDIS_STATUS_SUCCESS)
        {
            DEBUGP(DL_INFO, ("Cleanup: Open %p, set packet filter (%x) failed: %x\n",
                    pOpenContext, PacketFilter, NdisStatus));
            //
            //  Ignore the result. If this failed, we may continue
            //  to get indicated receives, which will be handled
            //  appropriately.
            //
            NdisStatus = NDIS_STATUS_SUCCESS;
        }


        NPROT_ACQUIRE_LOCK(&pOpenContext->Lock, FALSE);

        if (NPROT_TEST_FLAGS(pOpenContext->Flags, NPROTO_BIND_FLAGS, NPROTO_BIND_ACTIVE)){

            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);

            //
            //  Cancel any pending reads.
            //
            WdfIoQueuePurgeSynchronously(pOpenContext->ReadQueue);
            //
            // Cancel pending control request for status indication.
            //
            WdfIoQueuePurgeSynchronously(pOpenContext->StatusIndicationQueue);
        } else {

            NPROT_RELEASE_LOCK(&pOpenContext->Lock, FALSE);
        }

        //
        // Clean up the receive packet queue
        //
        ndisprotFlushReceiveQueue(pOpenContext);
    }

    NtStatus = STATUS_SUCCESS;

    DEBUGP(DL_INFO, ("Cleanup: OpenContext %p\n", pOpenContext));

    return;
}