📄 recv.c
字号:
/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
recv.c
Abstract:
NDIS protocol entry points and utility routines to handle receiving
data.
Environment:
Kernel mode only.
Revision History:
arvindm 4/6/2000 Created
--*/
#include "precomp.h"
#define __FILENUMBER 'VCER'
NTSTATUS
NdisuioRead(
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;
ULONG FunctionCode;
NTSTATUS NtStatus;
PNDISUIO_OPEN_CONTEXT pOpenContext;
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;
}
NUIO_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.
//
#ifndef WIN9X
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;
}
#endif
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
if (!NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE))
{
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
NtStatus = STATUS_INVALID_HANDLE;
break;
}
//
// Add this IRP to the list of pended Read IRPs
//
NUIO_INSERT_TAIL_LIST(&pOpenContext->PendedReads, &pIrp->Tail.Overlay.ListEntry);
NUIO_REF_OPEN(pOpenContext); // pended read IRP
pOpenContext->PendedReadCount++;
//
// Set up the IRP for possible cancellation.
//
pIrp->Tail.Overlay.DriverContext[0] = (PVOID)pOpenContext;
IoMarkIrpPending(pIrp);
IoSetCancelRoutine(pIrp, NdisuioCancelRead);
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
NtStatus = STATUS_PENDING;
//
// Run the service routine for reads.
//
ndisuioServiceReads(pOpenContext);
break;
}
while (FALSE);
if (NtStatus != STATUS_PENDING)
{
NUIO_ASSERT(NtStatus != STATUS_SUCCESS);
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = NtStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
}
return (NtStatus);
}
VOID
NdisuioCancelRead(
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
--*/
{
PNDISUIO_OPEN_CONTEXT pOpenContext;
PLIST_ENTRY pEnt;
PLIST_ENTRY pIrpEntry;
BOOLEAN Found;
IoReleaseCancelSpinLock(pIrp->CancelIrql);
Found = FALSE;
pOpenContext = (PNDISUIO_OPEN_CONTEXT) pIrp->Tail.Overlay.DriverContext[0];
NUIO_STRUCT_ASSERT(pOpenContext, oc);
NUIO_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))
{
NUIO_REMOVE_ENTRY_LIST(&pIrp->Tail.Overlay.ListEntry);
pOpenContext->PendedReadCount--;
Found = TRUE;
break;
}
}
NUIO_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);
NUIO_DEREF_OPEN(pOpenContext); // Cancel removed pended Read
}
}
VOID
ndisuioServiceReads(
IN PNDISUIO_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;
PLIST_ENTRY pIrpEntry;
PNDIS_PACKET pRcvPacket;
PLIST_ENTRY pRcvPacketEntry;
PUCHAR pSrc, pDst;
ULONG BytesRemaining; // at pDst
PNDIS_BUFFER pNdisBuffer;
ULONG BytesAvailable;
DEBUGP(DL_VERY_LOUD, ("ServiceReads: open %p/%x\n",
pOpenContext, pOpenContext->Flags));
NUIO_REF_OPEN(pOpenContext); // temp ref - service reads
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads) &&
!NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
{
//
// Get the first pended Read IRP
//
pIrpEntry = pOpenContext->PendedReads.Flink;
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.
//
NUIO_REMOVE_ENTRY_LIST(pIrpEntry);
//
// 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));
continue;
}
//
// Get the first queued receive packet
//
pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry);
pOpenContext->RecvPktCount --;
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
NUIO_DEREF_OPEN(pOpenContext); // Service: dequeue rcv packet
pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);
//
// Copy as much data as possible from the receive packet to
// the IRP MDL.
//
#ifndef WIN9X
pDst = MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
NUIO_ASSERT(pDst != NULL); // since it was already mapped
#else
pDst = MmGetSystemAddressForMdl(pIrp->MdlAddress); // Win9x
#endif
BytesRemaining = MmGetMdlByteCount(pIrp->MdlAddress);
pNdisBuffer = pRcvPacket->Private.Head;
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);
NUIO_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
{
ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
}
NUIO_DEREF_OPEN(pOpenContext); // took out pended Read
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
pOpenContext->PendedReadCount--;
}
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
NUIO_DEREF_OPEN(pOpenContext); // temp ref - service reads
}
NDIS_STATUS
NdisuioReceive(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID pHeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID pLookaheadBuffer,
IN UINT LookaheadBufferSize,
IN UINT PacketSize
)
/*++
Routine Description:
Our protocol receive handler called by NDIS, typically if we have
a miniport below that doesn't indicate packets.
We make a local packet/buffer copy of this data, queue it up, and
kick off the read service routine.
Arguments:
ProtocolBindingContext - pointer to open context
MacReceiveContext - for use in NdisTransferData
pHeaderBuffer - pointer to data header
HeaderBufferSize - size of the above
pLookaheadBuffer - pointer to buffer containing lookahead data
LookaheadBufferSize - size of the above
PacketSize - size of the entire packet, minus header size.
Return Value:
NDIS_STATUS_NOT_ACCEPTED - if this packet is uninteresting
NDIS_STATUS_SUCCESS - if we processed this successfully
--*/
{
PNDISUIO_OPEN_CONTEXT pOpenContext;
NDIS_STATUS Status;
PNDISUIO_ETH_HEADER pEthHeader;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -