📄 recv.c
字号:
)
/*++
Routine Description:
Queue up a received packet on the open context structure.
If the queue size goes beyond a water mark, discard a packet
at the head of the queue.
Finally, run the queue service routine.
Arguments:
pOpenContext - pointer to open context
pRcvPacket - the received packet
Return Value:
None
--*/
{
PLIST_ENTRY pEnt;
PLIST_ENTRY pDiscardEnt;
PNDIS_PACKET pDiscardPkt;
do
{
pEnt = NUIO_RCV_PKT_TO_LIST_ENTRY(pRcvPacket);
NUIO_REF_OPEN(pOpenContext); // queued rcv packet
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
//
// Check if the binding is in the proper state to receive
// this packet.
//
if (NUIO_TEST_FLAGS(pOpenContext->Flags, NUIOO_BIND_FLAGS, NUIOO_BIND_ACTIVE) &&
(pOpenContext->PowerState == NetDeviceStateD0))
{
NUIO_INSERT_TAIL_LIST(&pOpenContext->RecvPktQueue, pEnt);
pOpenContext->RecvPktCount++;
DEBUGP(DL_VERY_LOUD, ("QueueReceivePacket: open %p,"
" queued pkt %p, queue size %d\n",
pOpenContext, pRcvPacket, pOpenContext->RecvPktCount));
}
else
{
//
// Received this packet when the binding is going away.
// Drop this.
//
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
NUIO_DEREF_OPEN(pOpenContext); // dropped rcv packet - bad state
break;
}
//
// Trim the queue if it has grown too big.
//
if (pOpenContext->RecvPktCount > MAX_RECV_QUEUE_SIZE)
{
//
// Remove the head of the queue.
//
pDiscardEnt = pOpenContext->RecvPktQueue.Flink;
NUIO_REMOVE_ENTRY_LIST(pDiscardEnt);
pOpenContext->RecvPktCount --;
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
pDiscardPkt = NUIO_LIST_ENTRY_TO_RCV_PKT(pDiscardEnt);
ndisuioFreeReceivePacket(pOpenContext, pDiscardPkt);
NUIO_DEREF_OPEN(pOpenContext); // dropped rcv packet - queue too long
DEBUGP(DL_INFO, ("QueueReceivePacket: open %p queue"
" too long, discarded pkt %p\n",
pOpenContext, pDiscardPkt));
}
else
{
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
}
//
// Run the receive queue service routine now.
//
ndisuioServiceReads(pOpenContext);
}
while (FALSE);
}
PNDIS_PACKET
ndisuioAllocateReceivePacket(
IN PNDISUIO_OPEN_CONTEXT pOpenContext,
IN UINT DataLength,
OUT PUCHAR * ppDataBuffer
)
/*++
Routine Description:
Allocate resources to copy and queue a received packet.
Arguments:
pOpenContext - pointer to open context for received packet
DataLength - total length in bytes of the packet
ppDataBuffer - place to return pointer to allocated buffer
Return Value:
Pointer to NDIS packet if successful, else NULL.
--*/
{
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
PUCHAR pDataBuffer;
NDIS_STATUS Status;
pNdisPacket = NULL;
pNdisBuffer = NULL;
pDataBuffer = NULL;
do
{
NUIO_ALLOC_MEM(pDataBuffer, DataLength);
if (pDataBuffer == NULL)
{
DEBUGP(DL_FATAL, ("AllocRcvPkt: open %p, failed to alloc"
" data buffer %d bytes\n", pOpenContext, DataLength));
break;
}
//
// Make this an NDIS buffer.
//
NdisAllocateBuffer(
&Status,
&pNdisBuffer,
pOpenContext->RecvBufferPool,
pDataBuffer,
DataLength);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_FATAL, ("AllocateRcvPkt: open %p, failed to alloc"
" NDIS buffer, %d bytes\n", pOpenContext, DataLength));
break;
}
NdisAllocatePacket(&Status, &pNdisPacket, pOpenContext->RecvPacketPool);
if (Status != NDIS_STATUS_SUCCESS)
{
DEBUGP(DL_FATAL, ("AllocateRcvPkt: open %p, failed to alloc"
" NDIS packet, %d bytes\n", pOpenContext, DataLength));
break;
}
NDIS_SET_PACKET_STATUS(pNdisPacket, 0);
NUIO_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket) = NULL;
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
*ppDataBuffer = pDataBuffer;
break;
}
while (FALSE);
if (pNdisPacket == NULL)
{
//
// Clean up
//
if (pNdisBuffer != NULL)
{
NdisFreeBuffer(pNdisBuffer);
}
if (pDataBuffer != NULL)
{
NUIO_FREE_MEM(pDataBuffer);
}
}
return (pNdisPacket);
}
VOID
ndisuioFreeReceivePacket(
IN PNDISUIO_OPEN_CONTEXT pOpenContext,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Free up all resources associated with a received packet. If this
is a local copy, free the packet to our receive pool, else return
this to the miniport.
Arguments:
pOpenContext - pointer to open context
pNdisPacket - pointer to packet to be freed.
Return Value:
None
--*/
{
PNDIS_BUFFER pNdisBuffer;
UINT TotalLength;
UINT BufferLength;
PUCHAR pCopyData;
if (NdisGetPoolFromPacket(pNdisPacket) == pOpenContext->RecvPacketPool)
{
//
// This is a local copy.
//
#ifdef NDIS51
NdisGetFirstBufferFromPacketSafe(
pNdisPacket,
&pNdisBuffer,
(PVOID *)&pCopyData,
&BufferLength,
&TotalLength,
NormalPagePriority);
#else
NdisGetFirstBufferFromPacket(
pNdisPacket,
&pNdisBuffer,
(PVOID *)&pCopyData,
&BufferLength,
&TotalLength);
#endif
NUIO_ASSERT(BufferLength == TotalLength);
NUIO_ASSERT(pNdisBuffer != NULL);
NUIO_ASSERT(pCopyData != NULL); // we would have allocated non-paged pool
NdisFreePacket(pNdisPacket);
NdisFreeBuffer(pNdisBuffer);
NUIO_FREE_MEM(pCopyData);
}
else
{
NdisReturnPackets(&pNdisPacket, 1);
}
}
VOID
ndisuioCancelPendingReads(
IN PNDISUIO_OPEN_CONTEXT pOpenContext
)
/*++
Routine Description:
Cancel any pending read IRPs queued on the given open.
Arguments:
pOpenContext - pointer to open context
Return Value:
None
--*/
{
PIRP pIrp;
PLIST_ENTRY pIrpEntry;
NUIO_REF_OPEN(pOpenContext); // temp ref - cancel reads
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
while (!NUIO_IS_LIST_EMPTY(&pOpenContext->PendedReads))
{
//
// 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);
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
//
// Complete the IRP.
//
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0;
DEBUGP(DL_INFO, ("CancelPendingReads: Open %p, IRP %p cancelled\n",
pOpenContext, pIrp));
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
NUIO_DEREF_OPEN(pOpenContext); // took out pended Read for cancelling
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
pOpenContext->PendedReadCount--;
}
else
{
//
// It is being cancelled, let the cancel routine handle it.
//
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
//
// Give the cancel routine some breathing space, otherwise
// we might end up examining the same (cancelled) IRP over
// and over again.
//
NUIO_SLEEP(1);
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
}
}
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
NUIO_DEREF_OPEN(pOpenContext); // temp ref - cancel reads
}
VOID
ndisuioFlushReceiveQueue(
IN PNDISUIO_OPEN_CONTEXT pOpenContext
)
/*++
Routine Description:
Free any receive packets queued up on the specified open
Arguments:
pOpenContext - pointer to open context
Return Value:
None
--*/
{
PLIST_ENTRY pRcvPacketEntry;
PNDIS_PACKET pRcvPacket;
NUIO_REF_OPEN(pOpenContext); // temp ref - flushRcvQueue
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
while (!NUIO_IS_LIST_EMPTY(&pOpenContext->RecvPktQueue))
{
//
// Get the first queued receive packet
//
pRcvPacketEntry = pOpenContext->RecvPktQueue.Flink;
NUIO_REMOVE_ENTRY_LIST(pRcvPacketEntry);
pOpenContext->RecvPktCount --;
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
pRcvPacket = NUIO_LIST_ENTRY_TO_RCV_PKT(pRcvPacketEntry);
DEBUGP(DL_LOUD, ("FlushReceiveQueue: open %p, pkt %p\n",
pOpenContext, pRcvPacket));
ndisuioFreeReceivePacket(pOpenContext, pRcvPacket);
NUIO_DEREF_OPEN(pOpenContext); // took out pended Read
NUIO_ACQUIRE_LOCK(&pOpenContext->Lock);
}
NUIO_RELEASE_LOCK(&pOpenContext->Lock);
NUIO_DEREF_OPEN(pOpenContext); // temp ref - flushRcvQueue
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -