|
|
/***************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name:
RECEIVE.C
Abstract:
Packet and message receive routines
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
Revision History:
5/20/99 : created
Author:
Tom Green
****************************************************************************/
#include "precomp.h"
//
// Some debug stuff, not critical to operation:
//
ULONG RcvFrameAllocs = 0; ULONG RcvTimerCount = 0; ULONG RcvPacketCount = 0; ULONG RcvMaxPackets = 0; ULONG RcvIndicateCount = 0; ULONG RcvReturnCount = 0;
//
// For raw encapsulation test
//
extern ULONG gRawEncap;
/****************************************************************************/ /* RndismpGetReturnedPackets */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* This function is called by NDIS to return to our possession a packet */ /* that we had indicated up. */ /* */ /* Arguments: */ /* */ /* MiniportAdapterContext - a context version of our Adapter pointer */ /* pNdisPacket - the packet that is being freed */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID RndismpReturnPacket(IN NDIS_HANDLE MiniportAdapterContext, IN PNDIS_PACKET pNdisPacket) { PRNDISMP_ADAPTER pAdapter; PRNDISMP_RECV_PKT_RESERVED pRcvResvd; PRNDISMP_RECV_DATA_FRAME pRcvFrame; PRNDISMP_VC pVc; PNDIS_BUFFER pNdisBuffer; ULONG RefCount;
// get adapter context
pAdapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(pAdapter);
TRACE2(("RndismpReturnPacket: Adapter %x, Pkt %x\n", pAdapter, pNdisPacket));
// get receive frame context
pRcvResvd = PRNDISMP_RESERVED_FROM_RECV_PACKET(pNdisPacket); pRcvFrame = pRcvResvd->pRcvFrame; pVc = pRcvResvd->pVc;
// Free the buffer.
NdisQueryPacket(pNdisPacket, NULL, NULL, &pNdisBuffer, NULL); NdisFreeBuffer(pNdisBuffer);
DereferenceRcvFrame(pRcvFrame, pAdapter);
if (pVc != NULL) { RNDISMP_DEREF_VC(pVc, &RefCount); }
NdisFreePacket(pNdisPacket); RcvReturnCount++;
} // RndismpReturnPacket
/****************************************************************************/ /* DereferenceRcvFrame */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Utility routine to deref a receive frame structure, e.g. when a */ /* received packet is returned to us from higher layers. */ /* */ /* Arguments: */ /* */ /* pRcvFrame - Pointer to receive frame to be deref'ed. */ /* pAdapter - Pointer to adapter structure */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID DereferenceRcvFrame(IN PRNDISMP_RECV_DATA_FRAME pRcvFrame, IN PRNDISMP_ADAPTER pAdapter) { ULONG ReturnsPending;
ReturnsPending = NdisInterlockedDecrement(&pRcvFrame->ReturnsPending);
if (ReturnsPending == 0) { TRACE3(("DerefRcvFrame: Adapter %x, Frame %p, uPcontext %x, LocalCopy %d\n", pAdapter, pRcvFrame, pRcvFrame->MicroportMessageContext, pRcvFrame->bMessageCopy));
if (pRcvFrame->bMessageCopy) { FreeRcvMessageCopy(pRcvFrame->pLocalMessageCopy); } else { TRACE3(("DerefRcvFrame: uP MDL %x, uPContext %x\n", pRcvFrame->pMicroportMdl, pRcvFrame->MicroportMessageContext));
RNDISMP_RETURN_TO_MICROPORT(pAdapter, pRcvFrame->pMicroportMdl, pRcvFrame->MicroportMessageContext); }
FreeReceiveFrame(pRcvFrame, pAdapter);
}
} // DereferenceRcvFrame
/****************************************************************************/ /* RndisMIndicateReceive */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Called by microport to indicate receiving RNDIS messages */ /* */ /* Arguments: */ /* */ /* MiniportAdapterContext - a context version of our Adapter pointer */ /* pMdl - pointer to MDL chain describing RNDIS message */ /* MicroportMessageContext - context for message from micorport */ /* ChannelType - channel on which this message arrived (control/data) */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID RndisMIndicateReceive(IN NDIS_HANDLE MiniportAdapterContext, IN PMDL pMdl, IN NDIS_HANDLE MicroportMessageContext, IN RM_CHANNEL_TYPE ChannelType, IN NDIS_STATUS ReceiveStatus) { PRNDISMP_ADAPTER Adapter; PRNDIS_MESSAGE pMessage; BOOLEAN bMessageCopied = FALSE; PRNDISMP_MSG_HANDLER_FUNC pMsgHandlerFunc; BOOLEAN bReturnToMicroport; NDIS_STATUS Status; PRNDISMP_RECV_MSG_CONTEXT pRcvMsg; PMDL pTmpMdl; ULONG TotalLength;
Adapter = PRNDISMP_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
CHECK_VALID_ADAPTER(Adapter);
TRACE2(("RndisIndicateReceive: Adapter %x, Mdl %x\n", Adapter, pMdl));
RNDISMP_ASSERT_AT_DISPATCH(); bReturnToMicroport = TRUE;
#if DBG
NdisInterlockedIncrement(&Adapter->MicroportReceivesOutstanding); #endif
do { //
// Find the total length first.
//
TotalLength = 0; for (pTmpMdl = pMdl; pTmpMdl != NULL; pTmpMdl = RNDISMP_GET_MDL_NEXT(pTmpMdl)) { TotalLength += RNDISMP_GET_MDL_LENGTH(pTmpMdl); }
//
// Check if the entire message is in a single MDL - if not, make a copy
// TBD -- handle multi-MDL messages without copying.
//
if ((RNDISMP_GET_MDL_NEXT(pMdl) == NULL) && (!Adapter->bRunningOnWin9x || (ReceiveStatus != NDIS_STATUS_RESOURCES))) { pMessage = RNDISMP_GET_MDL_ADDRESS(pMdl); if (pMessage == NULL) { TRACE0(("RndisMIndicateReceive: Adapter %x: failed to" " access msg from MDL %x\n", Adapter, pMdl)); break; } } else { pMessage = CoalesceMultiMdlMessage(pMdl, TotalLength); if (pMessage == NULL) { break; } bMessageCopied = TRUE; }
TRACEDUMP(("Received msg (%d bytes):\n", TotalLength), pMessage, TotalLength);
// get timer tick for this message
NdisGetSystemUpTime(&Adapter->LastMessageFromDevice);
if (Adapter->bRunningOnWin9x) { Status = MemAlloc(&pRcvMsg, sizeof(RNDISMP_RECV_MSG_CONTEXT));
if (Status != NDIS_STATUS_SUCCESS) { bReturnToMicroport = TRUE; TRACE1(("RndisMIndicateReceive: Adapter %x, failed to alloc rcv msg\n", Adapter)); break; }
pRcvMsg->MicroportMessageContext = MicroportMessageContext; pRcvMsg->pMdl = pMdl; pRcvMsg->TotalLength = TotalLength; pRcvMsg->pMessage = pMessage; pRcvMsg->ReceiveStatus = ReceiveStatus; pRcvMsg->bMessageCopied = bMessageCopied; pRcvMsg->ChannelType = ChannelType;
//
// Queue all packets for indicating receives up to protocols.
// We do this rather than indicate packets directly because
// we are in a DPC context, and need to be in a "global event"
// context to make the upper layers happy. One way to be in a
// global event context is to be in the context of an NDIS timer
// callback function.
//
// So, queue this up on the adapter and start a timer
// routine if necessary.
//
bReturnToMicroport = FALSE;
RNDISMP_ACQUIRE_ADAPTER_LOCK(Adapter);
InsertTailList(&Adapter->PendingRcvMessageList, &pRcvMsg->Link);
if (!Adapter->IndicatingReceives) { Adapter->IndicatingReceives = TRUE;
NdisSetTimer(&Adapter->IndicateTimer, 0); }
RNDISMP_RELEASE_ADAPTER_LOCK(Adapter); } else { //
// Running on NT.
if ((Adapter->DeviceFlags & RNDIS_DF_RAW_DATA) || (gRawEncap)) { if (ChannelType == RMC_CONTROL) { RNDISMP_GET_MSG_HANDLER(pMsgHandlerFunc,pMessage->NdisMessageType); #if DBG
ASSERT(pMessage->NdisMessageType != REMOTE_NDIS_PACKET_MSG); #endif
} else { pMsgHandlerFunc = ReceivePacketMessageRaw; } } else { RNDISMP_GET_MSG_HANDLER(pMsgHandlerFunc, pMessage->NdisMessageType); #if DBG
if (pMessage->NdisMessageType == REMOTE_NDIS_PACKET_MSG) { ASSERT(ChannelType == RMC_DATA); } else { ASSERT(ChannelType == RMC_CONTROL); } #endif
}
bReturnToMicroport = (*pMsgHandlerFunc)( Adapter, pMessage, pMdl, TotalLength, MicroportMessageContext, ReceiveStatus, bMessageCopied); } } while (FALSE);
//
// Are we done with the microport's message?
//
if (bReturnToMicroport || bMessageCopied) { RNDISMP_RETURN_TO_MICROPORT(Adapter, pMdl, MicroportMessageContext); }
//
// If we had made a copy of the microport's message, are we done with
// this copy?
//
if (bMessageCopied && bReturnToMicroport) { FreeRcvMessageCopy(pMessage); } }
/****************************************************************************/ /* CoalesceMultiMdlMessage */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Make a copy of a received message that is in a chain of multiple */ /* MDLs, into one single buffer. */ /* */ /* Arguments: */ /* */ /* pMdl - pointer to MDL that is the head of the chain. */ /* TotalLength - length of data contained in entire chain. */ /* */ /* Return: */ /* */ /* PRNDIS_MESSAGE */ /* */ /****************************************************************************/ PRNDIS_MESSAGE CoalesceMultiMdlMessage(IN PMDL pMdl, IN ULONG TotalLength) { ULONG MdlLength; PRNDIS_MESSAGE pMessage; NDIS_STATUS Status; PMDL pTmpMdl; PUCHAR pDest;
TRACE2(("Coalesce: Mdl %x\n", pMdl));
Status = MemAlloc(&pMessage, TotalLength);
if (Status == NDIS_STATUS_SUCCESS) { pDest = (PUCHAR)pMessage; for (pTmpMdl = pMdl; pTmpMdl != NULL; pTmpMdl = RNDISMP_GET_MDL_NEXT(pTmpMdl)) { MdlLength = RNDISMP_GET_MDL_LENGTH(pTmpMdl); RNDISMP_MOVE_MEM(pDest, RNDISMP_GET_MDL_ADDRESS(pTmpMdl), MdlLength); pDest = (PUCHAR)pDest + MdlLength; } } else { pMessage = NULL; }
return (pMessage); }
/****************************************************************************/ /* FreeRcvMessageCopy */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Free the local copy of a received RNDIS message. */ /* */ /* Arguments: */ /* */ /* pMessage - pointer to RNDIS message */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID FreeRcvMessageCopy(IN PRNDIS_MESSAGE pMessage) { TRACE3(("FreeRcvMessageCopy: pMessage %x\n", pMessage)); MemFree(pMessage, -1); }
/****************************************************************************/ /* ReceivePacketMessage */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Got a packet message, so send it to the upper layers */ /* */ /* Arguments: */ /* */ /* pAdapter - pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - pointer to MDL received from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from micorport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN ReceivePacketMessage(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { ULONG LengthRemaining; // in entire message
PMDL pTmpMdl; PRNDISMP_RECV_DATA_FRAME pRcvFrame; ULONG NumberOfPackets; PRNDIS_PACKET pRndisPacket; ULONG i; #define MAX_RECV_PACKETS_IN_MSG 40
PNDIS_PACKET PacketArray[MAX_RECV_PACKETS_IN_MSG]; ULONG NumPackets;
PNDIS_PACKET pNdisPacket; PRNDISMP_RECV_PKT_RESERVED pRcvResvd; PNDIS_BUFFER pNdisBuffer; NDIS_STATUS BufferStatus; NDIS_STATUS Status; BOOLEAN bDiscardPkt; PRNDISMP_VC pVc;
bDiscardPkt = FALSE; pVc = NULL;
do { #ifndef BUILD_WIN9X
if (bMessageCopied) { ReceiveStatus = NDIS_STATUS_SUCCESS; } #else
//
// Rur ReturnPacket handler never gets called on
// Win98 Gold, so we force the status to be able
// to reclaim the indicated packet immediately.
//
ReceiveStatus = NDIS_STATUS_RESOURCES; #endif
//
// Allocate a receive frame to keep track of this RNDIS packet message.
//
pRcvFrame = AllocateReceiveFrame(pAdapter);
if (pRcvFrame == NULL) { bDiscardPkt = TRUE; break; }
pRcvFrame->MicroportMessageContext = MicroportMessageContext; if (bMessageCopied) { pRcvFrame->pLocalMessageCopy = pMessage; pRcvFrame->bMessageCopy = TRUE; } else { pRcvFrame->pMicroportMdl = pMdl; pRcvFrame->bMessageCopy = FALSE; }
NumberOfPackets = 0;
LengthRemaining = TotalLength;
//
// TBD - Check that the received message is well-formed!
//
//
// Temp ref to take care of multiple indications.
//
pRcvFrame->ReturnsPending = 1;
//
// Prepare NDIS packets for indicating up.
//
do { pRndisPacket = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
//
// Some sanity checks. TBD - do better checks!
//
if ((pMessage->MessageLength > LengthRemaining) || (pMessage->NdisMessageType != REMOTE_NDIS_PACKET_MSG) || (pMessage->MessageLength < RNDIS_MESSAGE_SIZE(RNDIS_PACKET))) { TRACE1(("ReceivePacketMessage: Msg %x: length %d or type %x has a problem\n", pMessage, pMessage->MessageLength, pMessage->NdisMessageType)); ASSERT(FALSE); RNDISMP_INCR_STAT(pAdapter, RecvError); break; }
if (pRndisPacket->DataLength > pMessage->MessageLength) { TRACE1(("ReceivePacketMessage: invalid data length (%d) > Msg length (%d)\n", pRndisPacket->DataLength, pMessage->MessageLength)); RNDISMP_INCR_STAT(pAdapter, RecvError); break; }
if (pRndisPacket->VcHandle != 0) { pVc = LookupVcId(pAdapter, pRndisPacket->VcHandle); if (pVc == NULL) { TRACE1(("ReceivePacketMessage: invalid Vc handle %x\n", pRndisPacket->VcHandle)); RNDISMP_INCR_STAT(pAdapter, RecvError); break; } }
//
// Allocate an NDIS packet to do the indication with.
//
NdisAllocatePacket(&Status, &pNdisPacket, pAdapter->ReceivePacketPool); if (Status != NDIS_STATUS_SUCCESS) { pNdisPacket = NULL;
TRACE2(("ReceivePacketMessage: failed to allocate packet, Adapter %X\n", pAdapter));
RNDISMP_INCR_STAT(pAdapter, RecvNoBuf); break; }
NDIS_SET_PACKET_STATUS(pNdisPacket, ReceiveStatus);
switch (pAdapter->Medium) { case NdisMedium802_3: NDIS_SET_PACKET_HEADER_SIZE(pNdisPacket, ETHERNET_HEADER_SIZE); break; default: break; }
NdisAllocateBuffer(&BufferStatus, &pNdisBuffer, pAdapter->ReceiveBufferPool, GET_PTR_TO_RNDIS_DATA_BUFF(pRndisPacket), pRndisPacket->DataLength);
if (BufferStatus != NDIS_STATUS_SUCCESS) { TRACE1(("ReceivePacketMessage: failed to allocate" " buffer, Adapter %X\n", pAdapter)); NdisFreePacket(pNdisPacket); RNDISMP_INCR_STAT(pAdapter, RecvNoBuf); break; }
TRACE2(("Rcv: msg Pkt %d bytes\n", pRndisPacket->DataLength)); TRACEDUMP(("Rcv %d bytes\n", pRndisPacket->DataLength), GET_PTR_TO_RNDIS_DATA_BUFF(pRndisPacket), MIN(pRndisPacket->DataLength, 32));
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Check if there is per-packet info.
//
if (!pAdapter->bRunningOnWin9x) { PRNDIS_PER_PACKET_INFO pPerPacketInfo; ULONG PerPacketInfoLength;
if (PerPacketInfoLength = pRndisPacket->PerPacketInfoLength) { TRACE1(("ReceivePacketMessage: Adapter %p, Pkt %p:" " non-zero perpacket length %d\n", pAdapter, pRndisPacket, PerPacketInfoLength));
pPerPacketInfo = (PRNDIS_PER_PACKET_INFO)((PUCHAR)pRndisPacket + pRndisPacket->PerPacketInfoOffset);
while (PerPacketInfoLength != 0) { switch (pPerPacketInfo->Type) { case TcpIpChecksumPacketInfo: NDIS_PER_PACKET_INFO_FROM_PACKET(pNdisPacket, TcpIpChecksumPacketInfo) = UlongToPtr(*(PULONG)((PUCHAR)pPerPacketInfo + pPerPacketInfo->PerPacketInformationOffset)); break;
case Ieee8021pPriority: NDIS_PER_PACKET_INFO_FROM_PACKET(pNdisPacket, Ieee8021pPriority) = UlongToPtr(*(PULONG)((PUCHAR)pPerPacketInfo + pPerPacketInfo->PerPacketInformationOffset));
default: break; } PerPacketInfoLength -= pPerPacketInfo->Size; pPerPacketInfo = (PRNDIS_PER_PACKET_INFO)((PUCHAR)pPerPacketInfo + pPerPacketInfo->Size); } } }
//
// Add this to the array of packets to be indicated up.
//
PacketArray[NumberOfPackets] = pNdisPacket; NumberOfPackets++; RNDISMP_INCR_STAT(pAdapter, RecvOk);
pRcvResvd = PRNDISMP_RESERVED_FROM_RECV_PACKET(pNdisPacket); pRcvResvd->pRcvFrame = pRcvFrame; pRcvResvd->pVc = pVc;
TRACE2(("ReceivePacketMessage: pRndisPkt %X, MsgLen %d," " DataLen %d, Stat %x, Discard %d\n", pRndisPacket, pMessage->MessageLength, pRndisPacket->DataLength, ReceiveStatus, bDiscardPkt));
LengthRemaining -= pMessage->MessageLength; pMessage = (PRNDIS_MESSAGE)((ULONG_PTR)pMessage + pMessage->MessageLength);
NdisInterlockedIncrement(&pRcvFrame->ReturnsPending);
if ((NumberOfPackets == MAX_RECV_PACKETS_IN_MSG) || (LengthRemaining < RNDIS_MESSAGE_SIZE(RNDIS_PACKET))) { if (pVc == NULL) { RcvIndicateCount += NumberOfPackets; NdisMIndicateReceivePacket(pAdapter->MiniportAdapterHandle, PacketArray, NumberOfPackets); } else { IndicateReceiveDataOnVc(pVc, PacketArray, NumberOfPackets); } if (ReceiveStatus == NDIS_STATUS_RESOURCES) { for (i = 0; i < NumberOfPackets; i++) { RNDISMP_INCR_STAT(pAdapter, RecvLowRes); RndismpReturnPacket(pAdapter, PacketArray[i]); } }
NumberOfPackets = 0; } } while (LengthRemaining >= RNDIS_MESSAGE_SIZE(RNDIS_PACKET));
if (NumberOfPackets != 0) { //
// We bailed out of the above loop. Return what we
// have collected so far.
//
for (i = 0; i < NumberOfPackets; i++) { RndismpReturnPacket(pAdapter, PacketArray[i]); } }
//
// Remove temp ref we added at the top.
//
DereferenceRcvFrame(pRcvFrame, pAdapter); } while (FALSE);
if (pVc != NULL) { ULONG RefCount;
RNDISMP_DEREF_VC(pVc, &RefCount); }
return (bDiscardPkt); }
/****************************************************************************/ /* ReceivePacketMessageRaw */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Got a packet message, so send it to the upper layers */ /* */ /* Arguments: */ /* */ /* pAdapter - pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - pointer to MDL received from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from micorport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN ReceivePacketMessageRaw(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { ULONG LengthRemaining; // in entire message
PMDL pTmpMdl; PRNDISMP_RECV_DATA_FRAME pRcvFrame; ULONG NumberOfPackets; PRNDIS_PACKET pRndisPacket; ULONG i; #define MAX_RECV_PACKETS_IN_MSG 40
PNDIS_PACKET PacketArray[MAX_RECV_PACKETS_IN_MSG]; ULONG NumPackets;
PNDIS_PACKET pNdisPacket; PRNDISMP_RECV_PKT_RESERVED pRcvResvd; PNDIS_BUFFER pNdisBuffer; NDIS_STATUS BufferStatus; NDIS_STATUS Status; BOOLEAN bDiscardPkt; PRNDISMP_VC pVc;
bDiscardPkt = FALSE; pVc = NULL; pRcvFrame = NULL;
do { #ifndef BUILD_WIN9X
if (bMessageCopied) { ReceiveStatus = NDIS_STATUS_SUCCESS; } #else
//
// Rur ReturnPacket handler never gets called on
// Win98 Gold, so we force the status to be able
// to reclaim the indicated packet immediately.
//
ReceiveStatus = NDIS_STATUS_RESOURCES; #endif
//
// Allocate a receive frame to keep track of this RNDIS packet message.
//
pRcvFrame = AllocateReceiveFrame(pAdapter);
if (pRcvFrame == NULL) { bDiscardPkt = TRUE; break; }
pRcvFrame->MicroportMessageContext = MicroportMessageContext; if (bMessageCopied) { pRcvFrame->pLocalMessageCopy = pMessage; pRcvFrame->bMessageCopy = TRUE; } else { pRcvFrame->pMicroportMdl = pMdl; pRcvFrame->bMessageCopy = FALSE; }
NumberOfPackets = 0;
LengthRemaining = TotalLength;
//
// Temp ref to take care of multiple indications.
//
pRcvFrame->ReturnsPending = 1;
//
// Prepare NDIS packets for indicating up.
//
{ pRndisPacket = RNDIS_MESSAGE_RAW_PTR_TO_MESSAGE_PTR(pMessage);
//
// Allocate an NDIS packet to do the indication with.
//
NdisAllocatePacket(&Status, &pNdisPacket, pAdapter->ReceivePacketPool); if (Status != NDIS_STATUS_SUCCESS) { pNdisPacket = NULL;
TRACE2(("ReceivePacketMessage: failed to allocate packet, Adapter %X\n", pAdapter));
RNDISMP_INCR_STAT(pAdapter, RecvNoBuf); bDiscardPkt = TRUE; break; }
NDIS_SET_PACKET_STATUS(pNdisPacket, ReceiveStatus);
switch (pAdapter->Medium) { case NdisMedium802_3: NDIS_SET_PACKET_HEADER_SIZE(pNdisPacket, ETHERNET_HEADER_SIZE); break; default: break; }
NdisAllocateBuffer(&BufferStatus, &pNdisBuffer, pAdapter->ReceiveBufferPool, pRndisPacket, TotalLength);
if (BufferStatus != NDIS_STATUS_SUCCESS) { TRACE1(("ReceivePacketMessage: failed to allocate" " buffer, Adapter %X\n", pAdapter)); NdisFreePacket(pNdisPacket); RNDISMP_INCR_STAT(pAdapter, RecvNoBuf); bDiscardPkt = TRUE; break; }
TRACE2(("Rcv: msg Pkt %d bytes\n", pMessage->MessageLength)); TRACEDUMP(("Rcv %d bytes\n", pMessage->MessageLength), pRndisPacket, MIN(pMessage->MessageLength, 32));
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Add this to the array of packets to be indicated up.
//
PacketArray[NumberOfPackets] = pNdisPacket; NumberOfPackets++; RNDISMP_INCR_STAT(pAdapter, RecvOk);
pRcvResvd = PRNDISMP_RESERVED_FROM_RECV_PACKET(pNdisPacket); pRcvResvd->pRcvFrame = pRcvFrame; pRcvResvd->pVc = pVc;
TRACE1(("ReceivePacketMessageRaw: pRcvFrame %p/%d, pRndisPkt %p," " DataLen %d, Stat %x, Discard %d\n", pRcvFrame, pRcvFrame->ReturnsPending, pRndisPacket, pRndisPacket->DataLength, ReceiveStatus, bDiscardPkt));
LengthRemaining -= pMessage->MessageLength;
NdisInterlockedIncrement(&pRcvFrame->ReturnsPending);
NdisMIndicateReceivePacket(pAdapter->MiniportAdapterHandle, PacketArray, NumberOfPackets);
if (ReceiveStatus == NDIS_STATUS_RESOURCES) { for (i = 0; i < NumberOfPackets; i++) { RNDISMP_INCR_STAT(pAdapter, RecvLowRes); RndismpReturnPacket(pAdapter, PacketArray[i]); } }
}
//
// Remove temp ref we added at the top.
//
DereferenceRcvFrame(pRcvFrame, pAdapter); } while (FALSE);
if (bDiscardPkt) { //
// Some failure occured above.
//
if (pRcvFrame != NULL) { FreeReceiveFrame(pRcvFrame, pAdapter); } }
return (bDiscardPkt); }
/****************************************************************************/ /* IndicateStatusMessage */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Got an indicate status message, so send to upper layers */ /* */ /* Arguments: */ /* */ /* pAdapter - Pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - Pointer to MDL from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from microport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN IndicateStatusMessage(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { PRNDIS_INDICATE_STATUS pRndisIndicateStatus;
TRACE3(("IndicateStatusMessage: Adapter %x, Mdl %x\n", pAdapter, pMdl));
// get a pointer to the indicate status message
pRndisIndicateStatus = RNDIS_MESSAGE_PTR_TO_MESSAGE_PTR(pMessage);
if (!pAdapter->Initing) { #if DBG
if (pRndisIndicateStatus->Status == NDIS_STATUS_MEDIA_CONNECT) { TRACE1(("Adapter %x: +++ Media Connect +++\n", pAdapter)); } else if (pRndisIndicateStatus->Status == NDIS_STATUS_MEDIA_DISCONNECT) { TRACE1(("Adapter %x: --- Media Disconnect ---\n", pAdapter)); } #endif // DBG
// send status indication to upper layers
NdisMIndicateStatus(pAdapter->MiniportAdapterHandle, (NDIS_STATUS) pRndisIndicateStatus->Status, MESSAGE_TO_STATUS_BUFFER(pRndisIndicateStatus), pRndisIndicateStatus->StatusBufferLength);
// always have to indicate status complete
NdisMIndicateStatusComplete(pAdapter->MiniportAdapterHandle); } else { //
// drop status indications that arrive when we are
// in the process of initializing.
//
TRACE1(("Adapter %x: indicated status %x when still initializing\n", pAdapter, (NDIS_STATUS) pRndisIndicateStatus->Status)); }
return (TRUE); } // IndicateStatusMessage
/****************************************************************************/ /* UnknownMessage */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Process a message with unknown message type. We simply drop it for now. */ /* */ /* Arguments: */ /* */ /* pAdapter - Pointer to our Adapter structure */ /* pMessage - pointer to RNDIS message */ /* pMdl - Pointer to MDL from microport */ /* TotalLength - length of complete message */ /* MicroportMessageContext - context for message from microport */ /* ReceiveStatus - used by microport to indicate it is low on resource */ /* bMessageCopied - is this a copy of the original message? */ /* */ /* Return: */ /* */ /* BOOLEAN - should the message be returned to the microport? */ /* */ /****************************************************************************/ BOOLEAN UnknownMessage(IN PRNDISMP_ADAPTER pAdapter, IN PRNDIS_MESSAGE pMessage, IN PMDL pMdl, IN ULONG TotalLength, IN NDIS_HANDLE MicroportMessageContext, IN NDIS_STATUS ReceiveStatus, IN BOOLEAN bMessageCopied) { TRACE1(("Unknown Message on Adapter %x, type %x, MDL %x, uPContext %x\n", pAdapter, pMessage->NdisMessageType, pMdl, MicroportMessageContext));
ASSERT(FALSE); return TRUE; }
/****************************************************************************/ /* AllocateReceiveFrame */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Allocate a receive frame to keep context about a single RNDIS_PACKET */ /* message. */ /* */ /* Arguments: */ /* */ /* pAdapter - Pointer to our Adapter structure */ /* */ /* Return: */ /* */ /* PRNDISMP_RECV_DATA_FRAME */ /* */ /****************************************************************************/ PRNDISMP_RECV_DATA_FRAME AllocateReceiveFrame(IN PRNDISMP_ADAPTER pAdapter) { PRNDISMP_RECV_DATA_FRAME pRcvFrame;
#ifndef DONT_USE_LOOKASIDE_LIST
pRcvFrame = (PRNDISMP_RECV_DATA_FRAME) NdisAllocateFromNPagedLookasideList(&pAdapter->RcvFramePool); #else
{ NDIS_STATUS Status;
Status = MemAlloc(&pRcvFrame, sizeof(RNDISMP_RECV_DATA_FRAME));
if (Status == NDIS_STATUS_SUCCESS) { NdisInterlockedIncrement(&RcvFrameAllocs); } else { pRcvFrame = NULL; } } #endif // DONT_USE_LOOKASIDE_LIST
return (pRcvFrame); }
/****************************************************************************/ /* FreeReceiveFrame */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Allocate a receive frame to keep context about a single RNDIS_PACKET */ /* message. */ /* */ /* Arguments: */ /* */ /* pRcvFrame - Pointer to receive frame being freed */ /* pAdapter - Pointer to our Adapter structure */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID FreeReceiveFrame(IN PRNDISMP_RECV_DATA_FRAME pRcvFrame, IN PRNDISMP_ADAPTER pAdapter) { #ifndef DONT_USE_LOOKASIDE_LIST
NdisFreeToNPagedLookasideList(&pAdapter->RcvFramePool, pRcvFrame); #else
MemFree(pRcvFrame, sizeof(RNDISMP_RECV_DATA_FRAME)); NdisInterlockedDecrement(&RcvFrameAllocs); #endif // DONT_USE_LOOKASIDE_LIST
}
/****************************************************************************/ /* IndicateTimeout */ /****************************************************************************/ /* */ /* Routine Description: */ /* */ /* Timeout callback routine to handle all receive indications. The actual */ /* NDIS routines to indicate receives is done from here, since this */ /* function runs in the right environment for protocols on WinME. */ /* */ /* Arguments: */ /* */ /* SystemSpecific[1-3] - Ignored */ /* Context - Pointer to our Adapter structure */ /* */ /* Return: */ /* */ /* VOID */ /* */ /****************************************************************************/ VOID IndicateTimeout(IN PVOID SystemSpecific1, IN PVOID Context, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3) { PRNDISMP_ADAPTER pAdapter; PLIST_ENTRY pEntry; PRNDISMP_RECV_MSG_CONTEXT pRcvMsg; PRNDISMP_MSG_HANDLER_FUNC pMsgHandlerFunc; PRNDIS_MESSAGE pMessage; BOOLEAN bMessageCopied; BOOLEAN bReturnToMicroport; ULONG CurMsgs;
pAdapter = (PRNDISMP_ADAPTER)Context; CHECK_VALID_ADAPTER(pAdapter);
ASSERT(pAdapter->IndicatingReceives == TRUE);
CurMsgs = 0; RcvTimerCount++;
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter);
while (!IsListEmpty(&pAdapter->PendingRcvMessageList)) { pEntry = RemoveHeadList(&pAdapter->PendingRcvMessageList);
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
CurMsgs++;
pRcvMsg = CONTAINING_RECORD(pEntry, RNDISMP_RECV_MSG_CONTEXT, Link);
RNDISMP_GET_MSG_HANDLER(pMsgHandlerFunc, pRcvMsg->pMessage->NdisMessageType);
bMessageCopied = pRcvMsg->bMessageCopied; pMessage = pRcvMsg->pMessage;
bReturnToMicroport = (*pMsgHandlerFunc)( pAdapter, pMessage, pRcvMsg->pMdl, pRcvMsg->TotalLength, pRcvMsg->MicroportMessageContext, pRcvMsg->ReceiveStatus, bMessageCopied);
//
// Are we done with the message?
//
if (bReturnToMicroport) { if (!bMessageCopied) { RNDISMP_RETURN_TO_MICROPORT(pAdapter, pRcvMsg->pMdl, pRcvMsg->MicroportMessageContext); } else { FreeRcvMessageCopy(pMessage); } }
MemFree(pRcvMsg, sizeof(RNDISMP_RECV_MSG_CONTEXT));
RNDISMP_ACQUIRE_ADAPTER_LOCK(pAdapter); }
pAdapter->IndicatingReceives = FALSE;
RcvMaxPackets = MAX(RcvMaxPackets, CurMsgs);
RNDISMP_RELEASE_ADAPTER_LOCK(pAdapter);
} // IndicateTimeout
|