📄 recv.c
字号:
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
--*/
{
PNDISPROT_OPEN_CONTEXT pOpenContext;
NDIS_STATUS Status;
PNDIS_PACKET pRcvPacket;
PUCHAR pRcvData;
UINT BytesTransferred;
PNDIS_BUFFER pOriginalNdisBuffer, pPartialNdisBuffer;
pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
NPROT_STRUCT_ASSERT(pOpenContext, oc);
pRcvPacket = NULL;
pRcvData = NULL;
Status = NDIS_STATUS_SUCCESS;
do
{
if (HeaderBufferSize != sizeof(NDISPROT_ETH_HEADER))
{
Status = NDIS_STATUS_NOT_ACCEPTED;
break;
}
//
// Allocate resources for queueing this up.
//
pRcvPacket = ndisprotAllocateReceivePacket(
pOpenContext,
PacketSize + HeaderBufferSize,
&pRcvData
);
if (pRcvPacket == NULL)
{
Status = NDIS_STATUS_NOT_ACCEPTED;
break;
}
NdisMoveMappedMemory(pRcvData, pHeaderBuffer, HeaderBufferSize);
//
// Check if the entire packet is within the lookahead.
//
if (PacketSize == LookaheadBufferSize)
{
NdisCopyLookaheadData(pRcvData+HeaderBufferSize,
pLookaheadBuffer,
LookaheadBufferSize,
pOpenContext->MacOptions);
//
// Queue this up for receive processing, and
// try to complete some read IRPs.
//
ndisprotQueueReceivePacket(pOpenContext, pRcvPacket);
}
else
{
//
// Allocate an NDIS buffer to map the receive area
// at an offset "HeaderBufferSize" from the current
// start. This is so that NdisTransferData can copy
// in at the right point in the destination buffer.
//
NdisAllocateBuffer(
&Status,
&pPartialNdisBuffer,
pOpenContext->RecvBufferPool,
pRcvData + HeaderBufferSize,
PacketSize);
if (Status == NDIS_STATUS_SUCCESS)
{
//
// Unlink and save away the original NDIS Buffer
// that maps the full receive buffer.
//
NdisUnchainBufferAtFront(pRcvPacket, &pOriginalNdisBuffer);
NPROT_RCV_PKT_TO_ORIGINAL_BUFFER(pRcvPacket) = pOriginalNdisBuffer;
//
// Link in the partial buffer for NdisTransferData to
// operate on.
//
NdisChainBufferAtBack(pRcvPacket, pPartialNdisBuffer);
DEBUGP(DL_LOUD, ("Receive: setting up for TransferData:"
" Pkt %p, OriginalBuf %p, PartialBuf %p\n",
pRcvPacket, pOriginalNdisBuffer, pPartialNdisBuffer));
NdisTransferData(
&Status,
pOpenContext->BindingHandle,
MacReceiveContext,
0, // ByteOffset
PacketSize,
pRcvPacket,
&BytesTransferred);
}
else
{
//
// Failure handled below in TransferDataComplete.
//
BytesTransferred = 0;
}
if (Status != NDIS_STATUS_PENDING)
{
NdisProtTransferDataComplete(
(NDIS_HANDLE)pOpenContext,
pRcvPacket,
Status,
BytesTransferred);
}
}
}
while (FALSE);
DEBUGP(DL_LOUD, ("Receive: Open %p, Pkt %p, Size %d\n",
pOpenContext, pRcvPacket, PacketSize));
return Status;
}
VOID
NdisProtTransferDataComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pNdisPacket,
IN NDIS_STATUS TransferStatus,
IN UINT BytesTransferred
)
/*++
Routine Description:
NDIS entry point called to signal completion of a call to
NdisTransferData that had pended.
Arguments:
ProtocolBindingContext - pointer to open context
pNdisPacket - our receive packet into which data is transferred
TransferStatus - status of the transfer
BytesTransferred - bytes copied into the packet.
Return Value:
None
--*/
{
PNDISPROT_OPEN_CONTEXT pOpenContext;
PNDIS_BUFFER pOriginalBuffer, pPartialBuffer;
UNREFERENCED_PARAMETER(BytesTransferred);
pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
NPROT_STRUCT_ASSERT(pOpenContext, oc);
//
// Check if an NDIS_BUFFER was created to map part of the receive buffer;
// if so, free it and link back the original NDIS_BUFFER that maps
// the full receive buffer to the packet.
//
pOriginalBuffer = NPROT_RCV_PKT_TO_ORIGINAL_BUFFER(pNdisPacket);
if (pOriginalBuffer != NULL)
{
//
// We had stashed off the NDIS_BUFFER for the full receive
// buffer in the packet reserved area. Unlink the partial
// buffer and link in the full buffer.
//
NdisUnchainBufferAtFront(pNdisPacket, &pPartialBuffer);
NdisChainBufferAtBack(pNdisPacket, pOriginalBuffer);
DEBUGP(DL_LOUD, ("TransferComp: Pkt %p, OrigBuf %p, PartialBuf %p\n",
pNdisPacket, pOriginalBuffer, pPartialBuffer));
//
// Free up the partial buffer.
//
NdisFreeBuffer(pPartialBuffer);
}
if (TransferStatus == NDIS_STATUS_SUCCESS)
{
//
// Queue this up for receive processing, and
// try to complete some read IRPs.
//
ndisprotQueueReceivePacket(pOpenContext, pNdisPacket);
}
else
{
ndisprotFreeReceivePacket(pOpenContext, pNdisPacket);
}
}
VOID
NdisProtReceiveComplete(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++
Routine Description:
Protocol entry point called by NDIS when the miniport
has finished indicating up a batch of receives.
We ignore this.
Arguments:
ProtocolBindingContext - pointer to open context
Return Value:
None
--*/
{
PNDISPROT_OPEN_CONTEXT pOpenContext;
pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
NPROT_STRUCT_ASSERT(pOpenContext, oc);
return;
}
INT
NdisProtReceivePacket(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Protocol entry point called by NDIS if the driver below
uses NDIS 4 style receive packet indications.
If the miniport allows us to hold on to this packet, we
use it as is, otherwise we make a copy.
Arguments:
ProtocolBindingContext - pointer to open context
pNdisPacket - the packet being indicated up.
Return Value:
None
--*/
{
PNDISPROT_OPEN_CONTEXT pOpenContext;
PNDIS_BUFFER pNdisBuffer;
UINT BufferLength;
PNDISPROT_ETH_HEADER pEthHeader;
PNDIS_PACKET pCopyPacket;
PUCHAR pCopyBuf;
UINT TotalPacketLength;
UINT BytesCopied;
INT RefCount = 0;
NDIS_STATUS Status;
pOpenContext = (PNDISPROT_OPEN_CONTEXT)ProtocolBindingContext;
NPROT_STRUCT_ASSERT(pOpenContext, oc);
#ifdef NDIS51
NdisGetFirstBufferFromPacketSafe(
pNdisPacket,
&pNdisBuffer,
&pEthHeader,
&BufferLength,
&TotalPacketLength,
NormalPagePriority);
if (pEthHeader == NULL)
{
//
// The system is low on resources. Set up to handle failure
// below.
//
BufferLength = 0;
}
#else
NdisGetFirstBufferFromPacket(
pNdisPacket,
&pNdisBuffer,
&pEthHeader,
&BufferLength,
&TotalPacketLength);
#endif
do
{
if (BufferLength < sizeof(NDISPROT_ETH_HEADER))
{
DEBUGP(DL_WARN,
("ReceivePacket: Open %p, runt pkt %p, first buffer length %d\n",
pOpenContext, pNdisPacket, BufferLength));
Status = NDIS_STATUS_NOT_ACCEPTED;
break;
}
DEBUGP(DL_LOUD, ("ReceivePacket: Open %p, interesting pkt %p\n",
pOpenContext, pNdisPacket));
//
// If the miniport is out of resources, we can't queue
// this packet - make a copy if this is so.
//
if ((NDIS_GET_PACKET_STATUS(pNdisPacket) == NDIS_STATUS_RESOURCES) ||
pOpenContext->bRunningOnWin9x)
{
pCopyPacket = ndisprotAllocateReceivePacket(
pOpenContext,
TotalPacketLength,
&pCopyBuf
);
if (pCopyPacket == NULL)
{
DEBUGP(DL_FATAL, ("ReceivePacket: Open %p, failed to"
" alloc copy, %d bytes\n", pOpenContext, TotalPacketLength));
break;
}
NdisCopyFromPacketToPacket(
pCopyPacket,
0,
TotalPacketLength,
pNdisPacket,
0,
&BytesCopied);
NPROT_ASSERT(BytesCopied == TotalPacketLength);
pNdisPacket = pCopyPacket;
}
else
{
//
// We can queue the original packet - return
// a packet reference count indicating that
// we will call NdisReturnPackets when we are
// done with this packet.
//
RefCount = 1;
}
//
// Queue this up and service any pending Read IRPs.
//
ndisprotQueueReceivePacket(pOpenContext, pNdisPacket);
}
while (FALSE);
return (RefCount);
}
VOID
ndisprotQueueReceivePacket(
IN PNDISPROT_OPEN_CONTEXT pOpenContext,
IN PNDIS_PACKET pRcvPacket
)
/*++
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -