2047 lines
40 KiB
C
2047 lines
40 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
D:\nt\private\ntos\tdi\rawwan\core\receive.c
|
|
|
|
Abstract:
|
|
|
|
Routines for receiving data, including TDI and NDIS entry
|
|
points and completions.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 05-16-97 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'VCER'
|
|
|
|
|
|
#if STATS
|
|
|
|
ULONG RecvPktsOk = 0;
|
|
ULONG RecvBytesOk = 0;
|
|
ULONG RecvPktsFail = 0;
|
|
ULONG RecvBytesFail = 0;
|
|
|
|
#endif // STATS
|
|
|
|
#if DBG
|
|
|
|
BOOLEAN bVerifyData = FALSE;
|
|
UCHAR CheckChar = 'X';
|
|
|
|
VOID
|
|
RWanCheckDataForChar(
|
|
IN PCHAR pHelpString,
|
|
IN PVOID Context,
|
|
IN PUCHAR pBuffer,
|
|
IN ULONG Length,
|
|
IN UCHAR Char
|
|
);
|
|
|
|
|
|
#define RWAN_CHECK_DATA(_pHelp, _Ctxt, _pBuf, _Len) \
|
|
{ \
|
|
if (bVerifyData) \
|
|
{ \
|
|
RWanCheckDataForChar(_pHelp, _Ctxt, _pBuf, _Len, CheckChar); \
|
|
} \
|
|
}
|
|
|
|
#else
|
|
|
|
#define RWAN_CHECK_DATA(_pHelp, _Ctxt, _pBuf, _Len)
|
|
|
|
#endif // DBG
|
|
|
|
|
|
#if DBG
|
|
|
|
VOID
|
|
RWanCheckDataForChar(
|
|
IN PCHAR pHelpString,
|
|
IN PVOID Context,
|
|
IN PUCHAR pBuffer,
|
|
IN ULONG Length,
|
|
IN UCHAR Char
|
|
)
|
|
{
|
|
ULONG i;
|
|
PUCHAR pBuf = pBuffer+1;
|
|
|
|
for (i = 1; i < Length; i++)
|
|
{
|
|
if (*pBuf == Char)
|
|
{
|
|
DbgPrint("RAWWAN: %s: %p: Found char %c at offset %d, 0x%p, of buffer 0x%p\n",
|
|
pHelpString,
|
|
Context,
|
|
Char,
|
|
i,
|
|
pBuf,
|
|
pBuffer);
|
|
DbgBreakPoint();
|
|
}
|
|
pBuf++;
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
RWAN_STATUS
|
|
RWanInitReceive(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize our receive structures. We allocate a buffer pool and
|
|
a packet pool for keeping copies of received packets that we aren't
|
|
allowed to keep by the miniport.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
RWAN_STATUS_SUCCESS if initialized successfully, else RWAN_STATUS_RESOURCES.
|
|
|
|
--*/
|
|
{
|
|
RWAN_STATUS RWanStatus;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
RWanCopyPacketPool = NULL;
|
|
RWanCopyBufferPool = NULL;
|
|
RWanStatus = RWAN_STATUS_SUCCESS;
|
|
|
|
NdisAllocatePacketPoolEx(
|
|
&Status,
|
|
&RWanCopyPacketPool,
|
|
RWAN_INITIAL_COPY_PACKET_COUNT,
|
|
RWAN_OVERFLOW_COPY_PACKET_COUNT,
|
|
0
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
RWanStatus = RWAN_STATUS_RESOURCES;
|
|
}
|
|
else
|
|
{
|
|
NdisAllocateBufferPool(
|
|
&Status,
|
|
&RWanCopyBufferPool,
|
|
RWAN_INITIAL_COPY_PACKET_COUNT+RWAN_OVERFLOW_COPY_PACKET_COUNT
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
NdisFreePacketPool(RWanCopyPacketPool);
|
|
RWanCopyPacketPool = NULL;
|
|
|
|
RWanStatus = RWAN_STATUS_RESOURCES;
|
|
}
|
|
}
|
|
|
|
return (RWanStatus);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanShutdownReceive(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is shutdown code, to clean up our receive structures.
|
|
We free the packet pool and buffer pool allocated when we
|
|
init'ed.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (RWanCopyPacketPool != NULL)
|
|
{
|
|
NdisFreePacketPool(RWanCopyPacketPool);
|
|
RWanCopyPacketPool = NULL;
|
|
}
|
|
|
|
if (RWanCopyBufferPool != NULL)
|
|
{
|
|
NdisFreeBufferPool(RWanCopyBufferPool);
|
|
RWanCopyBufferPool = NULL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
TDI_STATUS
|
|
RWanTdiReceive(
|
|
IN PTDI_REQUEST pTdiRequest,
|
|
OUT PUSHORT pFlags,
|
|
IN PUINT pReceiveLength,
|
|
IN PNDIS_BUFFER pNdisBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the TDI Entry point for receiving data over a connection.
|
|
|
|
Arguments:
|
|
|
|
pTdiRequest - Pointer to the TDI Request
|
|
pFlags - Place to return additional information about this
|
|
receive
|
|
pReceiveLength - Points to the total length of the receive buffer chain
|
|
pNdisBuffer - Start of receive buffer chain
|
|
|
|
Return Value:
|
|
|
|
TDI_PENDING if we queued this receive request successfully
|
|
TDI_INVALID_CONNECTION if the Connection context isn't valid
|
|
TDI_NO_RESOURCES if we had a resource problem with this receive
|
|
|
|
--*/
|
|
{
|
|
RWAN_CONN_ID ConnId;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
BOOLEAN bIsLockAcquired; // Do we hold the Conn Object lock
|
|
PRWAN_NDIS_VC pVc;
|
|
TDI_STATUS TdiStatus;
|
|
PRWAN_RECEIVE_REQUEST pRcvReq;
|
|
PRWAN_NDIS_ADAPTER pAdapter;
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
TdiStatus = TDI_PENDING;
|
|
bIsLockAcquired = FALSE;
|
|
ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
|
|
pRcvReq = NULL;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Allocate space to hold context for this receive
|
|
//
|
|
pRcvReq = RWanAllocateReceiveReq();
|
|
if (pRcvReq == NULL)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_WILDCARD,
|
|
("Rcv: Failed to allocate receive req!\n"));
|
|
TdiStatus = TDI_NO_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Prepare the receive request.
|
|
//
|
|
pRcvReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
|
|
pRcvReq->Request.ReqContext = pTdiRequest->RequestContext;
|
|
pRcvReq->TotalBufferLength = *pReceiveLength;
|
|
pRcvReq->AvailableBufferLength = *pReceiveLength;
|
|
pRcvReq->pUserFlags = pFlags;
|
|
pRcvReq->pBuffer = pNdisBuffer;
|
|
NdisQueryBufferSafe(
|
|
pNdisBuffer,
|
|
&(pRcvReq->pWriteData),
|
|
&(pRcvReq->BytesLeftInBuffer),
|
|
NormalPagePriority
|
|
);
|
|
|
|
if (pRcvReq->pWriteData == NULL)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_WILDCARD,
|
|
("Rcv: Failed to query req buffer!\n"));
|
|
TdiStatus = TDI_NO_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pRcvReq->pNextRcvReq = NULL;
|
|
if (pRcvReq->BytesLeftInBuffer > pRcvReq->AvailableBufferLength)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Rcv: pRcvReq %x, BytesLeft %d > Available %d, pTdiRequest %x\n",
|
|
pRcvReq,
|
|
pRcvReq->BytesLeftInBuffer,
|
|
pRcvReq->AvailableBufferLength,
|
|
pTdiRequest));
|
|
pRcvReq->BytesLeftInBuffer = pRcvReq->AvailableBufferLength;
|
|
}
|
|
|
|
//
|
|
// See if the given Connection is valid.
|
|
//
|
|
RWAN_ACQUIRE_CONN_TABLE_LOCK();
|
|
|
|
pConnObject = RWanGetConnFromId(ConnId);
|
|
|
|
RWAN_RELEASE_CONN_TABLE_LOCK();
|
|
|
|
|
|
if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: Invalid connection!\n"));
|
|
TdiStatus = TDI_INVALID_CONNECTION;
|
|
break;
|
|
}
|
|
|
|
bIsLockAcquired = TRUE;
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
//
|
|
// Check the Connection state.
|
|
//
|
|
if ((pConnObject->State != RWANS_CO_CONNECTED) ||
|
|
(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING)))
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("TdiReceive: Conn %x bad state %d/flags %x\n",
|
|
pConnObject, pConnObject->State, pConnObject->Flags));
|
|
|
|
TdiStatus = TDI_INVALID_STATE;
|
|
break;
|
|
}
|
|
|
|
pVc = pConnObject->NdisConnection.pNdisVc;
|
|
RWAN_ASSERT(pVc != NULL);
|
|
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
pAdapter = pVc->pNdisAf->pAdapter;
|
|
|
|
//
|
|
// Queue the receive request at the end of the queue on this VC.
|
|
//
|
|
if (pVc->pRcvReqHead == NULL)
|
|
{
|
|
pVc->pRcvReqHead = pVc->pRcvReqTail = pRcvReq;
|
|
}
|
|
else
|
|
{
|
|
RWAN_ASSERT(pVc->pRcvReqTail != NULL);
|
|
pVc->pRcvReqTail->pNextRcvReq = pRcvReq;
|
|
pVc->pRcvReqTail = pRcvReq;
|
|
}
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Rcv: VC %x, queued RcvReq %x, space available %d bytes\n",
|
|
pVc, pRcvReq, pRcvReq->AvailableBufferLength));
|
|
|
|
//
|
|
// Start the common indicate code (for receive requests as well
|
|
// as for receive indications).
|
|
//
|
|
RWAN_RESET_BIT(pConnObject->Flags, RWANF_CO_PAUSE_RECEIVE);
|
|
|
|
RWanIndicateData(pConnObject);
|
|
|
|
bIsLockAcquired = FALSE;
|
|
|
|
//
|
|
// Force return of any received packets that we have completed
|
|
// processing, to the miniport.
|
|
//
|
|
RWanNdisReceiveComplete((NDIS_HANDLE)pAdapter);
|
|
|
|
break;
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if (bIsLockAcquired)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
|
|
if (TdiStatus != TDI_PENDING)
|
|
{
|
|
//
|
|
// Error - clean up.
|
|
//
|
|
if (pRcvReq != NULL)
|
|
{
|
|
RWanFreeReceiveReq(pRcvReq);
|
|
}
|
|
}
|
|
|
|
return (TdiStatus);
|
|
}
|
|
|
|
|
|
|
|
UINT
|
|
RWanNdisCoReceivePacket(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point announcing arrival of a packet
|
|
on a VC known to us.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - Pointer to our Adapter context
|
|
ProtocolVcContext - Pointer to our VC context
|
|
pNdisPacket - the received packet
|
|
|
|
Return Value:
|
|
|
|
UINT - this is the reference count we place on the packet.
|
|
This is 0 if we either dropped the packet, or if the miniport
|
|
had marked the packet with NDIS_STATUS_RESOURCES. Otherwise,
|
|
this is 1 (we queue the packet and will call NdisReturnPackets
|
|
later).
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
UINT PacketRefCount;
|
|
NDIS_STATUS ReceiveStatus;
|
|
PRWAN_RECEIVE_INDICATION pRcvInd;
|
|
BOOLEAN bIsMiniportPacket; // Are we queueing the miniport's packet?
|
|
BOOLEAN bIsLockAcquired;
|
|
|
|
#if STATS
|
|
PNDIS_BUFFER StpNdisBuffer;
|
|
PVOID StFirstBufferVa;
|
|
UINT StFirstBufferLength;
|
|
UINT StTotalLength;
|
|
#endif // STATS
|
|
|
|
UNREFERENCED_PARAMETER(ProtocolBindingContext);
|
|
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
RWAN_ASSERT(pNdisPacket);
|
|
|
|
pConnObject = pVc->pConnObject;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Rcv: VC %x, NdisVCHandle %x, Pkt %x\n",
|
|
ProtocolVcContext,
|
|
((PRWAN_NDIS_VC)ProtocolVcContext)->NdisVcHandle,
|
|
pNdisPacket));
|
|
//
|
|
// Initialize.
|
|
//
|
|
PacketRefCount = 1;
|
|
ReceiveStatus = NDIS_STATUS_SUCCESS;
|
|
bIsMiniportPacket = TRUE;
|
|
bIsLockAcquired = TRUE;
|
|
|
|
do
|
|
{
|
|
#if STATS
|
|
NdisGetFirstBufferFromPacket(
|
|
pNdisPacket,
|
|
&StpNdisBuffer,
|
|
&StFirstBufferVa,
|
|
&StFirstBufferLength,
|
|
&StTotalLength
|
|
);
|
|
#endif // STATS
|
|
|
|
#if DBG
|
|
//
|
|
// Debugging miniports indicating up garbage packets.
|
|
//
|
|
{
|
|
ULONG DbgTotalLength;
|
|
PNDIS_BUFFER pDbgFirstBuffer;
|
|
PVOID pFirstBufferVA;
|
|
UINT DbgFirstBufferLength;
|
|
UINT DbgTotalBufferLength;
|
|
|
|
if ((pNdisPacket->Private.Head == NULL) || (pNdisPacket->Private.Tail == NULL))
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: VC %x, Pkt %x, Head/Tail is NULL!\n",
|
|
ProtocolVcContext, pNdisPacket));
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
NdisGetFirstBufferFromPacket(
|
|
pNdisPacket,
|
|
&pDbgFirstBuffer,
|
|
&pFirstBufferVA,
|
|
&DbgFirstBufferLength,
|
|
&DbgTotalBufferLength
|
|
);
|
|
|
|
if (pDbgFirstBuffer == NULL)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: VC %x, Pkt %x, first buffer is NULL!\n",
|
|
ProtocolVcContext, pNdisPacket));
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
if (DbgFirstBufferLength == 0)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: VC %x, Pkt %x, first buffer length is 0!\n",
|
|
ProtocolVcContext, pNdisPacket));
|
|
// RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
if (DbgTotalBufferLength == 0)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: VC %x, Pkt %x, Total buffer length is 0, FirstBufferLength %d!\n",
|
|
ProtocolVcContext, pNdisPacket, DbgFirstBufferLength));
|
|
// RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
if (pFirstBufferVA == NULL)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: VC %x, Pkt %x, FirstBufferVA is NULL, FirstLength %d, Total %d\n",
|
|
ProtocolVcContext, pNdisPacket, DbgFirstBufferLength, DbgTotalBufferLength));
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Recv: VC %x, Pkt %x, TotalLength %d bytes\n",
|
|
ProtocolVcContext, pNdisPacket, DbgTotalBufferLength));
|
|
|
|
|
|
if (DbgTotalBufferLength == 0)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Recv: VC %x, Pkt %x: discarding cuz zero length\n",
|
|
ProtocolVcContext, pNdisPacket));
|
|
bIsLockAcquired = FALSE;
|
|
PacketRefCount = 0;
|
|
ReceiveStatus = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// See if we are aborting this connection. If so, drop this packet.
|
|
//
|
|
if (pConnObject == NULL)
|
|
{
|
|
bIsLockAcquired = FALSE;
|
|
PacketRefCount = 0;
|
|
ReceiveStatus = NDIS_STATUS_FAILURE;
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: dropping cuz ConnObj is NULL\n"));
|
|
break;
|
|
}
|
|
|
|
RWAN_STRUCT_ASSERT(pConnObject, ntc);
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
//
|
|
// See if connection is closing. If so, drop this packet.
|
|
//
|
|
if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING) ||
|
|
((pConnObject->State != RWANS_CO_CONNECTED) &&
|
|
(pConnObject->State != RWANS_CO_IN_CALL_ACCEPTING)))
|
|
{
|
|
PacketRefCount = 0;
|
|
ReceiveStatus = NDIS_STATUS_FAILURE;
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: dropping on Conn %p, Flags %x, State %d\n",
|
|
pConnObject, pConnObject->Flags, pConnObject->State));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the packet cannot be queued, attempt to make a copy.
|
|
//
|
|
if (NDIS_GET_PACKET_STATUS(pNdisPacket) == NDIS_STATUS_RESOURCES)
|
|
{
|
|
PacketRefCount = 0; // we cannot hang on to this packet
|
|
|
|
pNdisPacket = RWanMakeReceiveCopy(pNdisPacket);
|
|
if (pNdisPacket == NULL)
|
|
{
|
|
RWANDEBUGP(DL_WARN, DC_WILDCARD,
|
|
("Rcv: failed to allocate receive copy!\n"));
|
|
ReceiveStatus = NDIS_STATUS_RESOURCES;
|
|
PacketRefCount = 0;
|
|
break;
|
|
}
|
|
bIsMiniportPacket = FALSE;
|
|
}
|
|
|
|
//
|
|
// Prepare a receive indication element to keep track of this
|
|
// receive.
|
|
//
|
|
pRcvInd = RWanAllocateReceiveInd();
|
|
if (pRcvInd == NULL)
|
|
{
|
|
PacketRefCount = 0;
|
|
ReceiveStatus = NDIS_STATUS_RESOURCES;
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Rcv: dropping cuz of failure allocating receive Ind!\n"));
|
|
break;
|
|
}
|
|
|
|
pRcvInd->pPacket = pNdisPacket;
|
|
pRcvInd->bIsMiniportPacket = bIsMiniportPacket;
|
|
pRcvInd->pNextRcvInd = NULL;
|
|
pRcvInd->pVc = pVc;
|
|
|
|
NdisGetFirstBufferFromPacket(
|
|
pNdisPacket,
|
|
&(pRcvInd->pBuffer),
|
|
(PVOID *)&(pRcvInd->pReadData),
|
|
&(pRcvInd->BytesLeftInBuffer),
|
|
&(pRcvInd->PacketLength)
|
|
);
|
|
|
|
pRcvInd->TotalBytesLeft = pRcvInd->PacketLength;
|
|
|
|
//
|
|
// Queue the receive indication at the end of the receive queue on
|
|
// this VC.
|
|
//
|
|
if (pVc->pRcvIndHead == NULL)
|
|
{
|
|
pVc->pRcvIndHead = pVc->pRcvIndTail = pRcvInd;
|
|
}
|
|
else
|
|
{
|
|
RWAN_ASSERT(pVc->pRcvIndTail != NULL);
|
|
pVc->pRcvIndTail->pNextRcvInd = pRcvInd;
|
|
pVc->pRcvIndTail = pRcvInd;
|
|
}
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DATA_RX,
|
|
("CoRcvPacket: Pkt x%x, pVc x%x, pRcvInd x%x, BytesLeft %d, PktLen %d, Head x%x, Tail x%x\n",
|
|
pNdisPacket,
|
|
pVc,
|
|
pRcvInd,
|
|
pRcvInd->BytesLeftInBuffer,
|
|
pRcvInd->PacketLength,
|
|
pVc->pRcvIndHead,
|
|
pVc->pRcvIndTail));
|
|
|
|
pVc->PendingPacketCount++; // Receive Ind
|
|
|
|
//
|
|
// Start the common indicate code (for receive requests as well
|
|
// as for receive indications).
|
|
//
|
|
if (pConnObject->State != RWANS_CO_IN_CALL_ACCEPTING)
|
|
{
|
|
RWanIndicateData(pConnObject);
|
|
}
|
|
else
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
RWANDEBUGP(DL_FATAL, DC_DATA_RX,
|
|
("Rcv: queued packet %d bytes on accepting VC %x, pConn %x\n",
|
|
pRcvInd->PacketLength, pVc, pConnObject));
|
|
}
|
|
|
|
bIsLockAcquired = FALSE; // It's released within RWanIndicateData
|
|
|
|
break;
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
if (bIsLockAcquired)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
|
|
if (ReceiveStatus != NDIS_STATUS_SUCCESS)
|
|
{
|
|
#if STATS
|
|
INCR_STAT(&RecvPktsFail);
|
|
ADD_STAT(&RecvBytesFail, StTotalLength);
|
|
#endif // STATS
|
|
|
|
//
|
|
// Clean up.
|
|
//
|
|
if (!bIsMiniportPacket &&
|
|
(pNdisPacket != NULL))
|
|
{
|
|
RWanFreeReceiveCopy(pNdisPacket);
|
|
}
|
|
}
|
|
#if STATS
|
|
else
|
|
{
|
|
INCR_STAT(&RecvPktsOk);
|
|
ADD_STAT(&RecvBytesOk, StTotalLength);
|
|
}
|
|
#endif // STATS
|
|
|
|
return (PacketRefCount);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanIndicateData(
|
|
IN PRWAN_TDI_CONNECTION pConnObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Core internal receive processing routine. This tries to match up
|
|
queued receive requests with queued receive indications and completes
|
|
as many requests as it can. It calls the receive event handler, if any,
|
|
for a receive indication that reaches the head of its queue without
|
|
matching up with a receive request.
|
|
|
|
Arguments:
|
|
|
|
pConnObject - Points to our TDI Connection context.
|
|
|
|
Locks on Entry:
|
|
|
|
pConnObject
|
|
|
|
Locks on Exit:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_TDI_ADDRESS pAddrObject;
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_NDIS_ADAPTER pAdapter;
|
|
PRcvEvent pRcvIndEvent;
|
|
INT rc;
|
|
PRWAN_RECEIVE_REQUEST pRcvReq;
|
|
PRWAN_RECEIVE_INDICATION pRcvInd;
|
|
PRWAN_RECEIVE_INDICATION pNextRcvInd;
|
|
UINT BytesToCopy;
|
|
//
|
|
// List of receive indications that have been completed here.
|
|
//
|
|
PRWAN_RECEIVE_INDICATION pCompletedRcvIndHead;
|
|
PRWAN_RECEIVE_INDICATION pCompletedRcvIndTail;
|
|
|
|
BOOLEAN IsMessageMode = TRUE;
|
|
//
|
|
// TBD: Set IsMessageMode based on the connection type/protocol type.
|
|
//
|
|
PVOID TdiEventContext;
|
|
BOOLEAN bConnectionInBadState = FALSE;
|
|
BOOLEAN bContinue = TRUE;
|
|
|
|
|
|
|
|
pVc = pConnObject->NdisConnection.pNdisVc;
|
|
pAddrObject = pConnObject->pAddrObject;
|
|
|
|
RWAN_ASSERT(pAddrObject != NULL);
|
|
|
|
pRcvIndEvent = pAddrObject->pRcvInd;
|
|
TdiEventContext = pAddrObject->RcvIndContext;
|
|
|
|
pCompletedRcvIndHead = NULL;
|
|
pCompletedRcvIndTail = NULL;
|
|
pAdapter = pVc->pNdisAf->pAdapter;
|
|
|
|
//
|
|
// Check if the client has paused receiving.
|
|
//
|
|
if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_PAUSE_RECEIVE))
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Re-entrancy check.
|
|
//
|
|
if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_INDICATING_DATA))
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
return;
|
|
}
|
|
|
|
RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_INDICATING_DATA);
|
|
|
|
//
|
|
// Make sure the Connection Object doesn't go away as long
|
|
// as we are in this routine.
|
|
//
|
|
RWanReferenceConnObject(pConnObject); // temp ref: RWanIndicateData
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("=> Ind-Rcv: VC %x/%x, ReqHead %x, IndHead %x\n",
|
|
pVc, pVc->Flags, pVc->pRcvReqHead, pVc->pRcvIndHead));
|
|
|
|
//
|
|
// Loop till we run out of receive requests/indications.
|
|
//
|
|
for (/* Nothing */;
|
|
/* Nothing */;
|
|
/* Nothing */)
|
|
{
|
|
if (pVc->pRcvIndHead == NULL)
|
|
{
|
|
//
|
|
// No data to pass up. Quit.
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// See if we have data available in the current receive indication.
|
|
//
|
|
pRcvInd = pVc->pRcvIndHead;
|
|
if (pRcvInd->TotalBytesLeft == 0)
|
|
{
|
|
//
|
|
// Move to the next receive indication.
|
|
//
|
|
pNextRcvInd = pRcvInd->pNextRcvInd;
|
|
|
|
//
|
|
// Add the current receive indication to the list of receive
|
|
// indications to be freed up.
|
|
//
|
|
pRcvInd->pNextRcvInd = NULL;
|
|
if (pCompletedRcvIndTail != NULL)
|
|
{
|
|
pCompletedRcvIndTail->pNextRcvInd = pRcvInd;
|
|
}
|
|
else
|
|
{
|
|
pCompletedRcvIndHead = pRcvInd;
|
|
}
|
|
pCompletedRcvIndTail = pRcvInd;
|
|
|
|
pVc->PendingPacketCount--; // Moved packet to completed list
|
|
|
|
//
|
|
// Move to the next receive indication.
|
|
//
|
|
pVc->pRcvIndHead = pNextRcvInd;
|
|
pRcvInd = pNextRcvInd;
|
|
|
|
//
|
|
// See if there are no more receive indications.
|
|
//
|
|
if (pRcvInd == NULL)
|
|
{
|
|
pVc->pRcvIndTail = NULL;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
#if DBG
|
|
if (pRcvInd)
|
|
{
|
|
RWAN_CHECK_DATA("IndicateData:", pRcvInd, pRcvInd->pReadData, pRcvInd->BytesLeftInBuffer);
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// We have data available to pass up.
|
|
//
|
|
// If we don't have any pending receive requests, and there
|
|
// is a Receive Indication event handler available, call the
|
|
// handler. We may get back a receive request.
|
|
//
|
|
if ((pVc->pRcvReqHead == NULL) &&
|
|
(pRcvIndEvent != NULL))
|
|
{
|
|
CONNECTION_CONTEXT ConnectionHandle;
|
|
ULONG ReceiveFlags;
|
|
ULONG BytesIndicated;
|
|
ULONG BytesTaken;
|
|
ULONG BytesAvailable;
|
|
PVOID pTSDU;
|
|
TDI_STATUS TdiStatus;
|
|
#ifdef NT
|
|
EventRcvBuffer * ERB;
|
|
EventRcvBuffer ** pERB = &ERB;
|
|
PTDI_REQUEST_KERNEL_RECEIVE pRequestInformation;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
#else
|
|
EventRcvBuffer ERB;
|
|
EventRcvBuffer * pERB = &ERB;
|
|
#endif // !NT
|
|
|
|
//
|
|
// Pre-allocate a receive request.
|
|
//
|
|
pRcvReq = RWanAllocateReceiveReq();
|
|
if (pRcvReq == NULL)
|
|
{
|
|
RWAN_ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
pRcvInd = pVc->pRcvIndHead;
|
|
ConnectionHandle = pConnObject->ConnectionHandle;
|
|
BytesIndicated = pRcvInd->BytesLeftInBuffer;
|
|
BytesAvailable = pRcvInd->TotalBytesLeft;
|
|
pTSDU = (PVOID)pRcvInd->pReadData;
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
ReceiveFlags = TDI_RECEIVE_NORMAL | TDI_RECEIVE_ENTIRE_MESSAGE;
|
|
|
|
BytesTaken = 0;
|
|
|
|
RWAN_ASSERT(BytesIndicated != 0);
|
|
RWAN_ASSERT(BytesAvailable != 0);
|
|
|
|
TdiStatus = (*pRcvIndEvent)(
|
|
TdiEventContext,
|
|
ConnectionHandle,
|
|
ReceiveFlags,
|
|
BytesIndicated,
|
|
BytesAvailable,
|
|
&BytesTaken,
|
|
pTSDU,
|
|
pERB
|
|
);
|
|
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Ind-Rcv: VC %x, Head %x, Indicated %d, Available %d, Bytes taken %d, Status %x\n",
|
|
pVc, pVc->pRcvReqHead, BytesIndicated, BytesAvailable, BytesTaken, TdiStatus));
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
//
|
|
// Check if anything bad happened to this connection
|
|
// while we were indicating.
|
|
//
|
|
if ((pConnObject->State != RWANS_CO_CONNECTED) ||
|
|
(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING)))
|
|
{
|
|
RWanFreeReceiveReq(pRcvReq);
|
|
bConnectionInBadState = TRUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// See if a receive request is given to us.
|
|
//
|
|
if (TdiStatus == TDI_MORE_PROCESSING)
|
|
{
|
|
//
|
|
// We have a receive request. Get at it.
|
|
//
|
|
#ifdef NT
|
|
NTSTATUS Status;
|
|
|
|
RWAN_ASSERT(ERB != NULL);
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(*pERB);
|
|
|
|
Status = RWanPrepareIrpForCancel(
|
|
(PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext,
|
|
ERB,
|
|
RWanCancelRequest
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pRequestInformation = (PTDI_REQUEST_KERNEL_RECEIVE)
|
|
&(pIrpSp->Parameters);
|
|
pRcvReq->Request.pReqComplete = RWanDataRequestComplete;
|
|
pRcvReq->Request.ReqContext = ERB;
|
|
pRcvReq->TotalBufferLength = pRequestInformation->ReceiveLength;
|
|
pRcvReq->pBuffer = ERB->MdlAddress;
|
|
pRcvReq->pUserFlags = (PUSHORT)
|
|
&(pRequestInformation->ReceiveFlags);
|
|
#else
|
|
pRcvReq->Request.pReqComplete = ERB.erb_rtn;
|
|
pRcvReq->Request.ReqContext = ERB.erb_context;
|
|
pRcvReq->TotalBufferLength = ERB.erb_size;
|
|
pRcvReq->pBuffer = ERB.erb_buffer;
|
|
pRcvReq->pUserFlags = ERB.erb_flags;
|
|
#endif // NT
|
|
pRcvReq->AvailableBufferLength = pRcvReq->TotalBufferLength;
|
|
NdisQueryBufferSafe(
|
|
pRcvReq->pBuffer,
|
|
&(pRcvReq->pWriteData),
|
|
&(pRcvReq->BytesLeftInBuffer),
|
|
NormalPagePriority
|
|
);
|
|
|
|
if (pRcvReq->pWriteData != NULL)
|
|
{
|
|
if (pRcvReq->BytesLeftInBuffer > pRcvReq->AvailableBufferLength)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Indicate: pRcvReq %x, BytesLeft %d > Available %d, pTdiRequest %x\n",
|
|
pRcvReq,
|
|
pRcvReq->BytesLeftInBuffer,
|
|
pRcvReq->AvailableBufferLength,
|
|
pRequestInformation));
|
|
|
|
pRcvReq->BytesLeftInBuffer = pRcvReq->AvailableBufferLength;
|
|
}
|
|
|
|
pRcvReq->pNextRcvReq = NULL;
|
|
|
|
|
|
//
|
|
// Insert this receive request at the head of the pending
|
|
// request queue.
|
|
//
|
|
if (pVc->pRcvReqHead == NULL)
|
|
{
|
|
pVc->pRcvReqHead = pVc->pRcvReqTail = pRcvReq;
|
|
}
|
|
else
|
|
{
|
|
RWAN_ASSERT(pVc->pRcvReqTail != NULL);
|
|
pRcvReq->pNextRcvReq = pVc->pRcvReqHead;
|
|
pVc->pRcvReqHead = pRcvReq;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Couldn't get virtual address of MDL passed in.
|
|
//
|
|
TdiStatus = TDI_SUCCESS;
|
|
RWanFreeReceiveReq(pRcvReq);
|
|
pRcvReq = NULL;
|
|
}
|
|
#ifdef NT
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The IRP was cancelled before it got to us.
|
|
// Continue as if the user returned SUCCESS.
|
|
//
|
|
TdiStatus = TDI_SUCCESS;
|
|
RWanFreeReceiveReq(pRcvReq);
|
|
pRcvReq = NULL;
|
|
}
|
|
#endif // NT
|
|
|
|
//
|
|
// Update based on what was consumed during the Indicate.
|
|
//
|
|
pRcvInd->BytesLeftInBuffer -= BytesTaken;
|
|
pRcvInd->TotalBytesLeft -= BytesTaken;
|
|
|
|
//
|
|
// If we still don't have any pending receive requests, quit.
|
|
//
|
|
if (pVc->pRcvReqHead == NULL)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Ind: VC %x/%x, ConnObj %x/%x, RcvInd %x, no pending Req\n",
|
|
pVc, pVc->Flags,
|
|
pConnObject, pConnObject->Flags,
|
|
pRcvInd));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We have receive requests, so continue from the top.
|
|
//
|
|
continue;
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We didn't get a receive request.
|
|
//
|
|
if (TdiStatus == TDI_NOT_ACCEPTED)
|
|
{
|
|
BytesTaken = 0;
|
|
|
|
//
|
|
// By returning this status, the TDI client is telling
|
|
// us to stop indicating data on this connection until
|
|
// it sends us a TDI receive.
|
|
//
|
|
RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_PAUSE_RECEIVE);
|
|
}
|
|
|
|
//
|
|
// Update based on what was consumed during the Indicate.
|
|
//
|
|
pRcvInd->BytesLeftInBuffer -= BytesTaken;
|
|
pRcvInd->TotalBytesLeft -= BytesTaken;
|
|
|
|
RWanFreeReceiveReq(pRcvReq);
|
|
|
|
if (TdiStatus == TDI_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
} // if Receive Event handler exists
|
|
|
|
//
|
|
// If we still don't have any pending receive requests, quit.
|
|
//
|
|
if (pVc->pRcvReqHead == NULL)
|
|
{
|
|
#if DBG1
|
|
if (pVc->pRcvIndHead && (pVc->pRcvIndHead->TotalBytesLeft == 0))
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Ind: VC %x/%x, No pending recv reqs, RcvInd empty!\n", pVc, pVc->Flags));
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Fill in the receive request at the head of the queue
|
|
// as much as we can.
|
|
//
|
|
pRcvReq = pVc->pRcvReqHead;
|
|
pRcvInd = pVc->pRcvIndHead;
|
|
|
|
RWAN_ASSERT(pRcvReq != NULL);
|
|
RWAN_ASSERT(pRcvInd != NULL);
|
|
|
|
while (pRcvReq->AvailableBufferLength != 0)
|
|
{
|
|
if (pRcvReq->BytesLeftInBuffer == 0)
|
|
{
|
|
//
|
|
// Move to the next buffer in the chain.
|
|
//
|
|
RWAN_ADVANCE_RCV_REQ_BUFFER(pRcvReq);
|
|
RWAN_ASSERT(pRcvReq->BytesLeftInBuffer != 0);
|
|
}
|
|
|
|
RWAN_ASSERT(pRcvInd != NULL);
|
|
|
|
if (pRcvInd->BytesLeftInBuffer == 0)
|
|
{
|
|
RWAN_ADVANCE_RCV_IND_BUFFER(pRcvInd);
|
|
RWAN_ASSERT(pRcvInd->BytesLeftInBuffer != 0);
|
|
}
|
|
|
|
BytesToCopy = MIN(pRcvReq->BytesLeftInBuffer, pRcvInd->BytesLeftInBuffer);
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DATA_RX,
|
|
("IndicateData: pVc x%x, pRcvInd x%x, pRcvReq x%x, copying %d bytes, %x to %x\n",
|
|
pVc,
|
|
pRcvInd,
|
|
pRcvReq,
|
|
BytesToCopy,
|
|
pRcvInd->pReadData,
|
|
pRcvReq->pWriteData));
|
|
|
|
#if DBG
|
|
if (pRcvInd)
|
|
{
|
|
RWAN_CHECK_DATA("IndicateData - copy:", pRcvInd, pRcvInd->pReadData, BytesToCopy);
|
|
}
|
|
#endif // DBG
|
|
RWAN_COPY_MEM(pRcvReq->pWriteData,
|
|
pRcvInd->pReadData,
|
|
BytesToCopy);
|
|
|
|
pRcvReq->pWriteData += BytesToCopy;
|
|
pRcvReq->BytesLeftInBuffer -= BytesToCopy;
|
|
pRcvReq->AvailableBufferLength -= BytesToCopy;
|
|
#if DBG
|
|
if (pRcvReq->AvailableBufferLength > pRcvReq->TotalBufferLength)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Indicate: VC %x, RcvRq %x, Avail %d > Total %d, BytesToCopy %d, RcvInd %x\n",
|
|
pVc, pRcvReq,
|
|
pRcvReq->AvailableBufferLength,
|
|
pRcvReq->TotalBufferLength,
|
|
BytesToCopy,
|
|
pRcvInd));
|
|
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
pRcvInd->pReadData += BytesToCopy;
|
|
pRcvInd->BytesLeftInBuffer -= BytesToCopy;
|
|
pRcvInd->TotalBytesLeft -= BytesToCopy;
|
|
|
|
//
|
|
// See if we have data available in the current receive indication.
|
|
//
|
|
if (pRcvInd->TotalBytesLeft == 0)
|
|
{
|
|
//
|
|
// Move to the next receive indication.
|
|
//
|
|
pNextRcvInd = pRcvInd->pNextRcvInd;
|
|
|
|
//
|
|
// Add the current receive indication to the list of receive
|
|
// indications to be freed up.
|
|
//
|
|
pRcvInd->pNextRcvInd = NULL;
|
|
if (pCompletedRcvIndTail != NULL)
|
|
{
|
|
pCompletedRcvIndTail->pNextRcvInd = pRcvInd;
|
|
}
|
|
else
|
|
{
|
|
pCompletedRcvIndHead = pRcvInd;
|
|
}
|
|
|
|
pCompletedRcvIndTail = pRcvInd;
|
|
|
|
pVc->PendingPacketCount--; // Moved packet to completed list
|
|
|
|
//
|
|
// Move to the next receive indication.
|
|
//
|
|
pVc->pRcvIndHead = pNextRcvInd;
|
|
pRcvInd = pNextRcvInd;
|
|
|
|
//
|
|
// See if there are no more receive indications.
|
|
//
|
|
if (pRcvInd == NULL)
|
|
{
|
|
pVc->pRcvIndTail = NULL;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If this connection uses message mode delivery,
|
|
// we don't allow a receive request to span multiple
|
|
// received packets.
|
|
//
|
|
if (IsMessageMode)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// A receive request has been filled in either completely
|
|
// or partially. If we are in message mode, complete the
|
|
// receive now, otherwise we will wait for more data.
|
|
//
|
|
if ((pRcvReq->AvailableBufferLength == 0) ||
|
|
IsMessageMode)
|
|
{
|
|
TDI_STATUS ReceiveStatus;
|
|
UINT BytesCopied;
|
|
|
|
//
|
|
// A receive request has been fully/partially satisfied. Take it
|
|
// out of the pending list and complete it.
|
|
//
|
|
pVc->pRcvReqHead = pRcvReq->pNextRcvReq;
|
|
if (pVc->pRcvReqHead == NULL)
|
|
{
|
|
pVc->pRcvReqTail = NULL;
|
|
}
|
|
|
|
BytesCopied = pRcvReq->TotalBufferLength - pRcvReq->AvailableBufferLength;
|
|
|
|
//
|
|
// Check if we copied in only part of a received packet into
|
|
// this receive request. If so, indicate an overflow.
|
|
//
|
|
if ((pRcvReq->AvailableBufferLength == 0) &&
|
|
(pVc->pRcvIndHead != NULL) &&
|
|
(pVc->pRcvIndHead->TotalBytesLeft != pVc->pRcvIndHead->PacketLength))
|
|
{
|
|
RWANDEBUGP(DL_LOUD, DC_WILDCARD,
|
|
("Ind-Rcv: Overflow: VC %x/%x, Head %x, BytesCopied %d, Left %d\n",
|
|
pVc, pVc->Flags, pVc->pRcvIndHead, BytesCopied, pVc->pRcvIndHead->TotalBytesLeft));
|
|
ReceiveStatus = TDI_BUFFER_OVERFLOW;
|
|
*(pRcvReq->pUserFlags) = 0;
|
|
}
|
|
else
|
|
{
|
|
ReceiveStatus = TDI_SUCCESS;
|
|
*(pRcvReq->pUserFlags) = TDI_RECEIVE_ENTIRE_MESSAGE;
|
|
}
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
*(pRcvReq->pUserFlags) |= TDI_RECEIVE_NORMAL;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Ind-Rcv: VC %x/%x, Head %x, completing TDI Rcv %x, %d bytes, Status %x\n",
|
|
pVc, pVc->Flags, pVc->pRcvReqHead, pRcvReq, BytesCopied, ReceiveStatus));
|
|
|
|
//
|
|
// Complete the Receive Req
|
|
//
|
|
(*pRcvReq->Request.pReqComplete)(
|
|
pRcvReq->Request.ReqContext,
|
|
ReceiveStatus,
|
|
BytesCopied
|
|
);
|
|
|
|
RWanFreeReceiveReq(pRcvReq);
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
//
|
|
// Check if anything bad happened to this connection
|
|
// while we were completing the receive request.
|
|
//
|
|
if ((pConnObject->State != RWANS_CO_CONNECTED) ||
|
|
(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING)))
|
|
{
|
|
bConnectionInBadState = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} // forever
|
|
|
|
|
|
RWAN_RESET_BIT(pConnObject->Flags, RWANF_CO_INDICATING_DATA);
|
|
|
|
rc = RWanDereferenceConnObject(pConnObject); // end temp ref: RWanIndicateData
|
|
|
|
if (rc > 0)
|
|
{
|
|
//
|
|
// Update receive indication queue on the VC. Only if the VC
|
|
// is still around...
|
|
//
|
|
if (pVc == pConnObject->NdisConnection.pNdisVc)
|
|
{
|
|
if (bConnectionInBadState)
|
|
{
|
|
ULONG AbortCount = 0;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Ind: start abort VC %x/%x state %d, pComplRcvHead %p, tail %p\n",
|
|
pVc, pVc->Flags, pVc->State, pCompletedRcvIndHead, pCompletedRcvIndTail));
|
|
//
|
|
// Take out all pending receives.
|
|
//
|
|
for (pRcvInd = pVc->pRcvIndHead;
|
|
pRcvInd != NULL;
|
|
pRcvInd = pNextRcvInd)
|
|
{
|
|
pNextRcvInd = pRcvInd->pNextRcvInd;
|
|
|
|
pRcvInd->pNextRcvInd = NULL;
|
|
if (pCompletedRcvIndTail != NULL)
|
|
{
|
|
pCompletedRcvIndTail->pNextRcvInd = pRcvInd;
|
|
}
|
|
else
|
|
{
|
|
pCompletedRcvIndHead = pRcvInd;
|
|
}
|
|
|
|
pCompletedRcvIndTail = pRcvInd;
|
|
|
|
pVc->PendingPacketCount--; // Abort: Moved packet to completed list
|
|
AbortCount++;
|
|
}
|
|
|
|
pVc->pRcvIndHead = pVc->pRcvIndTail = NULL;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_RX,
|
|
("Ind: end abort VC %x/%x state %d, pComplRcvHead %p, tail %p, Count %d\n",
|
|
pVc, pVc->Flags, pVc->State, pCompletedRcvIndHead, pCompletedRcvIndTail, AbortCount));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Update the first Receive Indication if necessary.
|
|
//
|
|
if (pVc->pRcvIndHead &&
|
|
(pVc->pRcvIndHead->TotalBytesLeft == 0))
|
|
{
|
|
RWANDEBUGP(DL_LOUD, DC_WILDCARD,
|
|
("Ind: VC %x/%x, empty pRcvInd at head %x\n", pVc, pVc->Flags,
|
|
pVc->pRcvIndHead));
|
|
|
|
pRcvInd = pVc->pRcvIndHead;
|
|
pNextRcvInd = pRcvInd->pNextRcvInd;
|
|
|
|
pRcvInd->pNextRcvInd = NULL;
|
|
|
|
if (pCompletedRcvIndTail != NULL)
|
|
{
|
|
pCompletedRcvIndTail->pNextRcvInd = pRcvInd;
|
|
}
|
|
else
|
|
{
|
|
pCompletedRcvIndHead = pRcvInd;
|
|
}
|
|
|
|
pCompletedRcvIndTail = pRcvInd;
|
|
|
|
pVc->PendingPacketCount--; // IndComplete: Moved packet to completed list
|
|
|
|
pVc->pRcvIndHead = pNextRcvInd;
|
|
if (pVc->pRcvIndHead == NULL)
|
|
{
|
|
pVc->pRcvIndTail = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_DATA_RX, ("Ind: ConnObj %p, VC %p blown away!\n",
|
|
pConnObject, pVc));
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Check if we had queued up an IncomingClose while indicating data:
|
|
//
|
|
if (RWAN_IS_FLAG_SET(pConnObject->Flags, RWANF_CO_PENDED_DISCON, RWANF_CO_PENDED_DISCON))
|
|
{
|
|
RWAN_RESET_BIT(pConnObject->Flags, RWANF_CO_PENDED_DISCON);
|
|
|
|
RWANDEBUGP(DL_FATAL, DC_DATA_RX, ("Ind: Conn %x, State %d, Addr %x, handling pended discon\n",
|
|
pConnObject, pConnObject->State, pConnObject->pAddrObject));
|
|
|
|
if (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS)
|
|
{
|
|
PDisconnectEvent pDisconInd;
|
|
PVOID IndContext;
|
|
PVOID ConnectionHandle;
|
|
|
|
pDisconInd = pConnObject->pAddrObject->pDisconInd;
|
|
IndContext = pConnObject->pAddrObject->DisconIndContext;
|
|
|
|
if (pDisconInd != NULL)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_DATA_RX,
|
|
("IndicateData: pConnObj %x/%x, st %x, will discon ind\n",
|
|
pConnObject, pConnObject->Flags, pConnObject->State));
|
|
|
|
pConnObject->State = RWANS_CO_DISCON_INDICATED;
|
|
ConnectionHandle = pConnObject->ConnectionHandle;
|
|
|
|
RWanScheduleDisconnect(pConnObject);
|
|
bContinue = FALSE;
|
|
|
|
(*pDisconInd)(
|
|
IndContext,
|
|
ConnectionHandle,
|
|
0, // Disconnect Data Length
|
|
NULL, // Disconnect Data
|
|
0, // Disconnect Info Length
|
|
NULL, // Disconnect Info
|
|
TDI_DISCONNECT_RELEASE
|
|
);
|
|
}
|
|
else
|
|
{
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if we need to close this connection.
|
|
//
|
|
if (bContinue)
|
|
{
|
|
if (RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_NEEDS_CLOSE))
|
|
{
|
|
RWanStartCloseCall(pConnObject, pVc);
|
|
}
|
|
else
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Link all completed receive indications to the list on this adapter.
|
|
// They will be returned to the miniport in the ReceiveComplete
|
|
// handler.
|
|
//
|
|
RWAN_ACQUIRE_GLOBAL_LOCK();
|
|
|
|
{
|
|
PRWAN_RECEIVE_INDICATION * ppRcvIndTail;
|
|
|
|
ppRcvIndTail = &(pAdapter->pCompletedReceives);
|
|
while (*ppRcvIndTail != NULL)
|
|
{
|
|
ppRcvIndTail = &((*ppRcvIndTail)->pNextRcvInd);
|
|
}
|
|
|
|
#if DBG
|
|
if (bConnectionInBadState)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_WILDCARD,
|
|
("Ind: Adapter %p &ComplRcvs %p ComplRcvs %p, will tack on %p\n",
|
|
pAdapter,
|
|
&pAdapter->pCompletedReceives,
|
|
pAdapter->pCompletedReceives,
|
|
pCompletedRcvIndHead));
|
|
}
|
|
#endif // DBG
|
|
|
|
*ppRcvIndTail = pCompletedRcvIndHead;
|
|
|
|
}
|
|
|
|
RWAN_RELEASE_GLOBAL_LOCK();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisReceiveComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the entry point called by NDIS when the miniport
|
|
informs it that it has completed indicating a bunch of
|
|
received packets.
|
|
|
|
We use this event to free up any completed receives
|
|
on this adapter binding.
|
|
|
|
Arguments:
|
|
|
|
ProtocolBindingContext - Pointer to our Adapter structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_ADAPTER pAdapter;
|
|
PRWAN_RECEIVE_INDICATION pRcvInd;
|
|
|
|
pAdapter = (PRWAN_NDIS_ADAPTER)ProtocolBindingContext;
|
|
RWAN_STRUCT_ASSERT(pAdapter, nad);
|
|
|
|
//
|
|
// Detach the list of completed receives from the adapter.
|
|
//
|
|
RWAN_ACQUIRE_GLOBAL_LOCK();
|
|
|
|
pRcvInd = pAdapter->pCompletedReceives;
|
|
pAdapter->pCompletedReceives = NULL;
|
|
|
|
RWAN_RELEASE_GLOBAL_LOCK();
|
|
|
|
RWanFreeReceiveIndList(pRcvInd);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisTransferDataComplete(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET pNdisPacket,
|
|
IN NDIS_STATUS Status,
|
|
IN UINT BytesTransferred
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// Not expected.
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
RWanNdisReceive(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN NDIS_HANDLE MacReceiveContext,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT HeaderBufferSize,
|
|
IN PVOID pLookAheadBuffer,
|
|
IN UINT LookAheadBufferSize,
|
|
IN UINT PacketSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// Not expected.
|
|
RWAN_ASSERT(FALSE);
|
|
return (NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
|
|
|
|
|
|
INT
|
|
RWanNdisReceivePacket(
|
|
IN NDIS_HANDLE ProtocolBindingContext,
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
// Not expected.
|
|
RWAN_ASSERT(FALSE);
|
|
return (0);
|
|
}
|
|
|
|
|
|
|
|
|
|
PRWAN_RECEIVE_REQUEST
|
|
RWanAllocateReceiveReq(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a structure to keep context of a TDI Receive request.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Pointer to the allocated receive request structure, or NULL.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_RECEIVE_REQUEST pRcvReq;
|
|
|
|
RWAN_ALLOC_MEM(pRcvReq, RWAN_RECEIVE_REQUEST, sizeof(RWAN_RECEIVE_REQUEST));
|
|
|
|
if (pRcvReq != NULL)
|
|
{
|
|
RWAN_SET_SIGNATURE(pRcvReq, nrr);
|
|
}
|
|
|
|
return (pRcvReq);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanFreeReceiveReq(
|
|
IN PRWAN_RECEIVE_REQUEST pRcvReq
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a receive request structure.
|
|
|
|
Arguments:
|
|
|
|
pRcvReq - Points to structure to be freed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
RWAN_STRUCT_ASSERT(pRcvReq, nrr);
|
|
|
|
RWAN_FREE_MEM(pRcvReq);
|
|
}
|
|
|
|
|
|
|
|
|
|
PRWAN_RECEIVE_INDICATION
|
|
RWanAllocateReceiveInd(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate a structure to keep context about an NDIS receive indication.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Pointer to the allocated structure, or NULL.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_RECEIVE_INDICATION pRcvInd;
|
|
|
|
RWAN_ALLOC_MEM(pRcvInd, RWAN_RECEIVE_INDICATION, sizeof(RWAN_RECEIVE_INDICATION));
|
|
|
|
if (pRcvInd != NULL)
|
|
{
|
|
RWAN_SET_SIGNATURE(pRcvInd, nri);
|
|
}
|
|
|
|
return (pRcvInd);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanFreeReceiveInd(
|
|
IN PRWAN_RECEIVE_INDICATION pRcvInd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a receive indication structure.
|
|
|
|
Arguments:
|
|
|
|
pRcvInd - Points to structure to be freed.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
RWAN_STRUCT_ASSERT(pRcvInd, nri);
|
|
RWAN_FREE_MEM(pRcvInd);
|
|
}
|
|
|
|
|
|
|
|
|
|
PNDIS_PACKET
|
|
RWanMakeReceiveCopy(
|
|
IN PNDIS_PACKET pNdisPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Make a copy of a received packet to a private packet.
|
|
|
|
Arguments:
|
|
|
|
pNdisPacket - Points to original packet
|
|
|
|
Return Value:
|
|
|
|
Pointer to private packet if successful, NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_PACKET pNewPacket;
|
|
PNDIS_BUFFER pNewBuffer;
|
|
PUCHAR pData;
|
|
UINT TotalLength;
|
|
UINT BytesCopied;
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
pNewPacket = NULL;
|
|
pNewBuffer = NULL;
|
|
pData = NULL;
|
|
|
|
do
|
|
{
|
|
NdisQueryPacket(
|
|
pNdisPacket,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&TotalLength
|
|
);
|
|
|
|
//
|
|
// Allocate space for the data.
|
|
//
|
|
RWAN_ALLOC_MEM(pData, UCHAR, TotalLength);
|
|
if (pData == NULL)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Make this an NDIS Buffer (MDL).
|
|
//
|
|
NdisAllocateBuffer(
|
|
&Status,
|
|
&pNewBuffer,
|
|
RWanCopyBufferPool,
|
|
pData,
|
|
TotalLength
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate a new packet.
|
|
//
|
|
NdisAllocatePacket(
|
|
&Status,
|
|
&pNewPacket,
|
|
RWanCopyPacketPool
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
NDIS_SET_PACKET_STATUS(pNewPacket, 0);
|
|
|
|
//
|
|
// Link the buffer to the packet.
|
|
//
|
|
NdisChainBufferAtFront(pNewPacket, pNewBuffer);
|
|
|
|
//
|
|
// Copy in the received packet.
|
|
//
|
|
NdisCopyFromPacketToPacket(
|
|
pNewPacket,
|
|
0, // Destn offset
|
|
TotalLength,
|
|
pNdisPacket,
|
|
0, // Source offset
|
|
&BytesCopied
|
|
);
|
|
|
|
RWAN_ASSERT(BytesCopied == TotalLength);
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
if (pNewPacket == NULL)
|
|
{
|
|
//
|
|
// Clean up.
|
|
//
|
|
if (pData != NULL)
|
|
{
|
|
RWAN_FREE_MEM(pData);
|
|
}
|
|
|
|
if (pNewBuffer != NULL)
|
|
{
|
|
NdisFreeBuffer(pNewBuffer);
|
|
}
|
|
}
|
|
|
|
return (pNewPacket);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanFreeReceiveCopy(
|
|
IN PNDIS_PACKET pCopyPacket
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a packet that was used to keep a copy of a received packet,
|
|
and its components (buffer etc).
|
|
|
|
Arguments:
|
|
|
|
pCopyPacket - Points to packet to be freed.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PNDIS_BUFFER pCopyBuffer;
|
|
PUCHAR pCopyData;
|
|
UINT TotalLength;
|
|
UINT BufferLength;
|
|
|
|
NdisGetFirstBufferFromPacket(
|
|
pCopyPacket,
|
|
&pCopyBuffer,
|
|
(PVOID *)&pCopyData,
|
|
&BufferLength,
|
|
&TotalLength
|
|
);
|
|
|
|
RWAN_ASSERT(BufferLength == TotalLength);
|
|
|
|
RWAN_ASSERT(pCopyBuffer != NULL);
|
|
|
|
NdisFreePacket(pCopyPacket);
|
|
|
|
NdisFreeBuffer(pCopyBuffer);
|
|
|
|
RWAN_FREE_MEM(pCopyData);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RWanFreeReceiveIndList(
|
|
IN PRWAN_RECEIVE_INDICATION pRcvInd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free a list of receive indications, and return any packets in there
|
|
that belong to the miniport.
|
|
|
|
Arguments:
|
|
|
|
pRcvInd - Head of list of receives.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_RECEIVE_INDICATION pNextRcvInd;
|
|
PNDIS_PACKET pNdisPacket;
|
|
#if DBG
|
|
RWAN_IRQL EntryIrq, ExitIrq;
|
|
#endif // DBG
|
|
|
|
RWAN_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
while (pRcvInd != NULL)
|
|
{
|
|
pNextRcvInd = pRcvInd->pNextRcvInd;
|
|
|
|
pNdisPacket = pRcvInd->pPacket;
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DATA_RX,
|
|
("FreeRcvIndList: freeing Pkt x%x, RcvInd x%x\n",
|
|
pNdisPacket, pRcvInd));
|
|
|
|
if (pRcvInd->bIsMiniportPacket)
|
|
{
|
|
NdisReturnPackets(&pNdisPacket, 1);
|
|
}
|
|
else
|
|
{
|
|
RWanFreeReceiveCopy(pNdisPacket);
|
|
}
|
|
|
|
RWanFreeReceiveInd(pRcvInd);
|
|
|
|
pRcvInd = pNextRcvInd;
|
|
}
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|