/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
Receive.c
Abstract:
This file contains the procedures for handling a receive indication from
a Wan Miniport link, bound to the lower interface of NdisWan, and passing
the data on to a protocol, bound to the upper interface of NdisWan. The
upper interface of NdisWan conforms to the NDIS 3.1 Miniport specification.
The lower interface of NdisWan conforms to the NDIS 3.1 Extentions for
Wan Miniport drivers.
Author:
Tony Bell (TonyBe) June 06, 1995
Environment:
Kernel Mode
Revision History:
TonyBe 06/06/95 Created
--*/
#include "wan.h"
#include "tcpip.h"
#include "vjslip.h"
#include "compress.h"
#include "isnipx.h"
#include "nbfconst.h"
#include "nbfhdrs.h"
#include <rc4.h>
VOID
DoMultilinkProcessing(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
VOID
UpdateMinRecvSeqNumber(
PBUNDLECB BundleCB
);
VOID
TryToAssembleFrame(
PBUNDLECB BundleCB
);
VOID
ProcessFrame(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
VOID
QueueDeferredReceive(
PADAPTERCB AdapterCB,
PRECV_DESC RecvDesc
);
BOOLEAN
DoVJDecompression(
PBUNDLECB BundleCB,
USHORT ProtocolID,
PUCHAR *DataPointer,
PULONG DataLength,
PUCHAR Header,
PULONG HeaderLength
);
BOOLEAN
DoDecompDecryptProcessing(
PBUNDLECB BundleCB,
PLINKCB LinkCB,
PUCHAR *DataPointer,
PULONG DataLength
);
VOID
DoCompressionReset(
PBUNDLECB BundleCB
);
VOID
FlushRecvDescWindow(
PBUNDLECB BundleCB
);
VOID
NdisWanReturnRecvDesc(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
VOID
FindHoleInRecvList(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
VOID
NdisWanCopyFromBufferToPacket(
PUCHAR Buffer,
ULONG BytesToCopy,
PNDIS_PACKET NdisPacket,
ULONG PacketOffset,
PULONG BytesCopied
);
#if 0
ULONG
CalculatePPPHeaderLength(
PLINKCB LinkCB
);
#endif
VOID
QueuePromiscuousReceive(
PRECV_DESC RecvDesc
);
#ifdef NT
VOID
CompleteIoRecvPacket(
PBUNDLECB BundleCB,
PLINKCB LinkCB,
USHORT PPPProtocolID,
PRECV_DESC RecvDesc
);
#endif
NDIS_STATUS
NdisWanReceiveIndication(
NDIS_HANDLE NdisLinkContext,
PUCHAR Packet,
ULONG PacketSize
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PLINKCB LinkCB;
PBUNDLECB BundleCB;
PRECV_DESC RecvDesc;
PUCHAR FramePointer;
ULONG FrameLength;
ULONG LinkFraming;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveIndication: Enter"));
LINKCB_FROM_LINKH(LinkCB, NdisLinkContext);
if (LinkCB == NULL) {
return (NDIS_STATUS_SUCCESS);
}
BundleCB = LinkCB->BundleCB;
if (BundleCB == NULL) {
return (NDIS_STATUS_SUCCESS);
}
NdisAcquireSpinLock(&BundleCB->Lock);
if (LinkCB->State != LINK_UP ||
BundleCB->State != BUNDLE_UP) {
NdisReleaseSpinLock(&BundleCB->Lock);
return (NDIS_STATUS_SUCCESS);
}
//
// We need to get a descriptor to copy data into
//
NdisWanGetRecvDesc(BundleCB, &RecvDesc);
if (RecvDesc == NULL) {
NdisReleaseSpinLock(&BundleCB->Lock);
return (NDIS_STATUS_SUCCESS);
}
//
// Copy the data
//
NdisMoveMemory(RecvDesc->StartBuffer, Packet, PacketSize);
FramePointer = RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
FrameLength = RecvDesc->CurrentBufferLength = PacketSize;
RecvDesc->LinkCB = LinkCB;
//
// Add up the statistics
//
LinkCB->LinkStats.BytesReceived += PacketSize;
LinkCB->LinkStats.FramesReceived++;
BundleCB->BundleStats.BytesReceived += PacketSize;
//
// If we are in framing detect mode figure it out
//
if ((LinkFraming = LinkCB->LinkInfo.RecvFramingBits) == 0x00) {
if (*FramePointer == 0xFF && *(FramePointer + 1) == 0x03) {
LinkFraming =
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits = PPP_FRAMING;
} else {
LinkFraming =
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits = RAS_FRAMING;
}
}
if (BundleCB->FramingInfo.RecvFramingBits == 0x00) {
if (*FramePointer == 0xFF && *(FramePointer + 1) == 0x03) {
BundleCB->FramingInfo.RecvFramingBits =
BundleCB->FramingInfo.SendFramingBits = PPP_FRAMING;
} else {
BundleCB->FramingInfo.RecvFramingBits =
BundleCB->FramingInfo.SendFramingBits = RAS_FRAMING;
}
}
NdisReleaseSpinLock(&BundleCB->Lock);
#if 0
if (FrameLength < CalculatePPPHeaderLength(LinkCB)) {
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Receive buffer to small! %d", PacketSize));
return (NDIS_STATUS_SUCCESS);
}
#endif
//
// If this is a PPP frame we will remove the link specific
// header information and check for multilink.
//
if (LinkFraming & PPP_FRAMING) {
//
// Remove the address/control part of the PPP header
//
if (*FramePointer == 0xFF) {
FramePointer += 2;
FrameLength -= 2;
}
//
// If multilink framing is set and this is a multilink frame
// send to the multilink processor!
//
if ((LinkFraming & PPP_MULTILINK_FRAMING) &&
((*FramePointer == 0x3D) ||
(*FramePointer == 0x00) && (*(FramePointer + 1) == 0x3D)) ) {
//
// Remove multilink protocol id
//
if (*FramePointer & 1) {
FramePointer++;
FrameLength--;
} else {
FramePointer += 2;
FrameLength -= 2;
}
RecvDesc->CurrentBufferLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
DoMultilinkProcessing(BundleCB, RecvDesc);
return (NDIS_STATUS_SUCCESS);
} // end of PPP_MULTILINK_FRAMING
} // end of PPP_FRAMING
//
// Send the frame on for further processing!
//
RecvDesc->CurrentBufferLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
NdisAcquireSpinLock(&BundleCB->Lock);
ASSERT(!(BundleCB->Flags & IN_RECEIVE));
BundleCB->Flags |= IN_RECEIVE;
NdisReleaseSpinLock(&BundleCB->Lock);
ProcessFrame(BundleCB, RecvDesc);
NdisAcquireSpinLock(&BundleCB->Lock);
BundleCB->Flags &= ~IN_RECEIVE;
NdisReleaseSpinLock(&BundleCB->Lock);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveIndication: Exit"));
return (NDIS_STATUS_SUCCESS);
}
VOID
DoMultilinkProcessing(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
/*++
Routine Name:
Routine Description:
Arguments:
*DataPointer - Points to a pointer that points to a data block that
should have one of the following formats:
0 1 2 3 4 5 6 7 8 9 1 1 1 1 1 1
0 1 2 3 4 5
+-+-+-+-+------------------------+
Short Sequence Number |B|E|0|0| Sequence Number |
+-+-+-+-+------------------------+
| Data |
+--------------------------------+
+-+-+-+-+-+-+-+-+----------------+
Long Sequence Number |B|E|0|0|0|0|0|0|Sequence Number |
+-+-+-+-+-+-+-+-+----------------+
| Sequence Number |
+--------------------------------+
| Data |
+--------------------------------+
Return Values:
--*/
{
BOOLEAN Inserted = FALSE;
ULONG BundleFraming;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
ULONG FrameLength = RecvDesc->CurrentBufferLength;
ULONG SequenceNumber, Flags;
PRECV_DESC RecvDescHole;
PLINKCB LinkCB = RecvDesc->LinkCB;
NdisAcquireSpinLock(&BundleCB->Lock);
BundleFraming = BundleCB->FramingInfo.RecvFramingBits;
RecvDescHole = BundleCB->RecvDescHole;
//
// Get the flags
//
Flags = *FramePointer & MULTILINK_FLAG_MASK;
//
// Get the sequence number
//
if (BundleFraming & PPP_SHORT_SEQUENCE_HDR_FORMAT) {
//
// Short sequence format
//
SequenceNumber = ((*FramePointer & 0x0F) << 8) | *(FramePointer + 1);
FramePointer += 2;
FrameLength -= 2;
} else {
//
// Long sequence format
//
SequenceNumber = (*(FramePointer + 1) << 16) |
(*(FramePointer + 2) << 8) |
*(FramePointer + 3);
FramePointer += 4;
FrameLength -= 4;
}
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("r %8.8x %8.8x h: %8.8x l: %d",SequenceNumber, Flags, RecvDescHole->SequenceNumber, LinkCB->hLinkHandle));
//
// Is the new recveive sequence number smaller that the last
// sequence number received on this link? If so the increasing seq
// number rule has been violated and we need to toss this one.
//
if (SEQ_LT(SequenceNumber,
LinkCB->LastRecvSeqNumber,
BundleCB->RecvSeqTest)) {
ASSERT(RecvDesc->RefCount == 1);
LinkCB->RecvFragmentsLost++;
BundleCB->RecvFragmentsLost++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dl s: %8.8x %8.8x lr: %8.8x", SequenceNumber, Flags,
LinkCB->LastRecvSeqNumber));
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
NdisReleaseSpinLock(&BundleCB->Lock);
return;
}
//
// Initialize the recv desc
//
RecvDesc->Flags = Flags;
RecvDesc->SequenceNumber =
LinkCB->LastRecvSeqNumber = SequenceNumber;
RecvDesc->CurrentBufferLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
//
// Is the new receive sequence number smaller than the hole? If so
// we received a fragment across a slow link after it has been flushed
//
if (SEQ_LT(SequenceNumber,
RecvDescHole->SequenceNumber,
BundleCB->RecvSeqTest)) {
ASSERT(RecvDesc->RefCount == 1);
LinkCB->RecvFragmentsLost++;
BundleCB->RecvFragmentsLost++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("db s: %8.8x %8.8x h: %8.8x", SequenceNumber, Flags,
RecvDescHole->SequenceNumber));
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
NdisReleaseSpinLock(&BundleCB->Lock);
return;
}
//
// If this fills the hole
//
if (SEQ_EQ(SequenceNumber, RecvDescHole->SequenceNumber)) {
//
// Insert the hole filler in the current holes spot
//
RecvDesc->Linkage.Blink = (PLIST_ENTRY)RecvDescHole->Linkage.Blink;
RecvDesc->Linkage.Flink = (PLIST_ENTRY)RecvDescHole->Linkage.Flink;
RecvDesc->Linkage.Blink->Flink =
RecvDesc->Linkage.Flink->Blink = (PLIST_ENTRY)RecvDesc;
//
// Find the next hole
//
FindHoleInRecvList(BundleCB, RecvDesc);
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r1"));
} else {
PRECV_DESC BeginDesc, EndDesc;
//
// This does not fill a hole so we need to insert it into
// the list at the right spot. This spot will be someplace
// between the hole and the end of the list.
//
BeginDesc = RecvDescHole;
EndDesc = (PRECV_DESC)BeginDesc->Linkage.Flink;
while ((PVOID)EndDesc != (PVOID)&BundleCB->RecvDescAssemblyList) {
//
// Calculate the absolute delta between the begining sequence
// number and the sequence number we are looking to insert.
//
ULONG DeltaBegin =
((RecvDesc->SequenceNumber - BeginDesc->SequenceNumber) &
BundleCB->RecvSeqMask);
//
// Calculate the absolute delta between the begining sequence
// number and the end sequence number.
//
ULONG DeltaEnd =
((EndDesc->SequenceNumber - BeginDesc->SequenceNumber) &
BundleCB->RecvSeqMask);
//
// If the delta from the begin to current is less than
// the delta from the end to current it is time to insert
//
if (DeltaBegin < DeltaEnd) {
PLIST_ENTRY Flink, Blink;
//
// Insert the desc
//
RecvDesc->Linkage.Flink = (PLIST_ENTRY)EndDesc;
RecvDesc->Linkage.Blink = (PLIST_ENTRY)BeginDesc;
BeginDesc->Linkage.Flink =
EndDesc->Linkage.Blink = (PLIST_ENTRY)RecvDesc;
Inserted = TRUE;
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r2"));
break;
} else {
//
// Get next pair of descriptors
//
BeginDesc = EndDesc;
EndDesc = (PRECV_DESC)EndDesc->Linkage.Flink;
}
}
if (!Inserted) {
//
// If we are here we have fallen through and we need to
// add this at the end of the list
//
InsertTailList(&BundleCB->RecvDescAssemblyList, &RecvDesc->Linkage);
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r3"));
}
}
//
// Update the bundles minimum recv sequence number. This is
// used to detect lost fragments.
//
UpdateMinRecvSeqNumber(BundleCB);
//
// Check for lost fragments. If the minimum recv sequence number
// over the bundle is greater than the hole sequence number we have
// lost a fragment and need to flush the assembly list until we find
// the first begin fragment after the hole.
//
if (SEQ_GT(BundleCB->MinReceivedSeqNumber,
RecvDescHole->SequenceNumber,
BundleCB->RecvSeqTest)) {
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("min %8.8x > h %8.8x b %8.8x", BundleCB->MinReceivedSeqNumber,
RecvDescHole->SequenceNumber, BundleCB));
//
// Flush the recv desc assembly window.
//
FlushRecvDescWindow(BundleCB);
}
//
// See if we can complete some frames!!!!
//
TryToAssembleFrame(BundleCB);
NdisReleaseSpinLock(&BundleCB->Lock);
}
VOID
UpdateMinRecvSeqNumber(
PBUNDLECB BundleCB
)
{
PLINKCB LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("MinReceived c %8.8x", BundleCB->MinReceivedSeqNumber));
BundleCB->MinReceivedSeqNumber = LinkCB->LastRecvSeqNumber;
for (LinkCB = (PLINKCB)LinkCB->Linkage.Flink;
(PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
if (SEQ_LT(LinkCB->LastRecvSeqNumber,
BundleCB->MinReceivedSeqNumber,
BundleCB->RecvSeqTest)) {
BundleCB->MinReceivedSeqNumber = LinkCB->LastRecvSeqNumber;
}
}
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("MinReceived n %8.8x", BundleCB->MinReceivedSeqNumber));
}
VOID
FindHoleInRecvList(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
/*++
Routine Name:
Routine Description:
We want to start at the spot where the current hole was removed
from and look for adjoining recv desc's in the list who have
sequence numbers that differ by more than 1.
Arguments:
Return Values:
--*/
{
PRECV_DESC NextRecvDesc, RecvDescHole;
ULONG SequenceNumber;
PLIST_ENTRY RecvList;
RecvDescHole = BundleCB->RecvDescHole;
RecvList = &BundleCB->RecvDescAssemblyList;
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("h: %8.8x", RecvDescHole->SequenceNumber));
if (IsListEmpty(RecvList)) {
//
// Set the new sequence number
//
RecvDescHole->SequenceNumber += 1;
RecvDescHole->SequenceNumber &= BundleCB->RecvSeqMask;
//
// Put the hole back on the list
//
InsertHeadList(RecvList, &RecvDescHole->Linkage);
} else {
//
// Walk the list looking for two descriptors that have
// sequence numbers differing by more than 1 or until we
// get to the end of the list
//
NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
SequenceNumber = RecvDesc->SequenceNumber;
while (((PVOID)NextRecvDesc != (PVOID)RecvList) &&
(((NextRecvDesc->SequenceNumber - RecvDesc->SequenceNumber) &
BundleCB->RecvSeqMask) == 1)) {
RecvDesc = NextRecvDesc;
NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
SequenceNumber = RecvDesc->SequenceNumber;
}
RecvDescHole->SequenceNumber = SequenceNumber + 1;
RecvDescHole->SequenceNumber &= BundleCB->RecvSeqMask;
RecvDescHole->Linkage.Flink = (PLIST_ENTRY)NextRecvDesc;
RecvDescHole->Linkage.Blink = (PLIST_ENTRY)RecvDesc;
RecvDesc->Linkage.Flink =
NextRecvDesc->Linkage.Blink =
(PLIST_ENTRY)RecvDescHole;
}
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("nh: %8.8x", RecvDescHole->SequenceNumber));
}
VOID
NdisWanGetRecvDesc(
PBUNDLECB BundleCB,
PRECV_DESC *ReturnRecvDesc
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PRECV_DESC RecvDesc = NULL;
ULONG i;
//
// Try the local pool first
//
if (BundleCB != NULL
&& !IsListEmpty(&BundleCB->RecvDescPool)) {
RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescPool);
BundleCB->RecvDescCount--;
} else {
//
// Since the local pool is empty we will
// try to get a desc from the global pool
//
// MAX_MRRU -> Data packet
// 14 -> Ethernet Header
// 128 -> Used for VJ header compression
// 3 * sizeof(PVOID) -> DWORD alignment
if (IsListEmpty(&GlobalRecvDescPool.List)) {
ULONG AllocationSize = sizeof(RECV_DESC) +
MAX_MRRU + 14 + 128 + 3 * sizeof(PVOID);
for (i = 0; i < 10; i++) {
//
// The global list is empty so we need to allocate
// some more
//
NdisWanAllocateMemory(&RecvDesc, AllocationSize);
if (RecvDesc != NULL) {
RecvDesc->AllocationSize = AllocationSize;
RecvDesc->WanHeader = (PUCHAR)RecvDesc + sizeof(RECV_DESC) + sizeof(PVOID);
(ULONG)RecvDesc->WanHeader &= (ULONG)~(sizeof(PVOID) - 1);
RecvDesc->LookAhead = RecvDesc->WanHeader + 14 + sizeof(PVOID);
(ULONG)RecvDesc->LookAhead &= (ULONG)~(sizeof(PVOID) - 1);
RecvDesc->StartBuffer = RecvDesc->LookAhead + 128 + sizeof(PVOID);
(ULONG)RecvDesc->StartBuffer &= (ULONG)~(sizeof(PVOID) - 1);
RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
NdisWanInterlockedInsertTailList(&GlobalRecvDescPool.List,
&RecvDesc->Linkage,
&GlobalRecvDescPool.Lock.SpinLock);
NdisWanInterlockedInc(&GlobalRecvDescPool.ulCount);
} else {
//
// Memory allocation failed!
//
break;
}
}
}
if (!IsListEmpty(&GlobalRecvDescPool.List)) {
RecvDesc =
(PRECV_DESC)NdisWanInterlockedRemoveHeadList(&GlobalRecvDescPool.List,
&GlobalRecvDescPool.Lock.SpinLock);
NdisWanInterlockedDec(&GlobalRecvDescPool.ulCount);
RecvDesc->BundleCB = BundleCB;
}
}
if (RecvDesc) {
ASSERT(RecvDesc->RefCount == 0);
NdisWanInterlockedInc(&RecvDesc->RefCount);
}
*ReturnRecvDesc = RecvDesc;
}
VOID
NdisWanReturnRecvDesc(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
{
if (NdisWanInterlockedDec(&RecvDesc->RefCount) == 0) {
if (BundleCB->State == BUNDLE_UP &&
BundleCB->RecvDescCount < BundleCB->RecvDescMax) {
//
// Return receive descriptor to bundle list
//
InsertTailList(&BundleCB->RecvDescPool, &RecvDesc->Linkage);
BundleCB->RecvDescCount++;
} else {
//
// Return receive descriptor to global list
//
NdisWanInterlockedInsertTailList(&GlobalRecvDescPool.List,
&RecvDesc->Linkage,
&GlobalRecvDescPool.Lock.SpinLock);
NdisWanInterlockedInc(&GlobalRecvDescPool.ulCount);
}
}
}
VOID
FlushRecvDescWindow(
IN PBUNDLECB BundleCB
)
/*++
Routine Name:
FlushRecvDescWindow
Routine Description:
This routine is called to flush recv desc's from the assembly list when
a fragment loss is detected. The idea is to flush fragments until we find
a begin fragment that has a sequence number >= the minimum received fragment
on the bundle.
Arguments:
--*/
{
PRECV_DESC RecvDescHole = BundleCB->RecvDescHole;
PRECV_DESC TempDesc;
ULONG Flags;
//
// Remove all recvdesc's until we find the hole
//
while (!IsListEmpty(&BundleCB->RecvDescAssemblyList)) {
TempDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescAssemblyList);
if (TempDesc == RecvDescHole) {
break;
}
BundleCB->RecvFragmentsLost++;
TempDesc->LinkCB->RecvFragmentsLost++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("flw %8.8x %8.8x h: %8.8x", TempDesc->SequenceNumber,
TempDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanReturnRecvDesc(BundleCB, TempDesc);
}
//
// Now flush all recvdesc's until we find a begin fragment that has a
// sequence number >= M or the list is empty.
//
while (!IsListEmpty(&BundleCB->RecvDescAssemblyList)) {
TempDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
Flags = TempDesc->Flags;
if (TempDesc->Flags & MULTILINK_BEGIN_FRAME) {
break;
}
BundleCB->RecvFragmentsLost++;
TempDesc->LinkCB->RecvFragmentsLost++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("flw %8.8x %8.8x h: %8.8x", TempDesc->SequenceNumber,
TempDesc->Flags, RecvDescHole->SequenceNumber));
RecvDescHole->SequenceNumber = TempDesc->SequenceNumber;
RemoveEntryList(&TempDesc->Linkage);
NdisWanReturnRecvDesc(BundleCB, TempDesc);
TempDesc == NULL;
}
//
// Now reinsert the hole desc.
//
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("h: %8.8x", RecvDescHole->SequenceNumber));
FindHoleInRecvList(BundleCB, TempDesc);
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("nh: %8.8x", RecvDescHole->SequenceNumber));
}
VOID
FlushRecvDescAssemblyList(
IN PBUNDLECB BundleCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PRECV_DESC RecvDesc;
while (!IsListEmpty(&BundleCB->RecvDescAssemblyList)) {
RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescAssemblyList);
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
}
}
VOID
FreeRecvDescFreeList(
IN PBUNDLECB BundleCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PRECV_DESC RecvDesc;
while (!IsListEmpty(&BundleCB->RecvDescPool)) {
RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescPool);
NdisWanInterlockedInsertTailList(&GlobalRecvDescPool.List,
&RecvDesc->Linkage,
&GlobalRecvDescPool.Lock.SpinLock);
NdisWanInterlockedInc(&GlobalRecvDescPool.ulCount);
}
}
VOID
TryToAssembleFrame(
PBUNDLECB BundleCB
)
/*++
Routine Name:
TryToAssembleFrame
Routine Description:
The goal here is to walk the recv list looking for a full frame
(BeginFlag, EndFlag, no holes in between). If we do not have a
full frame we return FALSE.
If we have a full frame we remove each desc from the assembly list
copying the data into the first desc and returning all of the desc's
except the first one to the free pool. Once all of the data had been
collected we process the frame. After the frame has been processed
we return the first desc to the free pool.
Arguments:
Return Values:
--*/
{
PRECV_DESC RecvDesc, RecvDescHole;
ULONG MaxRRecvFrameSize;
PUCHAR DataPointer;
RecvDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
RecvDescHole = BundleCB->RecvDescHole;
//
// If we are already doing some receive processing get out.
//
if (BundleCB->Flags & IN_RECEIVE) {
return;
}
TryToAssembleAgain:
while ((RecvDesc != RecvDescHole) &&
(RecvDesc->Flags & MULTILINK_BEGIN_FRAME)) {
PRECV_DESC NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
MaxRRecvFrameSize = BundleCB->FramingInfo.MaxRRecvFrameSize;
DataPointer = RecvDesc->CurrentBuffer + RecvDesc->CurrentBufferLength;
while ((NextRecvDesc != RecvDescHole) &&
!(RecvDesc->Flags & MULTILINK_END_FRAME)) {
RemoveEntryList(&NextRecvDesc->Linkage);
ASSERT(NextRecvDesc != RecvDescHole);
ASSERT(RecvDesc != RecvDescHole);
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("c 0x%8.8x -> 0x%8.8x",
NextRecvDesc->SequenceNumber, RecvDesc->SequenceNumber));
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("fl 0x%8.8x -> 0x%8.8x",
NextRecvDesc->Flags, RecvDesc->Flags));
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("l %d -> %d",
NextRecvDesc->CurrentBufferLength, RecvDesc->CurrentBufferLength));
//
// Update recvdesc info
//
RecvDesc->Flags |= NextRecvDesc->Flags;
RecvDesc->SequenceNumber = NextRecvDesc->SequenceNumber;
RecvDesc->CurrentBufferLength += NextRecvDesc->CurrentBufferLength;
//
// Make sure we don't assemble something too big!
//
if (RecvDesc->CurrentBufferLength > MaxRRecvFrameSize) {
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("Max receive size exceeded!"));
//
// Return the recv desc's
//
RemoveEntryList(&RecvDesc->Linkage);
BundleCB->RecvFragmentsLost += 2;
RecvDesc->LinkCB->RecvFragmentsLost += 2;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dumping %8.8x %8.8x h: %8.8x", RecvDesc->SequenceNumber,
RecvDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dumping %8.8x %8.8x h: %8.8x", NextRecvDesc->SequenceNumber,
NextRecvDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanReturnRecvDesc(BundleCB, NextRecvDesc);
//
// Start at the list head and flush until we find either the hole
// or a new begin fragment.
//
RecvDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
while (RecvDesc != RecvDescHole &&
!(RecvDesc->Flags & MULTILINK_BEGIN_FRAME)) {
RemoveHeadList(&BundleCB->RecvDescAssemblyList);
BundleCB->RecvFragmentsLost += 1;
RecvDesc->LinkCB->RecvFragmentsLost += 1;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dumping %8.8x %8.8x h: %8.8x", RecvDesc->SequenceNumber,
RecvDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
}
goto TryToAssembleAgain;
}
NdisMoveMemory(DataPointer,
NextRecvDesc->CurrentBuffer,
NextRecvDesc->CurrentBufferLength);
DataPointer += NextRecvDesc->CurrentBufferLength;
NdisWanReturnRecvDesc(BundleCB, NextRecvDesc);
NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
}
//
// We hit a hole before completion of the frame.
// Get out.
//
if (!IsCompleteFrame(RecvDesc->Flags)) {
return;
}
//
// If we made it here we must have a begin flag, end flag, and
// no hole in between. Let's build a frame.
//
RecvDesc = (PRECV_DESC)RemoveHeadList(&BundleCB->RecvDescAssemblyList);
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("a %8.8x %8.8x", RecvDesc->SequenceNumber, RecvDesc->Flags));
RecvDesc->LinkCB = NULL;
BundleCB->Flags |= IN_RECEIVE;
NdisReleaseSpinLock(&BundleCB->Lock);
ProcessFrame(BundleCB, RecvDesc);
NdisAcquireSpinLock(&BundleCB->Lock);
BundleCB->Flags &= ~IN_RECEIVE;
RecvDesc = (PRECV_DESC)BundleCB->RecvDescAssemblyList.Flink;
} // end of while MULTILINK_BEGIN_FRAME
}
VOID
ProcessFrame(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PPROTOCOLCB ProtocolCB = NULL;
PADAPTERCB AdapterCB;
PLINKCB LinkCB;
PUCHAR FramePointer;
ULONG BundleFraming, FrameLength;
PWAN_STATS BundleStats;
USHORT PPPProtocolID = 0;
ULONG i, LookAheadLength = 0;
ULONG TotalLength;
PUCHAR WanHeader;
PUCHAR LookAhead;
NDISWAN_RECV_CONTEXT ReceiveContext;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProcessFrame: Enter"));
//
// We do not have an active link or we have a zero
// length packet, so drop the receive.
//
if (BundleCB->State != BUNDLE_UP ||
RecvDesc->CurrentBufferLength == 0) {
goto PROCESS_FRAME_EXIT;
}
LinkCB = (RecvDesc->LinkCB == NULL) ?
(PLINKCB)BundleCB->LinkCBList.Flink : RecvDesc->LinkCB;
FramePointer = RecvDesc->CurrentBuffer;
FrameLength = RecvDesc->CurrentBufferLength;
WanHeader = RecvDesc->WanHeader;
LookAhead = RecvDesc->LookAhead;
BundleFraming = BundleCB->FramingInfo.RecvFramingBits;
BundleStats = &BundleCB->BundleStats;
BundleStats->FramesReceived++;
if (BundleFraming & PPP_FRAMING) {
//
// Get the PPP Protocol id
// 0xC1 is SPAP - Shiva hack!
//
if ((*FramePointer & 1) &&
(*FramePointer != 0xC1) &&
(*FramePointer != 0xCF)) {
//
// Field is compressed
//
PPPProtocolID = *FramePointer;
FramePointer++;
FrameLength--;
} else {
//
// Field is not compressed
//
PPPProtocolID = (*FramePointer << 8) | *(FramePointer + 1);
FramePointer += 2;
FrameLength -= 2;
}
//
// Is this a compressed frame?
//
if (PPPProtocolID == PPP_PROTOCOL_COMPRESSION) {
if (!DoDecompDecryptProcessing(BundleCB,
LinkCB,
&FramePointer,
&FrameLength)){
goto PROCESS_FRAME_EXIT;
}
//
// Get the new PPPProtocolID
//
if (*FramePointer & 1) {
//
// Field is compressed
//
PPPProtocolID = *FramePointer;
FramePointer++;
FrameLength--;
} else {
PPPProtocolID = (*FramePointer << 8) | *(FramePointer + 1);
FramePointer += 2;
FrameLength -= 2;
}
//end of PPP_PROTOCOL_COMPRESSED
} else if ((PPPProtocolID == PPP_PROTOCOL_COMP_RESET) &&
(*FramePointer == 14)) {
if (NdisWanCB.PromiscuousAdapter != NULL) {
RecvDesc->LookAheadLength = 0;
RecvDesc->WanHeader[0] =
RecvDesc->WanHeader[6] = ' ';
RecvDesc->WanHeader[1] =
RecvDesc->WanHeader[7] = 'R';
RecvDesc->WanHeader[2] =
RecvDesc->WanHeader[8] = 'E';
RecvDesc->WanHeader[3] =
RecvDesc->WanHeader[9] = 'C';
RecvDesc->WanHeader[4] =
RecvDesc->WanHeader[10] = 'V';
RecvDesc->WanHeader[5] =
RecvDesc->WanHeader[11] = (UCHAR)LinkCB->hLinkHandle;
RecvDesc->WanHeader[12] = (UCHAR)(PPPProtocolID >> 8);
RecvDesc->WanHeader[13] = (UCHAR)PPPProtocolID;
RecvDesc->WanHeaderLength = 14;
RecvDesc->CurrentBuffer = FramePointer;
RecvDesc->CurrentBufferLength = FrameLength;
//
// Queue the packet on the promiscous adapter
//
QueuePromiscuousReceive(RecvDesc);
}
//
// Compression reset!
//
DoCompressionReset(BundleCB);
goto PROCESS_FRAME_EXIT;
} // end of compression reset
// end of PPP_FRAMING
} else {
if (BundleFraming & RAS_FRAMING) {
//
// Must be RAS framing
//
// For normal NBF frames, first byte is always the DSAP
// i.e 0xF0 followed by SSAP 0xF0 or 0xF1
//
//
if (*FramePointer == 14) {
//
// Compression reset!
//
DoCompressionReset(BundleCB);
goto PROCESS_FRAME_EXIT;
}
if (*FramePointer == 0xFD) {
//
// Skip over 0xFD
//
FramePointer++;
FrameLength--;
//
// Decompress as if an NBF PPP Packet
//
if (!DoDecompDecryptProcessing(BundleCB,
LinkCB,
&FramePointer,
&FrameLength)){
//
// There was an error get out!
//
goto PROCESS_FRAME_EXIT;
}
}
//
// Make frame look like an NBF PPP packet
//
PPPProtocolID = PPP_PROTOCOL_NBF;
} // end of RAS framing
} // end of non-ppp framing
//
// If this is slip or if the ProtocolID == PPP_PROTOCOL_COMPRESSED_TCP ||
// ProtocolID == PPP_PROTOCOL_UNCOMPRESSED_TCP
//
if ((BundleFraming & SLIP_FRAMING) ||
((PPPProtocolID == PPP_PROTOCOL_COMPRESSED_TCP) ||
(PPPProtocolID == PPP_PROTOCOL_UNCOMPRESSED_TCP))) {
if (!DoVJDecompression(BundleCB, // Bundle
PPPProtocolID, // ProtocolID
&FramePointer, // Input buffer
&FrameLength, // Input length
LookAhead, // Output buffer
&LookAheadLength)) {
goto PROCESS_FRAME_EXIT;
}
PPPProtocolID = PPP_PROTOCOL_IP;
// end of check for VJ header compression
}
if ((PPPProtocolID >= 0x8000) ||
(BundleCB->ulNumberOfRoutes == 1)) {
RecvDesc->CurrentBufferLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
//
// Either this frame is an LCP, NCP or we have no routes yet.
// Indicate to PPP engine.
//
CompleteIoRecvPacket(BundleCB,
LinkCB,
PPPProtocolID,
RecvDesc);
goto PROCESS_FRAME_EXIT;
}
//
// We need to find a protocol to indicate this frame to.
//
NdisAcquireSpinLock(&BundleCB->Lock);
if (BundleCB->State != BUNDLE_UP) {
NdisReleaseSpinLock(&BundleCB->Lock);
goto PROCESS_FRAME_EXIT;
}
for (i = 1; i < BundleCB->ulNumberOfRoutes; i++) {
ProtocolCB = BundleCB->ProtocolCBTable[i];
if (IsValidProtocolCB(ProtocolCB) &&
(PPPProtocolID == ProtocolCB->usPPPProtocolID)) {
break;
}
}
if (!IsValidProtocolCB(ProtocolCB) ||
!(ProtocolCB->Flags & PROTOCOL_ROUTED)) {
NdisReleaseSpinLock(&BundleCB->Lock);
goto PROCESS_FRAME_EXIT;
}
AdapterCB = ProtocolCB->AdapterCB;
//
// We found a valid protocol to indicate this frame to!
//
//
// Fill the WanHeader dest address with the transports context
//
ETH_COPY_NETWORK_ADDRESS(WanHeader, ProtocolCB->TransportAddress);
if (PPPProtocolID == PPP_PROTOCOL_NBF) {
//
// For nbf fill the length field
//
WanHeader[12] = (UCHAR)(FrameLength >> 8);
WanHeader[13] = (UCHAR)FrameLength;
if (!(BundleFraming & NBF_PRESERVE_MAC_ADDRESS)) {
goto USE_OUR_ADDRESS;
}
//
// For nbf and preserve mac address option (SHIVA_FRAMING)
// we keep the source address.
//
ETH_COPY_NETWORK_ADDRESS(&WanHeader[6], FramePointer + 6);
FramePointer += 12;
FrameLength -= 12;
//
// For nbf fill the length field
//
WanHeader[12] = (UCHAR)(FrameLength >> 8);
WanHeader[13] = (UCHAR)FrameLength;
} else {
//
// For other protocols fill the protocol type
//
WanHeader[12] = (UCHAR)(ProtocolCB->usProtocolType >> 8);
WanHeader[13] = (UCHAR)ProtocolCB->usProtocolType;
//
// Use our address for the src address
//
USE_OUR_ADDRESS:
ETH_COPY_NETWORK_ADDRESS(&WanHeader[6], ProtocolCB->NdisWanAddress);
}
ASSERT(WanHeader == RecvDesc->WanHeader);
RecvDesc->WanHeaderLength = 14;
RecvDesc->LookAheadLength = LookAheadLength;
RecvDesc->CurrentBufferLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
//
// Check for non-idle data
//
if (ProtocolCB->NonIdleDetectFunc != NULL) {
PUCHAR HeaderBuffer;
ULONG HeaderLength, TotalLength;
HeaderBuffer = (LookAheadLength != 0) ? LookAhead : FramePointer;
HeaderLength = (LookAheadLength != 0) ? LookAheadLength : FrameLength;
TotalLength = LookAheadLength + FrameLength;
if (TRUE == ProtocolCB->NonIdleDetectFunc(HeaderBuffer, HeaderLength, TotalLength)) {
NdisWanGetSystemTime(&ProtocolCB->LastRecvNonIdleData);
BundleCB->LastRecvNonIdleData = ProtocolCB->LastRecvNonIdleData;
}
}
NdisReleaseSpinLock(&BundleCB->Lock);
if ((AdapterCB->ulReferenceCount == 0) &&
NdisWanAcquireMiniportLock(AdapterCB)) {
NdisAcquireSpinLock(&AdapterCB->Lock);
if (IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[ReceiveIndication])) {
AdapterCB->Flags |= RECEIVE_COMPLETE;
NdisWanSetDeferred(AdapterCB);
NdisReleaseSpinLock(&AdapterCB->Lock);
TotalLength = FrameLength + LookAheadLength;
if (LookAheadLength == 0) {
LookAhead = FramePointer;
LookAheadLength = FrameLength;
}
ASSERT((LONG)TotalLength > 0);
if (NdisWanCB.PromiscuousAdapter != NULL) {
//
// Queue the packet on the promiscous adapter
//
QueuePromiscuousReceive(RecvDesc);
}
//
// We got the lock and there are no pending receive
// indications so go ahead and indicate the frame to the protocol
//
NdisMEthIndicateReceive(AdapterCB->hMiniportHandle,
RecvDesc,
WanHeader,
14,
LookAhead,
LookAheadLength,
TotalLength);
NdisWanReleaseMiniportLock(AdapterCB);
goto PROCESS_FRAME_EXIT;
}
NdisReleaseSpinLock(&AdapterCB->Lock);
NdisWanReleaseMiniportLock(AdapterCB);
}
QueueDeferredReceive(AdapterCB, RecvDesc);
PROCESS_FRAME_EXIT:
NdisAcquireSpinLock(&BundleCB->Lock);
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
NdisReleaseSpinLock(&BundleCB->Lock);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProcessFrame: Exit"));
return;
}
VOID
QueueDeferredReceive(
PADAPTERCB AdapterCB,
PRECV_DESC RecvDesc
)
{
PDEFERRED_DESC DeferredDesc;
//
// The current buffer pointer may point to the decompressor's context
// We cannot leave the data in the decompressor so we need to copy it
// back to the receive descriptor so we check to see if the current
// buffer pointer is already pointing to somewhere in the receive descriptor
// If it is we do not need to do the copy.
//
if (RecvDesc->CurrentBuffer < RecvDesc->StartBuffer ||
RecvDesc->CurrentBuffer > RecvDesc->StartBuffer + MAX_MRRU) {
PUCHAR FramePointer;
ULONG FrameLength;
FramePointer = RecvDesc->CurrentBuffer;
FrameLength = RecvDesc->CurrentBufferLength;
RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
NdisMoveMemory(RecvDesc->CurrentBuffer,
FramePointer,
FrameLength);
}
NdisAcquireSpinLock(&AdapterCB->Lock);
NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
NdisWanInterlockedInc(&RecvDesc->RefCount);
DeferredDesc->Context = RecvDesc;
InsertTailDeferredQueue(&AdapterCB->DeferredQueue[ReceiveIndication],
DeferredDesc);
NdisWanSetDeferred(AdapterCB);
NdisReleaseSpinLock(&AdapterCB->Lock);
}
BOOLEAN
DoVJDecompression(
PBUNDLECB BundleCB,
USHORT ProtocolID,
PUCHAR *DataPointer,
PULONG DataLength,
PUCHAR Header,
PULONG HeaderLength
)
{
ULONG BundleFraming;
PUCHAR FramePointer = *DataPointer;
ULONG FrameLength = *DataLength;
UCHAR VJCompType = 0;
BOOLEAN DoDecomp = FALSE;
BOOLEAN VJDetect = FALSE;
*HeaderLength = 0;
BundleFraming = BundleCB->FramingInfo.RecvFramingBits;
if (BundleFraming & SLIP_FRAMING) {
VJCompType = *FramePointer & 0xF0;
//
// If the packet is compressed the header has to be atleast 3 bytes long.
// If this is a regular IP packet we do not decompress it.
//
if ((FrameLength > 2) && (VJCompType != TYPE_IP)) {
if (VJCompType & 0x80) {
VJCompType = TYPE_COMPRESSED_TCP;
} else if (VJCompType == TYPE_UNCOMPRESSED_TCP) {
*FramePointer &= 0x4F;
}
//
// If framing is set for detection, in order for this to be a good
// frame for detection we need a type of UNCOMPRESSED_TCP and a
// frame that is atleast 40 bytes long.
//
VJDetect = ((BundleFraming & SLIP_VJ_AUTODETECT) &&
(VJCompType == TYPE_UNCOMPRESSED_TCP) &&
(FrameLength > 39));
if ((BundleCB->VJCompress != NULL) &&
((BundleFraming & SLIP_VJ_COMPRESSION) || VJDetect)) {
//
// If VJ compression is set or if we are in
// autodetect and this looks like a reasonable
// frame
//
DoDecomp = TRUE;
}
}
// end of SLIP_FRAMING
} else {
//
// Must be PPP framing
//
if (ProtocolID == PPP_PROTOCOL_COMPRESSED_TCP) {
VJCompType = TYPE_COMPRESSED_TCP;
} else {
VJCompType = TYPE_UNCOMPRESSED_TCP;
}
DoDecomp = TRUE;
}
if (DoDecomp) {
ULONG PreCompSize = *DataLength;
ULONG PostCompSize;
if (BundleCB->VJCompress == NULL) {
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("RecvVJCompress == NULL!"));
return(FALSE);
}
NdisWanDbgOut(DBG_INFO, DBG_RECV_VJ,
("rvj %2.2x %d", VJCompType, PreCompSize));
if ((PostCompSize = sl_uncompress_tcp(DataPointer,
DataLength,
Header,
HeaderLength,
VJCompType,
BundleCB->VJCompress)) == 0) {
NdisWanDbgOut(DBG_INFO, DBG_RECV_VJ,
("rvj decomp error!"));
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Error in sl_uncompress_tcp!"));
return(FALSE);
}
if (VJDetect) {
NdisAcquireSpinLock(&BundleCB->Lock);
BundleCB->FramingInfo.RecvFramingBits |= SLIP_VJ_COMPRESSION;
BundleCB->FramingInfo.SendFramingBits |= SLIP_VJ_COMPRESSION;
NdisReleaseSpinLock(&BundleCB->Lock);
}
PostCompSize = *DataLength + *HeaderLength;
//
// Calculate how much expansion we had
//
BundleCB->BundleStats.BytesReceivedCompressed +=
(40 - (PostCompSize - PreCompSize));
BundleCB->BundleStats.BytesReceivedUncompressed += 40;
NdisWanDbgOut(DBG_INFO, DBG_RECV_VJ,
("rvj %d", PostCompSize));
}
return(TRUE);
}
BOOLEAN
DoDecompDecryptProcessing(
PBUNDLECB BundleCB,
PLINKCB LinkCB,
PUCHAR *DataPointer,
PULONG DataLength
)
{
USHORT Coherency;
PNDISWAN_IO_PACKET IoPacket;
ULONG Flags;
PWAN_STATS BundleStats;
PUCHAR FramePointer = *DataPointer;
ULONG FrameLength = *DataLength;
Flags = ((BundleCB->RecvCompInfo.MSCompType & NDISWAN_COMPRESSION) &&
(BundleCB->RecvCompressContext != NULL)) ? DO_COMPRESSION : 0;
if (BundleCB->RecvRC4Key != NULL) {
if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_ENCRYPTION) {
Flags |= (DO_ENCRYPTION | DO_LEGACY_ENCRYPTION);
} else if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_40_ENCRYPTION) {
Flags |= (DO_ENCRYPTION | DO_40_ENCRYPTION);
}
#ifdef ENCRYPT_128BIT
else if (BundleCB->RecvCompInfo.MSCompType & NDISWAN_128_ENCRYPTION) {
Flags |= (DO_ENCRYPTION | DO_128_ENCRYPTION);
}
#endif
}
BundleStats = &BundleCB->BundleStats;
if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
PUCHAR SessionKey = BundleCB->RecvEncryptInfo.SessionKey;
ULONG SessionKeyLength = BundleCB->RecvEncryptInfo.SessionKeyLength;
PVOID RecvRC4Key = BundleCB->RecvRC4Key;
PVOID RecvCompressContext = BundleCB->RecvCompressContext;
//
// Get the coherency counter
//
Coherency = (*FramePointer << 8) | *(FramePointer + 1);
FramePointer += 2;
FrameLength -= 2;
if (SEQ_LT(Coherency & 0x0FFF,
BundleCB->RCoherencyCounter & 0x0FFF,
0x0800)) {
//
// We received a sequence number that is less then the
// expected sequence number so we must be way out of sync
//
#if DBG
DbgPrint("NDISWAN: !!!!rc %4.4x < ec %4.4x!!!!\n", Coherency & 0x0FFF,
BundleCB->RCoherencyCounter & 0x0FFF);
#endif
goto RESYNC;
}
//
// See if this is a flush packet
//
if (Coherency & (PACKET_FLUSHED << 8)) {
NdisWanDbgOut(DBG_INFO, DBG_RECEIVE,
("Recv Packet Flushed 0x%4.4x\n", (Coherency & 0x0FFF)));
if ((BundleCB->RCoherencyCounter & 0x0FFF) >
(Coherency & 0x0FFF)) {
BundleCB->RCoherencyCounter += 0x1000;
}
BundleCB->RCoherencyCounter &= 0xF000;
BundleCB->RCoherencyCounter |= (Coherency & 0x0FFF);
if (Flags & DO_ENCRYPTION) {
//
// Re-Init the rc4 receive table
//
rc4_key(RecvRC4Key,
SessionKeyLength,
SessionKey);
}
if (Flags & DO_COMPRESSION) {
//
// Initialize the decompression history table
//
initrecvcontext(RecvCompressContext);
}
} // end of packet flushed
if ((Coherency & 0x0FFF) == (BundleCB->RCoherencyCounter & 0x0FFF)) {
//
// We are still in sync
//
BundleCB->RCoherencyCounter++;
if (Coherency & (PACKET_ENCRYPTED << 8)) {
//
// This packet is encrypted
//
if (!(Flags & DO_ENCRYPTION)) {
//
// We are not configured to decrypt
//
return (FALSE);
}
if ((BundleCB->RCoherencyCounter - BundleCB->LastRC4Reset)
>= 0x100) {
//
// It is time to change encryption keys
//
//
// Always align last reset on 0x100 boundary so as not to
// propagate error!
//
BundleCB->LastRC4Reset = BundleCB->RCoherencyCounter & 0xFF00;
//
// Prevent ushort rollover
//
if ((BundleCB->LastRC4Reset & 0xF000) == 0xF000) {
BundleCB->LastRC4Reset &= 0x0FFF;
BundleCB->RCoherencyCounter &= 0x0FFF;
}
if (Flags & DO_LEGACY_ENCRYPTION) {
//
// Change the session key
//
SessionKey[3] += 1;
SessionKey[4] += 3;
SessionKey[5] += 13;
SessionKey[6] += 57;
SessionKey[7] += 19;
} else {
//
// Change the session key
//
GetNewKeyFromSHA(&BundleCB->RecvEncryptInfo);
}
//
// We use rc4 to scramble and recover a new key
//
//
// Re-initialize the rc4 receive table to the
// intermediate value
//
rc4_key(RecvRC4Key, SessionKeyLength, SessionKey);
//
// Scramble the existing session key
//
rc4(RecvRC4Key, SessionKeyLength, SessionKey);
//
// If this is 40 bit encryption we need to fix
// the first 3 bytes of the key.
//
#ifdef ENCRYPT_128BIT
if (!(Flags & DO_128_ENCRYPTION)) {
#endif
//
// Re-Salt the first 3 bytes
//
SessionKey[0] = 0xD1;
SessionKey[1] = 0x26;
SessionKey[2] = 0x9E;
#ifdef ENCRYPT_128BIT
}
#endif
NdisWanDbgOut(DBG_TRACE, DBG_CCP,
("RC4 Recv encryption KeyLength %d", BundleCB->RecvEncryptInfo.SessionKeyLength));
NdisWanDbgOut(DBG_TRACE, DBG_CCP,
("RC4 Recv encryption Key %.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
BundleCB->RecvEncryptInfo.SessionKey[0],
BundleCB->RecvEncryptInfo.SessionKey[1],
BundleCB->RecvEncryptInfo.SessionKey[2],
BundleCB->RecvEncryptInfo.SessionKey[3],
BundleCB->RecvEncryptInfo.SessionKey[4],
BundleCB->RecvEncryptInfo.SessionKey[5],
BundleCB->RecvEncryptInfo.SessionKey[6],
BundleCB->RecvEncryptInfo.SessionKey[7],
BundleCB->RecvEncryptInfo.SessionKey[8],
BundleCB->RecvEncryptInfo.SessionKey[9],
BundleCB->RecvEncryptInfo.SessionKey[10],
BundleCB->RecvEncryptInfo.SessionKey[11],
BundleCB->RecvEncryptInfo.SessionKey[12],
BundleCB->RecvEncryptInfo.SessionKey[13],
BundleCB->RecvEncryptInfo.SessionKey[14],
BundleCB->RecvEncryptInfo.SessionKey[15]));
// Re-initialize the rc4 receive table to the
// scrambled session key
//
rc4_key(RecvRC4Key, SessionKeyLength, SessionKey);
} // end of reset encryption key
//
// Decrypt the data!
//
rc4(RecvRC4Key,
FrameLength,
FramePointer);
} // end of encryption
if (Coherency & (PACKET_COMPRESSED << 8)) {
//
// This packet is compressed!
//
if (!(Flags & DO_COMPRESSION)) {
//
// We are not configured to decompress
//
return (FALSE);
}
//
// Add up bundle stats
//
BundleStats->BytesReceivedCompressed += FrameLength;
if (decompress(FramePointer,
FrameLength,
((Coherency & (PACKET_AT_FRONT << 8)) >> 8),
&FramePointer,
&FrameLength,
RecvCompressContext) == FALSE) {
#if DBG
DbgPrint("dce %4.4x\n", Coherency);
#endif
//
// Error decompressing!
//
BundleCB->RCoherencyCounter--;
goto RESYNC;
}
BundleStats->BytesReceivedUncompressed += FrameLength;
} // end of compression
} else { // end of insync
RESYNC:
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("oos r %4.4x, e %4.4x\n", (Coherency & 0x0FFF),
(BundleCB->RCoherencyCounter & 0x0FFF)));
//
// We are out of sync!
//
NdisWanAllocateMemory(&IoPacket, sizeof(NDISWAN_IO_PACKET) + 100);
if (IoPacket != NULL) {
NDIS_STATUS IoStatus;
IoPacket->hHandle = LinkCB->hLinkHandle;
IoPacket->usHandleType = LINKHANDLE;
IoPacket->usHeaderSize = 0;
IoPacket->usPacketSize = 6;
IoPacket->usPacketFlags = 0;
IoPacket->PacketData[0] = 0x80;
IoPacket->PacketData[1] = 0xFD;
IoPacket->PacketData[2] = 14;
IoPacket->PacketData[3] = BundleCB->CCPIdentifier++;
IoPacket->PacketData[4] = 0x00;
IoPacket->PacketData[5] = 0x04;
IoStatus = BuildIoPacket(IoPacket, FALSE);
NdisWanFreeMemory(IoPacket);
}
return (FALSE);
} // end of out of sync
} else { // end of DoCompEncrypt
//
// For some reason we were not able to
// decrypt/decompress!
//
return (FALSE);
}
*DataPointer = FramePointer;
*DataLength = FrameLength;
return (TRUE);
}
VOID
DoCompressionReset(
PBUNDLECB BundleCB
)
{
if (BundleCB->RecvCompInfo.MSCompType != 0) {
//
// The next outgoing packet will flush
//
NdisAcquireSpinLock(&BundleCB->Lock);
BundleCB->Flags |= RECV_PACKET_FLUSH;
NdisReleaseSpinLock(&BundleCB->Lock);
}
}
VOID
NdisWanReceiveComplete(
IN NDIS_HANDLE NdisLinkContext
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveComplete: Enter"));
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanReceiveComplete: Exit"));
}
NDIS_STATUS
NdisWanTransferData(
OUT PNDIS_PACKET NdisPacket,
OUT PUINT BytesTransferred,
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE MiniportReceiveContext,
IN UINT ByteOffset,
IN UINT BytesToTransfer
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PRECV_DESC RecvDesc;
PUCHAR LookAhead, FramePointer;
ULONG LookAheadLength, FrameLength;
ULONG BytesToCopy, BytesCopied, PacketOffset = 0;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanTransferData: Enter"));
RecvDesc = (PRECV_DESC)MiniportReceiveContext;
LookAhead = RecvDesc->LookAhead;
LookAheadLength = RecvDesc->LookAheadLength;
FramePointer = RecvDesc->CurrentBuffer;
FrameLength = RecvDesc->CurrentBufferLength;
*BytesTransferred = 0;
if (BytesToTransfer == 0) {
return (NDIS_STATUS_SUCCESS);
}
ASSERT(BytesToTransfer <= (FrameLength + LookAheadLength));
if ((ByteOffset < LookAheadLength) && (LookAheadLength != 0)) {
//
// First we will copy the lookahead bytes
//
BytesToCopy = LookAheadLength - ByteOffset;
BytesToCopy = (BytesToTransfer < BytesToCopy) ?
BytesToTransfer : BytesToCopy;
NdisWanCopyFromBufferToPacket(LookAhead + ByteOffset,
BytesToCopy,
NdisPacket,
PacketOffset,
&BytesCopied);
*BytesTransferred += BytesCopied;
PacketOffset += BytesCopied;
BytesToTransfer -= BytesCopied;
ByteOffset = 0;
}
if (FrameLength != 0) {
//
// Now we copy the rest of the frame
//
BytesToCopy = (BytesToTransfer < FrameLength) ?
BytesToTransfer : FrameLength;
NdisWanCopyFromBufferToPacket(FramePointer + ByteOffset,
BytesToCopy,
NdisPacket,
PacketOffset,
&BytesCopied);
*BytesTransferred += BytesCopied;
}
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("NdisWanTransferData: Exit"));
return (NDIS_STATUS_SUCCESS);
}
VOID
NdisWanCopyFromBufferToPacket(
PUCHAR Buffer,
ULONG BytesToCopy,
PNDIS_PACKET NdisPacket,
ULONG PacketOffset,
PULONG BytesCopied
)
{
PNDIS_BUFFER NdisBuffer;
ULONG NdisBufferCount, NdisBufferLength;
PVOID VirtualAddress;
ULONG LocalBytesCopied = 0;
*BytesCopied = 0;
//
// Make sure we actually want to do something
//
if (BytesToCopy == 0) {
return;
}
//
// Get the buffercount of the packet
//
NdisQueryPacket(NdisPacket,
NULL,
&NdisBufferCount,
&NdisBuffer,
NULL);
//
// Make sure this is not a null packet
//
if (NdisBufferCount == 0) {
return;
}
//
// Get first buffer and buffer length
//
NdisQueryBuffer(NdisBuffer,
&VirtualAddress,
&NdisBufferLength);
while (LocalBytesCopied < BytesToCopy) {
if (NdisBufferLength == 0) {
NdisGetNextBuffer(NdisBuffer,
&NdisBuffer);
if (NdisBuffer == NULL) {
break;
}
NdisQueryBuffer(NdisBuffer,
&VirtualAddress,
&NdisBufferLength);
continue;
}
if (PacketOffset != 0) {
if (PacketOffset > NdisBufferLength) {
PacketOffset -= NdisBufferLength;
NdisBufferLength = 0;
continue;
} else {
VirtualAddress = (PUCHAR)VirtualAddress + PacketOffset;
NdisBufferLength -= PacketOffset;
PacketOffset = 0;
}
}
//
// Copy the data
//
{
ULONG AmountToMove;
ULONG AmountRemaining;
AmountRemaining = BytesToCopy - LocalBytesCopied;
AmountToMove = (NdisBufferLength < AmountRemaining) ?
NdisBufferLength : AmountRemaining;
NdisMoveMemory((PUCHAR)VirtualAddress,
Buffer,
AmountToMove);
Buffer += AmountToMove;
LocalBytesCopied += AmountToMove;
NdisBufferLength -= AmountToMove;
}
}
*BytesCopied = LocalBytesCopied;
}
#if 0
ULONG
CalculatePPPHeaderLength(
PLINKCB LinkCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
ULONG PPPHeaderLength = 0;
ULONG LinkFraming = LinkCB->LinkInfo.RecvFramingBits;
if (LinkFraming & PPP_FRAMING) {
PPPHeaderLength += (LinkFraming & PPP_COMPRESS_ADDRESS_CONTROL) ? 0 : 2;
if (LinkFraming & PPP_MULTILINK_FRAMING) {
PPPHeaderLength += (LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD) ? 1 : 2;
PPPHeaderLength += (LinkFraming & PPP_SHORT_SEQUENCE_HDR_FORMAT) ? 2 : 4;
}
PPPHeaderLength += (LinkFraming & PPP_COMPRESS_PROTOCOL_FIELD) ? 1 : 2;
}
return (PPPHeaderLength);
}
#endif
VOID
NdisWanProcessReceiveIndications(
PADAPTERCB AdapterCB
)
{
while (!IsDeferredQueueEmpty(&AdapterCB->DeferredQueue[ReceiveIndication])) {
PRECV_DESC RecvDesc;
PBUNDLECB BundleCB;
PDEFERRED_DESC ReturnDesc;
ReturnDesc = RemoveHeadDeferredQueue(&AdapterCB->DeferredQueue[ReceiveIndication]);
RecvDesc = ReturnDesc->Context;
BundleCB = RecvDesc->BundleCB;
NdisAcquireSpinLock(&BundleCB->Lock);
if ((BundleCB->State == BUNDLE_UP) &&
(BundleCB->Flags & BUNDLE_ROUTED)) {
PUCHAR LookAhead;
ULONG LookAheadLength;
ULONG TotalLength = RecvDesc->LookAheadLength +
RecvDesc->CurrentBufferLength;
NdisReleaseSpinLock(&BundleCB->Lock);
if (RecvDesc->LookAheadLength == 0) {
LookAhead = RecvDesc->CurrentBuffer;
LookAheadLength = RecvDesc->CurrentBufferLength;
} else {
LookAhead = RecvDesc->LookAhead;
LookAheadLength = RecvDesc->LookAheadLength;
}
ASSERT((LONG)TotalLength > 0);
NdisReleaseSpinLock(&AdapterCB->Lock);
if (NdisWanCB.PromiscuousAdapter != NULL) {
//
// Queue the packet on the promiscous adapter
//
QueuePromiscuousReceive(RecvDesc);
}
NdisMEthIndicateReceive(AdapterCB->hMiniportHandle,
RecvDesc,
RecvDesc->WanHeader,
14,
LookAhead,
LookAheadLength,
TotalLength);
NdisAcquireSpinLock(&AdapterCB->Lock);
NdisAcquireSpinLock(&BundleCB->Lock);
}
NdisWanReturnRecvDesc(BundleCB, RecvDesc);
NdisReleaseSpinLock(&BundleCB->Lock);
InsertHeadDeferredQueue(&AdapterCB->FreeDeferredQueue, ReturnDesc);
}
}
VOID
QueuePromiscuousReceive(
PRECV_DESC RecvDesc
)
{
PADAPTERCB AdapterCB = NdisWanCB.PromiscuousAdapter;
PLOOPBACK_DESC LoopbackDesc;
ULONG AllocationSize, BufferLength;
PDEFERRED_DESC DeferredDesc;
PUCHAR DataOffset;
BufferLength = RecvDesc->WanHeaderLength +
RecvDesc->LookAheadLength +
RecvDesc->CurrentBufferLength;
AllocationSize = sizeof(LOOPBACK_DESC) + BufferLength;
NdisWanAllocateMemory(&LoopbackDesc, AllocationSize);
if (LoopbackDesc == NULL) {
return;
}
LoopbackDesc->AllocationSize = (USHORT)AllocationSize;
LoopbackDesc->BufferLength = (USHORT)BufferLength;
LoopbackDesc->Buffer = (PUCHAR)LoopbackDesc + sizeof(LOOPBACK_DESC);
//
// Copy all of the data
//
DataOffset = LoopbackDesc->Buffer;
NdisMoveMemory(DataOffset,
RecvDesc->WanHeader,
RecvDesc->WanHeaderLength);
DataOffset += RecvDesc->WanHeaderLength;
if (RecvDesc->LookAheadLength != 0) {
NdisMoveMemory(DataOffset,
RecvDesc->LookAhead,
RecvDesc->LookAheadLength);
DataOffset += RecvDesc->LookAheadLength;
}
NdisMoveMemory(DataOffset,
RecvDesc->CurrentBuffer,
RecvDesc->CurrentBufferLength);
NdisAcquireSpinLock(&AdapterCB->Lock);
NdisWanGetDeferredDesc(AdapterCB, &DeferredDesc);
if (DeferredDesc == NULL) {
NdisWanFreeMemory(LoopbackDesc);
return;
}
DeferredDesc->Context = (PVOID)LoopbackDesc;
InsertTailDeferredQueue(&AdapterCB->DeferredQueue[Loopback], DeferredDesc);
NdisWanSetDeferred(AdapterCB);
NdisReleaseSpinLock(&AdapterCB->Lock);
}
BOOLEAN
IpIsDataFrame(
PUCHAR HeaderBuffer,
ULONG HeaderBufferLength,
ULONG TotalLength
)
{
UINT tcpheaderlength ;
UINT ipheaderlength ;
UCHAR *tcppacket;
UCHAR *ippacket = HeaderBuffer;
IPHeader UNALIGNED *ipheader = (IPHeader UNALIGNED *) HeaderBuffer;
#define TYPE_UDP 17
#define UDPPACKET_SRC_PORT_137(x) ((UCHAR) *(x + ((*x & 0x0f)*4) + 1) == 137)
if (ipheader->ip_p == TYPE_UDP) {
if (!UDPPACKET_SRC_PORT_137(ippacket))
return TRUE ;
else {
//
// UDP port 137 - is wins traffic. we count this as idle traffic.
//
return FALSE ;
}
}
#define TYPE_TCP 6
#define TCPPACKET_SRC_OR_DEST_PORT_139(x,y) (((UCHAR) *(x + y + 1) == 139) || ((UCHAR) *(x + y + 3) == 139))
//
// TCP packets with SRC | DEST == 139 which are ACKs (0 data) or Session Alives
// are considered as idle
//
if (ipheader->ip_p == TYPE_TCP) {
ipheaderlength = ((UCHAR)*ippacket & 0x0f)*4 ;
tcppacket = ippacket + ipheaderlength ;
tcpheaderlength = (*(tcppacket + 10) >> 4)*4 ;
if (!TCPPACKET_SRC_OR_DEST_PORT_139(ippacket,ipheaderlength))
return TRUE ;
//
// NetBT traffic
//
//
// if zero length tcp packet - this is an ACK on 139 - filter this.
//
if (TotalLength == (ipheaderlength + tcpheaderlength))
return FALSE ;
//
// Session alives are also filtered.
//
if ((UCHAR) *(tcppacket+tcpheaderlength) == 0x85)
return FALSE ;
}
//
// all other ip traffic is valid traffic
//
return TRUE ;
}
BOOLEAN
IpxIsDataFrame(
PUCHAR HeaderBuffer,
ULONG HeaderBufferLength,
ULONG TotalLength
)
{
/*++
Routine Description:
This routine is called when a frame is received on a WAN
line. It returns TRUE unless:
- The frame is from the RIP socket
- The frame is from the SAP socket
- The frame is a netbios keep alive
- The frame is an NCP keep alive
Arguments:
HeaderBuffer - points to a contiguous buffer starting at the IPX header.
HeaderBufferLength - Length of the header buffer (could be same as totallength)
TotalLength - the total length of the frame
Return Value:
TRUE - if this is a connection-based packet.
FALSE - otherwise.
--*/
IPX_HEADER UNALIGNED * IpxHeader = (IPX_HEADER UNALIGNED *)HeaderBuffer;
USHORT SourceSocket;
//
// First get the source socket.
//
SourceSocket = IpxHeader->SourceSocket;
//
// Not connection-based
//
if ((SourceSocket == RIP_SOCKET) ||
(SourceSocket == SAP_SOCKET)) {
return FALSE;
}
//
// See if there are at least two more bytes to look at.
//
if (TotalLength >= sizeof(IPX_HEADER) + 2) {
if (SourceSocket == NB_SOCKET) {
UCHAR ConnectionControlFlag;
UCHAR DataStreamType;
USHORT TotalDataLength;
//
// ConnectionControlFlag and DataStreamType will always follow
// IpxHeader
//
ConnectionControlFlag = ((PUCHAR)(IpxHeader+1))[0];
DataStreamType = ((PUCHAR)(IpxHeader+1))[1];
//
// If this is a SYS packet with or without a request for ACK and
// has session data in it.
//
if (((ConnectionControlFlag == 0x80) || (ConnectionControlFlag == 0xc0)) &&
(DataStreamType == 0x06)) {
//
// TotalDataLength is in the same buffer.
//
TotalDataLength = ((USHORT UNALIGNED *)(IpxHeader+1))[4];
//
// KeepAlive - return FALSE
//
if (TotalDataLength == 0) {
return FALSE;
}
}
} else {
//
// Now see if it is an NCP keep alive. It can be from rip or from
// NCP on this machine
//
if (TotalLength == sizeof(IPX_HEADER) + 2) {
UCHAR KeepAliveSignature = ((PUCHAR)(IpxHeader+1))[1];
if ((KeepAliveSignature == '?') ||
(KeepAliveSignature == 'Y')) {
return FALSE;
}
}
}
}
//
// This was a normal packet, so return TRUE
//
return TRUE;
}
BOOLEAN
NbfIsDataFrame(
PUCHAR HeaderBuffer,
ULONG HeaderBufferLength,
ULONG TotalLength
)
{
/*++
Routine Description:
This routine looks at a data packet from the net to deterimine if there is
any data flowing on the connection.
Arguments:
HeaderBuffer - Pointer to the dlc header for this packet.
HeaderBufferLength - Length of the header buffer (could be same as totallength)
TotalLength - the total length of the frame
Return Value:
True if this is a frame that indicates data traffic on the connection.
False otherwise.
--*/
PDLC_FRAME DlcHeader = (PDLC_FRAME)HeaderBuffer;
BOOLEAN Command = (BOOLEAN)!(DlcHeader->Ssap & DLC_SSAP_RESPONSE);
PNBF_HDR_CONNECTION nbfHeader;
if (TotalLength < sizeof(PDLC_FRAME)) {
return(FALSE);
}
if (!(DlcHeader->Byte1 & DLC_I_INDICATOR)) {
//
// We have an I frame.
//
if (TotalLength < 4 + sizeof(NBF_HDR_CONNECTION)) {
//
// It's a runt I-frame.
//
return(FALSE);
}
nbfHeader = (PNBF_HDR_CONNECTION) ((PUCHAR)DlcHeader + 4);
switch (nbfHeader->Command) {
case NBF_CMD_DATA_FIRST_MIDDLE:
case NBF_CMD_DATA_ONLY_LAST:
case NBF_CMD_DATA_ACK:
case NBF_CMD_SESSION_CONFIRM:
case NBF_CMD_SESSION_INITIALIZE:
case NBF_CMD_NO_RECEIVE:
case NBF_CMD_RECEIVE_OUTSTANDING:
case NBF_CMD_RECEIVE_CONTINUE:
return(TRUE);
break;
default:
return(FALSE);
break;
}
}
return(FALSE);
}
#ifdef NT
VOID
CompleteIoRecvPacket(
PBUNDLECB BundleCB,
PLINKCB LinkCB,
USHORT PPPProtocolID,
PRECV_DESC RecvDesc
)
{
PWAN_ASYNC_EVENT AsyncEvent;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
ULONG FrameLength = RecvDesc->CurrentBufferLength;
KIRQL Irql;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("CompleteIoRecvPacket: Enter"));
IoAcquireCancelSpinLock(&Irql);
if (!IsListEmpty(&RecvPacketQueue.List)) {
PNDISWAN_IO_PACKET IoPacket;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
ULONG SizeNeeded, BufferLength;
AsyncEvent =
(PWAN_ASYNC_EVENT)NdisWanInterlockedRemoveHeadList(&RecvPacketQueue.List,
&RecvPacketQueue.Lock.SpinLock);
NdisWanInterlockedDec(&RecvPacketQueue.ulCount);
Irp = (PIRP)AsyncEvent->Context;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
BufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
SizeNeeded = sizeof(NDISWAN_IO_PACKET) + 14 + FrameLength;
if ((BufferLength >= SizeNeeded) && (LinkCB->hLinkContext != NULL)) {
PUCHAR Data;
IoPacket = Irp->AssociatedIrp.SystemBuffer;
IoPacket->hHandle = LinkCB->hLinkContext;
IoPacket->usHandleType = LINKHANDLE;
IoPacket->usHeaderSize = 14;
IoPacket->usPacketSize = (USHORT)FrameLength + 14;
IoPacket->usPacketFlags = 0;
Data = IoPacket->PacketData;
//
// First build the header
//
Data[0] =
Data[6] = ' ';
Data[1] =
Data[7] = 'R';
Data[2] =
Data[8] = 'E';
Data[3] =
Data[9] = 'C';
Data[4] =
Data[10] = 'V';
Data[5] =
Data[11] = (UCHAR)LinkCB->hLinkHandle;
Data[12] = (UCHAR)(PPPProtocolID >> 8);
Data[13] = (UCHAR)PPPProtocolID;
NdisMoveMemory(RecvDesc->WanHeader, Data, 14);
RecvDesc->WanHeaderLength = 14;
//
// Now copy the data
//
NdisMoveMemory(Data + 14,
FramePointer,
FrameLength);
IoSetCancelRoutine(Irp, NULL);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = SizeNeeded;
IoReleaseCancelSpinLock(Irql);
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
//
// Free the wan_async_event structure
//
NdisWanFreeMemory(AsyncEvent);
if (NdisWanCB.PromiscuousAdapter != NULL) {
RecvDesc->LookAheadLength = 0;
//
// Queue the packet on the promiscous adapter
//
QueuePromiscuousReceive(RecvDesc);
}
} else {
#if DBG
DbgPrint("NDISWAN: Error I/O recv: bufferlength %d, linkcontext: 0x%8.8x\n",
BufferLength, LinkCB->hLinkContext);
#endif
InsertHeadList(&RecvPacketQueue.List, &AsyncEvent->Linkage);
NdisWanInterlockedInc(&NdisWanCB.IORecvError2);
IoReleaseCancelSpinLock(Irql);
}
} else {
#if DBG
DbgPrint("NDISWAN: No I/O recv packets available!\n");
#endif
NdisWanInterlockedInc(&NdisWanCB.IORecvError1);
IoReleaseCancelSpinLock(Irql);
}
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("CompleteIoRecvPacket: Exit"));
}
#endif // end ifdef NT