Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3097 lines
86 KiB

/*++
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"
#define __FILE_SIG__ RECEIVE_FILESIG
VOID
DoMultilinkProcessing(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
);
VOID
UpdateMinRecvSeqNumber(
PBUNDLECB BundleCB,
UINT Class
);
VOID
TryToAssembleFrame(
PBUNDLECB BundleCB,
UINT Class
);
NDIS_STATUS
ProcessPPPFrame(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
NDIS_STATUS
IndicateRecvPacket(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
BOOLEAN
DoVJDecompression(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
BOOLEAN
DoDecompDecryptProcessing(
PBUNDLECB BundleCB,
PUCHAR *DataPointer,
PLONG DataLength
);
VOID
DoCompressionReset(
PBUNDLECB BundleCB
);
VOID
FlushRecvDescWindow(
PBUNDLECB BundleCB,
UINT Class
);
VOID
FindHoleInRecvList(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc,
UINT Class
);
BOOLEAN
GetProtocolFromPPPId(
PBUNDLECB BundleCB,
USHORT Id,
PPROTOCOLCB *ProtocolCB
);
#ifdef NT
NDIS_STATUS
CompleteIoRecvPacket(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
);
#endif
NDIS_STATUS
DetectBroadbandFraming(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PBUNDLECB BundleCB = LinkCB->BundleCB;
PUCHAR FramePointer;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("DetectFraming: Enter"));
FramePointer = RecvDesc->CurrentBuffer;
if (*FramePointer == 0xFE && *(FramePointer + 1) == 0xFE &&
*(FramePointer + 2) == 0x03 && *(FramePointer + 3) == 0xCF) {
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits =
PPP_FRAMING | LLC_ENCAPSULATION;
LinkCB->RecvHandler = ReceiveLLC;
} else {
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits =
PPP_FRAMING | PPP_COMPRESS_ADDRESS_CONTROL;
LinkCB->RecvHandler = ReceivePPP;
}
Status = (*LinkCB->RecvHandler)(LinkCB, RecvDesc);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("DetectFraming: Exit Status %x",Status));
return (Status);
}
NDIS_STATUS
DetectFraming(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PBUNDLECB BundleCB = LinkCB->BundleCB;
PUCHAR FramePointer;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("DetectFraming: Enter"));
ASSERT(LinkCB->LinkInfo.RecvFramingBits == 0x00);
FramePointer = RecvDesc->CurrentBuffer;
//
// If we are in framing detect mode figure it out
//
if (LinkCB->LinkInfo.RecvFramingBits == 0 ||
LinkCB->LinkInfo.SendFramingBits == 0) {
if (*FramePointer == 0xFF && *(FramePointer + 1) == 0x03) {
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits = PPP_FRAMING;
LinkCB->RecvHandler = ReceivePPP;
} else if (*FramePointer == 0x01 && *(FramePointer + 1) == 0x1B &&
*(FramePointer + 2) == 0x02){
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits = ARAP_V2_FRAMING;
LinkCB->RecvHandler = ReceiveARAP;
} else if (*FramePointer == 0x16 && *(FramePointer + 1) == 0x10 &&
*(FramePointer + 2) == 0x02){
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits = ARAP_V1_FRAMING;
LinkCB->RecvHandler = ReceiveARAP;
} else if (*FramePointer == 0xFE && *(FramePointer + 1) == 0xFE &&
*(FramePointer + 2) == 0x03 &&
*(FramePointer + 3) == 0xCF) {
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits =
PPP_FRAMING | LLC_ENCAPSULATION;
LinkCB->RecvHandler = ReceiveLLC;
} else {
LinkCB->LinkInfo.RecvFramingBits =
LinkCB->LinkInfo.SendFramingBits = RAS_FRAMING;
LinkCB->RecvHandler = ReceiveRAS;
}
if (BundleCB->FramingInfo.RecvFramingBits == 0x00) {
if (LinkCB->LinkInfo.RecvFramingBits & PPP_FRAMING) {
BundleCB->FramingInfo.RecvFramingBits =
BundleCB->FramingInfo.SendFramingBits = PPP_FRAMING;
} else if (LinkCB->LinkInfo.RecvFramingBits & ARAP_V1_FRAMING) {
BundleCB->FramingInfo.RecvFramingBits =
BundleCB->FramingInfo.SendFramingBits = ARAP_V1_FRAMING;
} else if (LinkCB->LinkInfo.RecvFramingBits & ARAP_V2_FRAMING) {
BundleCB->FramingInfo.RecvFramingBits =
BundleCB->FramingInfo.SendFramingBits = ARAP_V2_FRAMING;
} else if (LinkCB->LinkInfo.RecvFramingBits & RAS_FRAMING) {
BundleCB->FramingInfo.RecvFramingBits =
BundleCB->FramingInfo.SendFramingBits = RAS_FRAMING;
} else {
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE,
("DetectFraming Failed! 0x%2.2x 0x%2.2x 0x%2.2x",
FramePointer[0], FramePointer[1], FramePointer[2]));
return (NDIS_STATUS_SUCCESS);
}
}
} else {
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE,
("FramingBits set but still in detect 0x%x 0x%x",
LinkCB->LinkInfo.RecvFramingBits,
LinkCB->LinkInfo.SendFramingBits));
return (NDIS_STATUS_SUCCESS);
}
Status = (*LinkCB->RecvHandler)(LinkCB, RecvDesc);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("DetectFraming: Exit Status %x",Status));
return (Status);
}
NDIS_STATUS
ReceivePPP(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
PBUNDLECB BundleCB = LinkCB->BundleCB;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
LONG FrameLength = RecvDesc->CurrentLength;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceivePPP: Enter"));
//
// Remove the address/control part of the PPP header
//
if (*FramePointer == 0xFF) {
FramePointer += 2;
FrameLength -= 2;
}
if (FrameLength <= 0) {
Status = NDIS_STATUS_FAILURE;
goto RECEIVE_PPP_EXIT;
}
//
// If multilink framing is set and this is a multilink frame
// send to the multilink processor!
//
if ((LinkCB->LinkInfo.RecvFramingBits & PPP_MULTILINK_FRAMING) &&
((*FramePointer == 0x3D) ||
(*FramePointer == 0x00) && (*(FramePointer + 1) == 0x3D)) ) {
//
// Remove multilink protocol id
//
if (*FramePointer & 1) {
FramePointer++;
FrameLength--;
} else {
FramePointer += 2;
FrameLength -= 2;
}
if (FrameLength <= 0) {
Status = NDIS_STATUS_FAILURE;
goto RECEIVE_PPP_EXIT;
}
RecvDesc->CurrentBuffer = FramePointer;
RecvDesc->CurrentLength = FrameLength;
DoMultilinkProcessing(LinkCB, RecvDesc);
Status = NDIS_STATUS_PENDING;
goto RECEIVE_PPP_EXIT;
}
RecvDesc->CurrentBuffer = FramePointer;
RecvDesc->CurrentLength = FrameLength;
Status = ProcessPPPFrame(BundleCB, RecvDesc);
RECEIVE_PPP_EXIT:
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceivePPP: Exit Status %x", Status));
return (Status);
}
NDIS_STATUS
ReceiveSLIP(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
PBUNDLECB BundleCB = LinkCB->BundleCB;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
ULONG FrameLength = RecvDesc->CurrentLength;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveSLIP: Enter"));
ASSERT(BundleCB->FramingInfo.RecvFramingBits & SLIP_FRAMING);
BundleCB->Stats.FramesReceived++;
if (!DoVJDecompression(BundleCB, // Bundle
RecvDesc)) { // RecvDesc
goto RECEIVE_SLIP_EXIT;
}
Status = IndicateRecvPacket(BundleCB, RecvDesc);
RECEIVE_SLIP_EXIT:
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveSLIP: Exit Status %x", Status));
return (Status);
}
NDIS_STATUS
ReceiveRAS(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
PBUNDLECB BundleCB = LinkCB->BundleCB;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
LONG FrameLength = RecvDesc->CurrentLength;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveRAS: Enter"));
ASSERT(BundleCB->FramingInfo.RecvFramingBits & RAS_FRAMING);
BundleCB->Stats.FramesReceived++;
// 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 RECEIVE_RAS_EXIT;
}
if (*FramePointer == 0xFD) {
//
// Skip over 0xFD
//
FramePointer++;
FrameLength--;
//
// Decompress as if an NBF PPP Packet
//
if (!DoDecompDecryptProcessing(BundleCB,
&FramePointer,
&FrameLength)){
//
// There was an error get out!
//
goto RECEIVE_RAS_EXIT;
}
}
//
// Make frame look like an NBF PPP packet
//
RecvDesc->ProtocolID = PPP_PROTOCOL_NBF;
RecvDesc->CurrentLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
Status = IndicateRecvPacket(BundleCB, RecvDesc);
RECEIVE_RAS_EXIT:
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveRAS: Exit Status %x",Status));
return (Status);
}
NDIS_STATUS
ReceiveARAP(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
PBUNDLECB BundleCB = LinkCB->BundleCB;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveARAP: Enter"));
ASSERT(BundleCB->FramingInfo.RecvFramingBits & ARAP_FRAMING);
BundleCB->Stats.FramesReceived++;
RecvDesc->ProtocolID = PPP_PROTOCOL_APPLETALK;
Status = IndicateRecvPacket(BundleCB, RecvDesc);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveARAP: Exit Status %x",Status));
return (Status);
}
NDIS_STATUS
ReceiveLLC(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
PBUNDLECB BundleCB = LinkCB->BundleCB;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
LONG FrameLength = RecvDesc->CurrentLength;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveLLC: Enter"));
//
// Skip over LLC
//
if (FrameLength < 4) {
}
if (*FramePointer != 0xFE || *(FramePointer + 1) != 0xFE ||
*(FramePointer + 2) != 0x03 || *(FramePointer + 3) != 0xCF) {
LinkCB->LinkInfo.RecvFramingBits = 0;
LinkCB->RecvHandler = DetectBroadbandFraming;
return (NDIS_STATUS_FAILURE);
}
FramePointer += 4;
FrameLength -= 4;
if (FrameLength <= 0) {
return (NDIS_STATUS_FAILURE);
}
RecvDesc->CurrentBuffer = FramePointer;
RecvDesc->CurrentLength = FrameLength;
Status = ProcessPPPFrame(BundleCB, RecvDesc);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveLLC: Exit Status %x",Status));
return (Status);
}
NDIS_STATUS
ReceiveForward(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
{
PBUNDLECB BundleCB = LinkCB->BundleCB;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveForward: Enter"));
BundleCB->Stats.FramesReceived++;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ReceiveForward: Exit Status %x",Status));
return (Status);
}
NDIS_STATUS
ProcessPPPFrame(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
{
USHORT PPPProtocolID;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
LONG FrameLength = RecvDesc->CurrentLength;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProcessPPPFrame: Enter"));
BundleCB->Stats.FramesReceived++;
//
// 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;
}
if (FrameLength <= 0) {
goto PROCESS_PPP_EXIT;
}
#if 0
if (BundleCB->Stats.FramesReceived == 1) {
if (PPPProtocolID != 0xC021) {
DbgPrint("NDISWAN: Non-LCP first frame! %x %x\n",
BundleCB, RecvDesc);
DbgBreakPoint();
}
}
#endif
//
// Is this a compressed frame?
//
if (PPPProtocolID == PPP_PROTOCOL_COMPRESSION) {
if (!DoDecompDecryptProcessing(BundleCB,
&FramePointer,
&FrameLength)){
goto PROCESS_PPP_EXIT;
}
//
// Get the new PPPProtocolID
//
if ((*FramePointer & 1) && (FrameLength > 0)) {
//
// Field is compressed
//
PPPProtocolID = *FramePointer;
FramePointer++;
FrameLength--;
} else if (FrameLength > 1) {
PPPProtocolID = (*FramePointer << 8) | *(FramePointer + 1);
FramePointer += 2;
FrameLength -= 2;
} else {
//
// Invalid frame!
//
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Invalid FrameLen %d", FrameLength));
goto PROCESS_PPP_EXIT;
}
//end of PPP_PROTOCOL_COMPRESSED
} else if ((PPPProtocolID == PPP_PROTOCOL_COMP_RESET) &&
(*FramePointer == 14)) {
if (NdisWanCB.PromiscuousAdapter != NULL) {
UCHAR Header[] = {' ', 'R', 'E', 'C', 'V', 0xFF};
PUCHAR HeaderPointer;
USHORT ProtocolID;
RecvDesc->ProtocolID = PPPProtocolID;
RecvDesc->CurrentBuffer = FramePointer;
RecvDesc->CurrentLength = FrameLength;
HeaderPointer =
RecvDesc->StartBuffer;
ProtocolID = RecvDesc->ProtocolID;
//
// Fill the frame out, and queue the data
//
NdisMoveMemory(HeaderPointer,
Header,
sizeof(Header));
NdisMoveMemory(&HeaderPointer[6],
Header,
sizeof(Header));
HeaderPointer[5] =
HeaderPointer[11] = (UCHAR)RecvDesc->LinkCB->hLinkHandle;
HeaderPointer[12] = (UCHAR)(ProtocolID >> 8);
HeaderPointer[13] = (UCHAR)ProtocolID;
NdisMoveMemory(HeaderPointer + 14,
RecvDesc->CurrentBuffer,
RecvDesc->CurrentLength);
RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
RecvDesc->CurrentLength += 14;
//
// Queue the packet on the promiscous adapter
//
IndicatePromiscuousRecv(BundleCB, RecvDesc, RECV_BUNDLE_PPP);
}
//
// Compression reset!
//
DoCompressionReset(BundleCB);
goto PROCESS_PPP_EXIT;
// end of compression reset
} else {
//
// If we have negotiated encryption and we receive non-encrypted data
// that is not a ppp control packet we will dump the frame!
//
if ((BundleCB->RecvFlags & DO_ENCRYPTION) &&
(PPPProtocolID < 0x8000)) {
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Received non-encrypted data with encryption negotiated!"));
goto PROCESS_PPP_EXIT;
}
}
RecvDesc->ProtocolID = PPPProtocolID;
RecvDesc->CurrentLength = FrameLength;
RecvDesc->CurrentBuffer = FramePointer;
//
// If this is slip or if the ProtocolID == PPP_PROTOCOL_COMPRESSED_TCP ||
// ProtocolID == PPP_PROTOCOL_UNCOMPRESSED_TCP
//
if ((BundleCB->RecvFlags & DO_VJ) &&
((PPPProtocolID == PPP_PROTOCOL_COMPRESSED_TCP) ||
(PPPProtocolID == PPP_PROTOCOL_UNCOMPRESSED_TCP))) {
if (!DoVJDecompression(BundleCB, // Bundle
RecvDesc)) { // RecvDesc
goto PROCESS_PPP_EXIT;
}
}
Status = IndicateRecvPacket(BundleCB, RecvDesc);
PROCESS_PPP_EXIT:
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProcessPPPFrame: Exit Status 0x%x", Status));
return (Status);
}
NDIS_STATUS
IndicateRecvPacket(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
{
PNDIS_PACKET NdisPacket;
PPROTOCOLCB ProtocolCB;
PMINIPORTCB MiniportCB;
USHORT PPPProtocolID = RecvDesc->ProtocolID;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
ULONG FrameLength = RecvDesc->CurrentLength;
PUCHAR HeaderBuffer = RecvDesc->StartBuffer;
NDIS_STATUS Status = NDIS_STATUS_PENDING;
PCM_VCCB CmVcCB = NULL;
KIRQL OldIrql;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("IndicateRecvPacket: Enter"));
if ((PPPProtocolID >= 0x8000) ||
(BundleCB->ulNumberOfRoutes == 0)) {
//
// Either this frame is an LCP, NCP or we have no routes yet.
// Indicate to PPP engine.
//
Status = CompleteIoRecvPacket(BundleCB, RecvDesc);
return (Status);
}
if (!GetProtocolFromPPPId(BundleCB,
PPPProtocolID,
&ProtocolCB)) {
return (NDIS_STATUS_SUCCESS);
}
REF_PROTOCOLCB(ProtocolCB);
if (!IsListEmpty(&ProtocolCB->VcList)) {
CmVcCB = (PCM_VCCB)ProtocolCB->VcList.Flink;
REF_CMVCCB(CmVcCB);
}
MiniportCB = ProtocolCB->MiniportCB;
//
// We found a valid protocol to indicate this frame to!
//
//
// We need to get a data buffer, a couple a ndis buffer, and
// a ndis packet to indicate to the protocol
//
//
// Fill the WanHeader dest address with the transports context
//
ETH_COPY_NETWORK_ADDRESS(HeaderBuffer, ProtocolCB->TransportAddress);
if (PPPProtocolID == PPP_PROTOCOL_NBF) {
//
// For nbf fill the length field
//
HeaderBuffer[12] = (UCHAR)(FrameLength >> 8);
HeaderBuffer[13] = (UCHAR)FrameLength;
if (!(BundleCB->FramingInfo.RecvFramingBits & 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(&HeaderBuffer[6], FramePointer + 6);
FramePointer += 12;
FrameLength -= 12;
//
// For nbf fill the length field
//
HeaderBuffer[12] = (UCHAR)(FrameLength >> 8);
HeaderBuffer[13] = (UCHAR)FrameLength;
} else {
//
// For other protocols fill the protocol type
//
HeaderBuffer[12] = (UCHAR)(ProtocolCB->ProtocolType >> 8);
HeaderBuffer[13] = (UCHAR)ProtocolCB->ProtocolType;
//
// Use our address for the src address
//
USE_OUR_ADDRESS:
ETH_COPY_NETWORK_ADDRESS(&HeaderBuffer[6], ProtocolCB->NdisWanAddress);
}
if (FrameLength > BundleCB->FramingInfo.MaxRRecvFrameSize ||
FrameLength + RecvDesc->HeaderLength > BundleCB->FramingInfo.MaxRRecvFrameSize) {
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("DataLen %d + HdrLen %d > MRRU %d",
FrameLength, RecvDesc->HeaderLength, BundleCB->FramingInfo.MaxRRecvFrameSize));
goto INDICATE_RECV_PACKET_EXIT;
}
RecvDesc->HeaderLength += MAC_HEADER_LENGTH;
//
// Build the NdisPacket
// USE RtlMoveMemory because memory ranges may overlap. NdisMoveMemory
// actually does an rtlcopymemory which does not handle overlapping
// src/dest ranges.
//
RtlMoveMemory(HeaderBuffer + RecvDesc->HeaderLength,
FramePointer,
FrameLength);
RecvDesc->CurrentBuffer = HeaderBuffer;
RecvDesc->CurrentLength =
RecvDesc->HeaderLength + FrameLength;
if (NdisWanCB.PromiscuousAdapter != NULL) {
//
// Queue the packet on the promiscous adapter
//
IndicatePromiscuousRecv(BundleCB,
RecvDesc,
RECV_BUNDLE_DATA);
}
NdisPacket =
RecvDesc->NdisPacket;
PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket)->RecvDesc =
RecvDesc;
NdisAdjustBufferLength(RecvDesc->NdisBuffer,
RecvDesc->CurrentLength);
NdisRecalculatePacketCounts(NdisPacket);
//
// Check for non-idle data
//
if (ProtocolCB->NonIdleDetectFunc != NULL) {
PUCHAR PHeaderBuffer = HeaderBuffer + MAC_HEADER_LENGTH;
if (TRUE == ProtocolCB->NonIdleDetectFunc(PHeaderBuffer,
RecvDesc->HeaderLength + FrameLength,
RecvDesc->HeaderLength + FrameLength)) {
NdisWanGetSystemTime(&ProtocolCB->LastNonIdleData);
BundleCB->LastNonIdleData = ProtocolCB->LastNonIdleData;
}
} else {
NdisWanGetSystemTime(&ProtocolCB->LastNonIdleData);
BundleCB->LastNonIdleData = ProtocolCB->LastNonIdleData;
}
ReleaseBundleLock(BundleCB);
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
INSERT_DBG_RECV(PacketTypeNdis,
MiniportCB,
ProtocolCB,
RecvDesc->LinkCB,
NdisPacket);
//
// Indicate the packet
//
if (CmVcCB != NULL) {
NdisMCoIndicateReceivePacket(CmVcCB->NdisVcHandle,
&NdisPacket,
1);
DEREF_CMVCCB(CmVcCB);
} else {
NdisMIndicateReceivePacket(MiniportCB->MiniportHandle,
&NdisPacket,
1);
}
KeLowerIrql(OldIrql);
AcquireBundleLock(BundleCB);
INDICATE_RECV_PACKET_EXIT:
DEREF_PROTOCOLCB(ProtocolCB);
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("IndicateRecvPacket: Exit Status %x",Status));
return (Status);
}
VOID
DoMultilinkProcessing(
PLINKCB LinkCB,
PRECV_DESC RecvDesc
)
/*++
Routine Name:
Routine Description:
Arguments:
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 |
+--------------------------------+
MCML +-+-+-+-+------------------------+
Short Sequence Number |B|E|Cls| Sequence Number |
+-+-+-+-+------------------------+
| Data |
+--------------------------------+
MCML +-+-+-+-+-+-+-+-+----------------+
Long Sequence Number |B|E| Class |0|0|Sequence Number |
+-+-+-+-+-+-+-+-+----------------+
| Sequence Number |
+--------------------------------+
| Data |
+--------------------------------+
Return Values:
--*/
{
BOOLEAN Inserted = FALSE;
ULONG BundleFraming;
ULONG SequenceNumber, Flags;
PBUNDLECB BundleCB = LinkCB->BundleCB;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
LONG FrameLength = RecvDesc->CurrentLength;
PRECV_DESC RecvDescHole;
UINT Class = 0;
PBUNDLE_RECV_INFO BundleRecvInfo;
PLINK_RECV_INFO LinkRecvInfo;
//
// Get the flags
//
Flags = *FramePointer & MULTILINK_FLAG_MASK;
//
// Get the sequence number
//
if (BundleCB->FramingInfo.RecvFramingBits &
PPP_SHORT_SEQUENCE_HDR_FORMAT) {
//
// Short sequence format
//
SequenceNumber =
((*FramePointer & 0x0F) << 8) | *(FramePointer + 1);
if (BundleCB->FramingInfo.RecvFramingBits &
PPP_MC_MULTILINK_FRAMING) {
Class =
((*FramePointer & MCML_SHORTCLASS_MASK) >> 4);
}
FramePointer += 2;
FrameLength -= 2;
} else {
//
// Long sequence format
//
SequenceNumber = (*(FramePointer + 1) << 16) |
(*(FramePointer + 2) << 8) |
*(FramePointer + 3);
if (BundleCB->FramingInfo.RecvFramingBits &
PPP_MC_MULTILINK_FRAMING) {
Class =
((*FramePointer & MCML_LONGCLASS_MASK) >> 2);
}
FramePointer += 4;
FrameLength -= 4;
}
if (Class >= MAX_MCML) {
LinkCB->Stats.FramingErrors++;
BundleCB->Stats.FramingErrors++;
return;
}
BundleRecvInfo = &BundleCB->RecvInfo[Class];
LinkRecvInfo = &LinkCB->RecvInfo[Class];
if (FrameLength <= 0) {
LinkCB->Stats.FramingErrors++;
LinkRecvInfo->FragmentsLost++;
BundleCB->Stats.FramingErrors++;
BundleRecvInfo->FragmentsLost++;
return;
}
RecvDescHole = BundleRecvInfo->RecvDescHole;
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("r %x %x h: %x l: %d",SequenceNumber, Flags, RecvDescHole->SequenceNumber, LinkCB->hLinkHandle));
//
// Is the new receive 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,
LinkRecvInfo->LastSeqNumber,
BundleCB->RecvSeqTest)) {
LinkCB->Stats.FramingErrors++;
LinkRecvInfo->FragmentsLost++;
BundleCB->Stats.FramingErrors++;
BundleRecvInfo->FragmentsLost++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dl s: %x %x lr: %x", SequenceNumber, Flags,
LinkRecvInfo->LastSeqNumber));
NdisWanFreeRecvDesc(RecvDesc);
return;
}
//
// 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)) {
LinkCB->Stats.FramingErrors++;
LinkRecvInfo->FragmentsLost++;
BundleCB->Stats.FramingErrors++;
BundleRecvInfo->FragmentsLost++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("db s: %x %x h: %x", SequenceNumber, Flags,
RecvDescHole->SequenceNumber));
NdisWanFreeRecvDesc(RecvDesc);
return;
}
//
// Initialize the recv desc
//
RecvDesc->Flags |= Flags;
RecvDesc->SequenceNumber =
LinkRecvInfo->LastSeqNumber = SequenceNumber;
if (RecvDesc->CopyRequired) {
PUCHAR StartData =
RecvDesc->StartBuffer + MAC_HEADER_LENGTH + PROTOCOL_HEADER_LENGTH;
NdisMoveMemory(StartData,
FramePointer,
FrameLength);
FramePointer = StartData;
RecvDesc->CopyRequired = FALSE;
}
RecvDesc->CurrentBuffer = FramePointer;
RecvDesc->CurrentLength = FrameLength;
//
// 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, Class);
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)&BundleRecvInfo->AssemblyList) {
//
// 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(&BundleRecvInfo->AssemblyList, &RecvDesc->Linkage);
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("r3"));
}
}
//
// Another recvdesc has been placed on the assembly list.
//
BundleRecvInfo->AssemblyCount++;
//
// Update the bundles minimum recv sequence number. This is
// used to detect lost fragments.
//
UpdateMinRecvSeqNumber(BundleCB, Class);
//
// See if we can complete some frames!!!!
//
TryToAssembleFrame(BundleCB, Class);
//
// 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(BundleRecvInfo->MinSeqNumber,
RecvDescHole->SequenceNumber,
BundleCB->RecvSeqTest)) {
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("min %x > h %x b %p",
BundleRecvInfo->MinSeqNumber,
RecvDescHole->SequenceNumber,
BundleCB));
do {
//
// Flush the recv desc assembly window.
//
FlushRecvDescWindow(BundleCB, Class);
} while (SEQ_GT(BundleRecvInfo->MinSeqNumber,
RecvDescHole->SequenceNumber,
BundleCB->RecvSeqTest));
}
//
// If the number of recvdesc's is starting to stack up
// we may have a link that is not sending so flush
//
if (BundleRecvInfo->AssemblyCount >
(MAX_RECVDESC_COUNT + BundleCB->ulLinkCBCount)) {
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("%x AssemblyCount %d > %d", BundleCB,
BundleRecvInfo->AssemblyCount, MAX_RECVDESC_COUNT + BundleCB->ulLinkCBCount));
//
// Flush the recv desc assembly window.
//
FlushRecvDescWindow(BundleCB, Class);
}
}
VOID
UpdateMinRecvSeqNumber(
PBUNDLECB BundleCB,
UINT Class
)
{
PBUNDLE_RECV_INFO BundleRecvInfo;
PLINK_RECV_INFO LinkRecvInfo;
PLINKCB LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
BundleRecvInfo = &BundleCB->RecvInfo[Class];
LinkRecvInfo = &LinkCB->RecvInfo[Class];
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("MinReceived c %x", BundleRecvInfo->MinSeqNumber));
BundleRecvInfo->MinSeqNumber = LinkRecvInfo->LastSeqNumber;
for (LinkCB = (PLINKCB)LinkCB->Linkage.Flink;
(PVOID)LinkCB != (PVOID)&BundleCB->LinkCBList;
LinkCB = (PLINKCB)LinkCB->Linkage.Flink) {
LinkRecvInfo = &LinkCB->RecvInfo[Class];
if (SEQ_LT(LinkRecvInfo->LastSeqNumber,
BundleRecvInfo->MinSeqNumber,
BundleCB->RecvSeqTest)) {
BundleRecvInfo->MinSeqNumber = LinkRecvInfo->LastSeqNumber;
}
}
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("MinReceived n %x", BundleRecvInfo->MinSeqNumber));
}
VOID
FindHoleInRecvList(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc,
UINT Class
)
/*++
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;
PBUNDLE_RECV_INFO BundleRecvInfo;
BundleRecvInfo = &BundleCB->RecvInfo[Class];
RecvDescHole = BundleRecvInfo->RecvDescHole;
RecvList = &BundleRecvInfo->AssemblyList;
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV,
("h: %x", 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: %x", RecvDescHole->SequenceNumber));
}
VOID
FlushRecvDescWindow(
IN PBUNDLECB BundleCB,
IN UINT Class
)
/*++
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;
PRECV_DESC TempDesc;
PBUNDLE_RECV_INFO BundleRecvInfo;
BundleRecvInfo = &BundleCB->RecvInfo[Class];
RecvDescHole = BundleRecvInfo->RecvDescHole;
//
// Remove all recvdesc's until we find the hole
//
while (!IsListEmpty(&BundleRecvInfo->AssemblyList)) {
TempDesc = (PRECV_DESC)
RemoveHeadList(&BundleRecvInfo->AssemblyList);
if (TempDesc == RecvDescHole) {
break;
}
BundleRecvInfo->FragmentsLost++;
BundleRecvInfo->AssemblyCount--;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("flw %x %x h: %x", TempDesc->SequenceNumber,
TempDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanFreeRecvDesc(TempDesc);
}
BundleCB->Stats.FramingErrors++;
//
// Now flush all recvdesc's until we find a begin fragment that has a
// sequence number >= M or the list is empty.
//
while (!IsListEmpty(&BundleRecvInfo->AssemblyList)) {
TempDesc = (PRECV_DESC)
BundleRecvInfo->AssemblyList.Flink;
if (TempDesc->Flags & MULTILINK_BEGIN_FRAME) {
break;
}
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("flw %x %x h: %x", TempDesc->SequenceNumber,
TempDesc->Flags, RecvDescHole->SequenceNumber));
RecvDescHole->SequenceNumber = TempDesc->SequenceNumber;
RemoveHeadList(&BundleRecvInfo->AssemblyList);
BundleRecvInfo->AssemblyCount--;
BundleRecvInfo->FragmentsLost++;
NdisWanFreeRecvDesc(TempDesc);
TempDesc = NULL;
}
//
// Now reinsert the hole desc.
//
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("h: %x", RecvDescHole->SequenceNumber));
FindHoleInRecvList(BundleCB, TempDesc, Class);
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("nh: %x", RecvDescHole->SequenceNumber));
//
// See if we can complete some frames!!!!
//
TryToAssembleFrame(BundleCB, Class);
}
VOID
FlushAssemblyLists(
IN PBUNDLECB BundleCB
)
/*++
Routine Name:
Routine Description:
Arguments:
Return Values:
--*/
{
PRECV_DESC RecvDesc;
UINT Class;
for (Class = 0; Class < MAX_MCML; Class++) {
PBUNDLE_RECV_INFO RecvInfo = &BundleCB->RecvInfo[Class];
while (!IsListEmpty(&RecvInfo->AssemblyList)) {
RecvDesc = (PRECV_DESC)RemoveHeadList(&RecvInfo->AssemblyList);
RecvInfo->AssemblyCount--;
if (RecvDesc->Flags != MULTILINK_HOLE_FLAG) {
NdisWanFreeRecvDesc(RecvDesc);
}
}
}
}
VOID
TryToAssembleFrame(
PBUNDLECB BundleCB,
UINT Class
)
/*++
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;
PUCHAR DataPointer;
LINKCB LinkCB;
PBUNDLE_RECV_INFO BundleRecvInfo;
BundleRecvInfo = &BundleCB->RecvInfo[Class];
RecvDesc = (PRECV_DESC)BundleRecvInfo->AssemblyList.Flink;
RecvDescHole = BundleRecvInfo->RecvDescHole;
TryToAssembleAgain:
while ((RecvDesc != RecvDescHole) &&
(RecvDesc->Flags & MULTILINK_BEGIN_FRAME)) {
PRECV_DESC NextRecvDesc = (PRECV_DESC)RecvDesc->Linkage.Flink;
DataPointer = RecvDesc->CurrentBuffer + RecvDesc->CurrentLength;
while ((NextRecvDesc != RecvDescHole) &&
!(RecvDesc->Flags & MULTILINK_END_FRAME)) {
RemoveEntryList(&NextRecvDesc->Linkage);
BundleRecvInfo->AssemblyCount--;
ASSERT(NextRecvDesc != RecvDescHole);
ASSERT(RecvDesc != RecvDescHole);
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("c 0x%x -> 0x%x",
NextRecvDesc->SequenceNumber, RecvDesc->SequenceNumber));
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("fl 0x%x -> 0x%x",
NextRecvDesc->Flags, RecvDesc->Flags));
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("l %d -> %d",
NextRecvDesc->CurrentLength, RecvDesc->CurrentLength));
//
// Update recvdesc info
//
RecvDesc->Flags |= NextRecvDesc->Flags;
RecvDesc->SequenceNumber = NextRecvDesc->SequenceNumber;
RecvDesc->CurrentLength += NextRecvDesc->CurrentLength;
//
// Make sure we don't assemble something too big!
//
if (RecvDesc->CurrentLength > (LONG)glMRRU) {
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("Max receive size exceeded!"));
//
// Return the recv desc's
//
RemoveEntryList(&RecvDesc->Linkage);
BundleRecvInfo->AssemblyCount--;
BundleCB->Stats.FramingErrors++;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dumping %x %x h: %x", RecvDesc->SequenceNumber,
RecvDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanFreeRecvDesc(RecvDesc);
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dumping %x %x h: %x", NextRecvDesc->SequenceNumber,
NextRecvDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanFreeRecvDesc(NextRecvDesc);
//
// Start at the list head and flush until we find either the hole
// or a new begin fragment.
//
RecvDesc = (PRECV_DESC)BundleRecvInfo->AssemblyList.Flink;
while (RecvDesc != RecvDescHole &&
!(RecvDesc->Flags & MULTILINK_BEGIN_FRAME)) {
RemoveHeadList(&BundleRecvInfo->AssemblyList);
BundleRecvInfo->AssemblyCount--;
NdisWanDbgOut(DBG_FAILURE, DBG_MULTILINK_RECV,
("dumping %x %x h: %x", RecvDesc->SequenceNumber,
RecvDesc->Flags, RecvDescHole->SequenceNumber));
NdisWanFreeRecvDesc(RecvDesc);
}
goto TryToAssembleAgain;
}
NdisMoveMemory(DataPointer,
NextRecvDesc->CurrentBuffer,
NextRecvDesc->CurrentLength);
DataPointer += NextRecvDesc->CurrentLength;
NdisWanFreeRecvDesc(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(&BundleRecvInfo->AssemblyList);
BundleRecvInfo->AssemblyCount--;
NdisWanDbgOut(DBG_INFO, DBG_MULTILINK_RECV, ("a %x %x", RecvDesc->SequenceNumber, RecvDesc->Flags));
RecvDesc->LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
if (NDIS_STATUS_PENDING != ProcessPPPFrame(BundleCB, RecvDesc)) {
NdisWanFreeRecvDesc(RecvDesc);
}
RecvDesc = (PRECV_DESC)BundleRecvInfo->AssemblyList.Flink;
} // end of while MULTILINK_BEGIN_FRAME
}
BOOLEAN
DoVJDecompression(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
{
ULONG BundleFraming;
PUCHAR FramePointer = RecvDesc->CurrentBuffer;
LONG FrameLength = RecvDesc->CurrentLength;
UCHAR VJCompType = 0;
BOOLEAN DoDecomp = FALSE;
BOOLEAN VJDetect = FALSE;
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 ((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 (RecvDesc->ProtocolID == PPP_PROTOCOL_COMPRESSED_TCP) {
VJCompType = TYPE_COMPRESSED_TCP;
} else {
VJCompType = TYPE_UNCOMPRESSED_TCP;
}
DoDecomp = TRUE;
}
if (DoDecomp) {
PUCHAR HeaderBuffer;
LONG PostCompSize, PreCompSize;
PreCompSize = RecvDesc->CurrentLength;
HeaderBuffer =
RecvDesc->StartBuffer + MAC_HEADER_LENGTH;
if ((PostCompSize = sl_uncompress_tcp(&RecvDesc->CurrentBuffer,
&RecvDesc->CurrentLength,
HeaderBuffer,
&RecvDesc->HeaderLength,
VJCompType,
BundleCB->VJCompress)) == 0) {
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("Error in sl_uncompress_tcp!"));
return(FALSE);
}
if (VJDetect) {
BundleCB->FramingInfo.RecvFramingBits |= SLIP_VJ_COMPRESSION;
BundleCB->FramingInfo.SendFramingBits |= SLIP_VJ_COMPRESSION;
}
ASSERT(PostCompSize == RecvDesc->HeaderLength + RecvDesc->CurrentLength);
#if DBG
if (VJCompType == TYPE_COMPRESSED_TCP) {
ASSERT(RecvDesc->HeaderLength > 0);
NdisWanDbgOut(DBG_TRACE, DBG_RECV_VJ,("rvj b %d a %d",(RecvDesc->HeaderLength - (PostCompSize-PreCompSize)), RecvDesc->HeaderLength));
}
#endif
//
// Calculate how much expansion we had
//
BundleCB->Stats.BytesReceivedCompressed +=
(RecvDesc->HeaderLength - (PostCompSize - PreCompSize));
BundleCB->Stats.BytesReceivedUncompressed += RecvDesc->HeaderLength;
}
RecvDesc->ProtocolID = PPP_PROTOCOL_IP;
return(TRUE);
}
#define SEQ_TYPE_IN_ORDER 1
#define SEQ_TYPE_AFTER_EXPECTED 2
#define SEQ_TYPE_BEFORE_EXPECTED 3
BOOLEAN
DoDecompDecryptProcessing(
PBUNDLECB BundleCB,
PUCHAR *DataPointer,
PLONG DataLength
)
{
USHORT Coherency, CurrCoherency;
ULONG Flags;
PWAN_STATS BundleStats;
PUCHAR FramePointer = *DataPointer;
LONG FrameLength = *DataLength;
ULONG PacketSeqType;
LONG OutOfOrderDepth;
LONG NumberMissed;
Flags = BundleCB->RecvFlags;
BundleStats = &BundleCB->Stats;
if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) {
PUCHAR SessionKey = BundleCB->RecvCryptoInfo.SessionKey;
ULONG SessionKeyLength = BundleCB->RecvCryptoInfo.SessionKeyLength;
PVOID RecvRC4Key = BundleCB->RecvCryptoInfo.RC4Key;
PVOID RecvCompressContext = BundleCB->RecvCompressContext;
BOOLEAN SyncCoherency = FALSE;
//
// Get the coherency counter
//
Coherency = (*FramePointer << 8) | *(FramePointer + 1);
FramePointer += 2;
FrameLength -= 2;
if (FrameLength <= 0) {
goto RESYNC;
}
if (!(Flags & DO_HISTORY_LESS))
{
// history-based
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
//
NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_RECEIVE,
("Recv old frame!!!! b %p rc %x < ec %x!!!!", BundleCB, Coherency & 0x0FFF,
BundleCB->RCoherencyCounter & 0x0FFF));
goto RESYNC;
}
}
else
{
// history-less
if((Coherency & 0x0FFF) == (BundleCB->RCoherencyCounter & 0x0FFF))
{
PacketSeqType = SEQ_TYPE_IN_ORDER;
}
else
{
if (SEQ_GT(Coherency & 0x0FFF,
BundleCB->RCoherencyCounter & 0x0FFF,
0x0800))
{
PacketSeqType = SEQ_TYPE_BEFORE_EXPECTED;
NumberMissed = ((Coherency & 0x0FFF) - (BundleCB->RCoherencyCounter & 0x0FFF)) & 0x0FFF;
ASSERT(NumberMissed > 0);
}
else
{
OutOfOrderDepth = ((BundleCB->RCoherencyCounter & 0x0FFF) - (Coherency & 0x0FFF)) & 0x0FFF;
if(OutOfOrderDepth <= (LONG)glMaxOutOfOrderDepth)
{
PacketSeqType = SEQ_TYPE_AFTER_EXPECTED;
}
else
{
//
// We received a sequence number that is either too earlier or too later
//
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE,
("Recv frame way out of order! b %p rc %x < ec %x!!!!", BundleCB, Coherency & 0x0FFF,
BundleCB->RCoherencyCounter & 0x0FFF));
return (FALSE);
}
}
}
}
//
// See if this is a flush packet
//
if (Coherency & (PACKET_FLUSHED << 8)) {
NdisWanDbgOut(DBG_INFO, DBG_RECEIVE,
("Recv Packet Flushed 0x%x", (Coherency & 0x0FFF)));
SyncCoherency = TRUE;
if ((Flags & DO_ENCRYPTION) &&
!(Flags & DO_HISTORY_LESS)) {
//
// 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 we are in history-less mode and we get out of sync
// we need to recreate all of the interim encryption
// keys that we missed, cache the keys
// When a packet comes in later, look for the cached key
//
if ((Flags & DO_HISTORY_LESS) &&
PacketSeqType != SEQ_TYPE_IN_ORDER) {
ULONG count;
LONG index;
PCACHED_KEY pKey;
if(PacketSeqType == SEQ_TYPE_AFTER_EXPECTED)
{
if (Coherency & (PACKET_ENCRYPTED << 8))
{
// This packet is encrypted
if (!(Flags & DO_ENCRYPTION)) {
//
// We are not configured to decrypt
//
return (FALSE);
}
// Find the cached key for this packet
pKey = BundleCB->RecvCryptoInfo.pCurrKey;
for(count = 0; count < glCachedKeyCount; count++)
{
// Walk through the keys
if(pKey > (PCACHED_KEY)BundleCB->RecvCryptoInfo.CachedKeyBuffer)
{
pKey = (PCACHED_KEY)((PUCHAR)pKey - (sizeof(USHORT)+ SessionKeyLength));
}
else
{
pKey = (PCACHED_KEY)BundleCB->RecvCryptoInfo.pLastKey;
}
if(pKey->Coherency == (Coherency & 0x0FFF))
{
//
// Re-Init the rc4 receive table
//
rc4_key(RecvRC4Key,
SessionKeyLength,
pKey->SessionKey);
pKey->Coherency = 0xffff; // avoid duplication
//
// Decrypt the data!
//
rc4(RecvRC4Key,
FrameLength,
FramePointer);
goto DECOMPRESS_DATA;
}
}
// Can't recover this packet, drop it
return (FALSE);
}
goto DECOMPRESS_DATA;
}
// This packet comes earlier than expected
SyncCoherency = TRUE;
if (Flags & DO_ENCRYPTION) {
#ifdef DBG_ECP
DbgPrint("NDISWAN: Missed %d frames, regening keys...\n", NumberMissed);
DbgPrint("NDISWAN: resync b %p rc %x ec %x\n", BundleCB, Coherency & 0x0FFF,
BundleCB->RCoherencyCounter & 0x0FFF);
#endif
CurrCoherency = BundleCB->RCoherencyCounter & 0x0FFF;
while (NumberMissed--) {
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->RecvCryptoInfo);
}
//
// 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 (Flags & DO_40_ENCRYPTION) {
//
// If this is 40 bit encryption we need to fix
// the first 3 bytes of the key.
//
SessionKey[0] = 0xD1;
SessionKey[1] = 0x26;
SessionKey[2] = 0x9E;
} else if (Flags & DO_56_ENCRYPTION) {
//
// If this is 56 bit encryption we need to fix
// the first byte of the key.
//
SessionKey[0] = 0xD1;
}
if(NumberMissed < (LONG)glCachedKeyCount)
{
BundleCB->RecvCryptoInfo.pCurrKey->Coherency = CurrCoherency;
NdisMoveMemory(BundleCB->RecvCryptoInfo.pCurrKey->SessionKey,
SessionKey,
SessionKeyLength);
if(BundleCB->RecvCryptoInfo.pCurrKey < BundleCB->RecvCryptoInfo.pLastKey)
{
BundleCB->RecvCryptoInfo.pCurrKey = (PCACHED_KEY)((PUCHAR)BundleCB->RecvCryptoInfo.pCurrKey +
sizeof(USHORT) + SessionKeyLength);
ASSERT(BundleCB->RecvCryptoInfo.pCurrKey <= BundleCB->RecvCryptoInfo.pLastKey);
}
else
{
BundleCB->RecvCryptoInfo.pCurrKey = (PCACHED_KEY)BundleCB->RecvCryptoInfo.CachedKeyBuffer;
}
}
NdisWanDbgOut(DBG_TRACE, DBG_CCP,
("RC4 Recv encryption KeyLength %d", BundleCB->RecvCryptoInfo.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->RecvCryptoInfo.SessionKey[0],
BundleCB->RecvCryptoInfo.SessionKey[1],
BundleCB->RecvCryptoInfo.SessionKey[2],
BundleCB->RecvCryptoInfo.SessionKey[3],
BundleCB->RecvCryptoInfo.SessionKey[4],
BundleCB->RecvCryptoInfo.SessionKey[5],
BundleCB->RecvCryptoInfo.SessionKey[6],
BundleCB->RecvCryptoInfo.SessionKey[7],
BundleCB->RecvCryptoInfo.SessionKey[8],
BundleCB->RecvCryptoInfo.SessionKey[9],
BundleCB->RecvCryptoInfo.SessionKey[10],
BundleCB->RecvCryptoInfo.SessionKey[11],
BundleCB->RecvCryptoInfo.SessionKey[12],
BundleCB->RecvCryptoInfo.SessionKey[13],
BundleCB->RecvCryptoInfo.SessionKey[14],
BundleCB->RecvCryptoInfo.SessionKey[15]));
// Re-initialize the rc4 receive table to the
// scrambled session key
//
rc4_key(RecvRC4Key, SessionKeyLength, SessionKey);
if(CurrCoherency < (USHORT)0x0FFF)
{
++CurrCoherency;
}
else
{
CurrCoherency = 0;
}
}
}
}
if (SyncCoherency) {
if ((BundleCB->RCoherencyCounter & 0x0FFF) >
(Coherency & 0x0FFF)) {
BundleCB->RCoherencyCounter += 0x1000;
}
BundleCB->RCoherencyCounter &= 0xF000;
BundleCB->RCoherencyCounter |= (Coherency & 0x0FFF);
}
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);
}
//
// Check for history less
//
if ((Flags & DO_HISTORY_LESS) ||
(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->RecvCryptoInfo);
}
//
// 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.
//
if (Flags & DO_40_ENCRYPTION) {
//
// If this is 40 bit encryption we need to fix
// the first 3 bytes of the key.
//
SessionKey[0] = 0xD1;
SessionKey[1] = 0x26;
SessionKey[2] = 0x9E;
} else if (Flags & DO_56_ENCRYPTION) {
//
// If this is 56 bit encryption we need to fix
// the first byte of the key.
//
SessionKey[0] = 0xD1;
}
NdisWanDbgOut(DBG_TRACE, DBG_CCP,
("RC4 Recv encryption KeyLength %d", BundleCB->RecvCryptoInfo.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->RecvCryptoInfo.SessionKey[0],
BundleCB->RecvCryptoInfo.SessionKey[1],
BundleCB->RecvCryptoInfo.SessionKey[2],
BundleCB->RecvCryptoInfo.SessionKey[3],
BundleCB->RecvCryptoInfo.SessionKey[4],
BundleCB->RecvCryptoInfo.SessionKey[5],
BundleCB->RecvCryptoInfo.SessionKey[6],
BundleCB->RecvCryptoInfo.SessionKey[7],
BundleCB->RecvCryptoInfo.SessionKey[8],
BundleCB->RecvCryptoInfo.SessionKey[9],
BundleCB->RecvCryptoInfo.SessionKey[10],
BundleCB->RecvCryptoInfo.SessionKey[11],
BundleCB->RecvCryptoInfo.SessionKey[12],
BundleCB->RecvCryptoInfo.SessionKey[13],
BundleCB->RecvCryptoInfo.SessionKey[14],
BundleCB->RecvCryptoInfo.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
DECOMPRESS_DATA:
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("dce1 %x\n", Coherency);
#endif
//
// Error decompressing!
//
if (!(Flags & DO_HISTORY_LESS)) {
BundleCB->RCoherencyCounter--;
}
goto RESYNC;
}
if (FrameLength <= 0 ||
FrameLength > (LONG)glMRRU) {
#if DBG
DbgPrint("dce2 %d %x\n", FrameLength, Coherency);
#endif
//
// Error decompressing!
//
if (!(Flags & DO_HISTORY_LESS)) {
BundleCB->RCoherencyCounter--;
}
goto RESYNC;
}
BundleStats->BytesReceivedUncompressed += FrameLength;
} // end of compression
} else { // end of insync
RESYNC:
NdisWanDbgOut(DBG_FAILURE, DBG_RECEIVE, ("oos r %x, e %x\n", (Coherency & 0x0FFF),
(BundleCB->RCoherencyCounter & 0x0FFF)));
if (!(Flags & DO_HISTORY_LESS)) {
//
// We are out of sync!
//
do {
PLINKCB LinkCB;
PNDISWAN_IO_PACKET IoPacket;
if (BundleCB->ulLinkCBCount == 0) {
break;
}
NdisWanAllocateMemory(&IoPacket,
sizeof(NDISWAN_IO_PACKET) + 100,
IOPACKET_TAG);
if (IoPacket == NULL) {
break;
}
LinkCB =
(PLINKCB)BundleCB->LinkCBList.Flink;
NdisDprAcquireSpinLock(&LinkCB->Lock);
if (LinkCB->State != LINK_UP) {
NdisDprReleaseSpinLock(&LinkCB->Lock);
NdisWanFreeMemory(IoPacket);
break;
}
REF_LINKCB(LinkCB);
NdisDprReleaseSpinLock(&LinkCB->Lock);
IoPacket->hHandle = BundleCB->hBundleHandle;
IoPacket->usHandleType = BUNDLEHANDLE;
IoPacket->usHeaderSize = 0;
IoPacket->usPacketSize = 6;
IoPacket->usPacketFlags = 0;
IoPacket->PacketData[0] = 0x80;
IoPacket->PacketData[1] = 0xFD;
IoPacket->PacketData[2] = 14;
IoPacket->PacketData[3] = (UCHAR)BundleCB->CCPIdentifier++;
IoPacket->PacketData[4] = 0x00;
IoPacket->PacketData[5] = 0x04;
LinkCB = (PLINKCB)BundleCB->LinkCBList.Flink;
BuildIoPacket(LinkCB, BundleCB, IoPacket, FALSE);
NdisWanFreeMemory(IoPacket);
} while (FALSE);
}
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
//
BundleCB->Flags |= RECV_PACKET_FLUSH;
}
}
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"));
}
BOOLEAN
IpIsDataFrame(
PUCHAR HeaderBuffer,
ULONG HeaderBufferLength,
ULONG TotalLength
)
{
UINT tcpheaderlength ;
UINT ipheaderlength ;
UCHAR *tcppacket;
UCHAR *ippacket = HeaderBuffer;
UCHAR SrcPort, DstPort;
IPV4Header UNALIGNED *ipheader = (IPV4Header UNALIGNED *) HeaderBuffer;
#define TYPE_IGMP 2
if (ipheader->ip_p == TYPE_IGMP) {
if (gbIGMPIdle) {
return FALSE;
}
return TRUE;
}
SrcPort = (UCHAR) *(ippacket + ((*ippacket & 0x0f)*4) + 1);
DstPort = (UCHAR) *(ippacket + ((*ippacket & 0x0f)*4) + 3);
if (DstPort == 53) {
//
// UDP/TCP port 53 - DNS
//
return FALSE;
}
#define TYPE_UDP 17
#define UDPPACKET_SRC_PORT_137(x) ((UCHAR) *(x + ((*x & 0x0f)*4) + 1) == 137)
#define UDPPACKET_SRC_PORT_138(x) ((UCHAR) *(x + ((*x & 0x0f)*4) + 1) == 138)
if (ipheader->ip_p == TYPE_UDP) {
if ((SrcPort == 137) ||
(SrcPort == 138)) {
//
// UDP port 137 - NETBIOS Name Service
// UDP port 138 - NETBIOS Datagram Service
//
return FALSE ;
} else {
return TRUE ;
}
}
#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 this is a PPTP keepalive packet then ignore
//
if (DstPort == 1723) {
UNALIGNED PPTP_HEADER *PptpHeader;
PptpHeader = (UNALIGNED PPTP_HEADER*)(tcppacket+tcpheaderlength);
if (PptpHeader->PacketType == 1 &&
(PptpHeader->MessageType == 5 ||
PptpHeader->MessageType == 6)) {
return FALSE;
}
return TRUE;
}
if (!((SrcPort == 139) || (DstPort == 139)))
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 ;
//
// If this is a PPTP keep alive then ignore
//
}
//
// 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);
}
VOID
IndicatePromiscuousRecv(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc,
RECV_TYPE RecvType
)
{
UCHAR Header1[] = {' ', 'W', 'A', 'N', 'R', 0xFF, ' ', 'W', 'A', 'N', 'R', 0xFF};
PUCHAR HeaderBuffer, DataBuffer;
ULONG HeaderLength, DataLength;
PNDIS_BUFFER NdisBuffer;
PNDIS_PACKET NdisPacket;
PRECV_DESC LocalRecvDesc;
PLINKCB LinkCB = RecvDesc->LinkCB;
KIRQL OldIrql;
PMINIPORTCB Adapter;
NdisAcquireSpinLock(&NdisWanCB.Lock);
Adapter = NdisWanCB.PromiscuousAdapter;
NdisReleaseSpinLock(&NdisWanCB.Lock);
if (Adapter == NULL) {
return;
}
DataLength = (RecvDesc->CurrentLength > (LONG)glLargeDataBufferSize) ?
glLargeDataBufferSize : RecvDesc->CurrentLength;
LocalRecvDesc =
NdisWanAllocateRecvDesc(DataLength + MAC_HEADER_LENGTH);
if (LocalRecvDesc == NULL) {
return;
}
HeaderBuffer =
LocalRecvDesc->StartBuffer;
HeaderLength = 0;
switch (RecvType) {
case RECV_LINK:
NdisMoveMemory(HeaderBuffer, Header1, sizeof(Header1));
HeaderBuffer[5] =
HeaderBuffer[11] = (UCHAR)LinkCB->hLinkHandle;
HeaderBuffer[12] = (UCHAR)(DataLength >> 8);
HeaderBuffer[13] = (UCHAR)DataLength;
HeaderLength = MAC_HEADER_LENGTH;
break;
case RECV_BUNDLE_PPP:
case RECV_BUNDLE_DATA:
break;
}
DataBuffer = HeaderBuffer + HeaderLength;
NdisMoveMemory(DataBuffer,
RecvDesc->CurrentBuffer,
DataLength);
LocalRecvDesc->CurrentBuffer = HeaderBuffer;
LocalRecvDesc->CurrentLength = HeaderLength + DataLength;
if (LocalRecvDesc->CurrentLength > 1514) {
LocalRecvDesc->CurrentLength = 1514;
}
//
// Get an ndis packet
//
NdisPacket =
LocalRecvDesc->NdisPacket;
PPROTOCOL_RESERVED_FROM_NDIS(NdisPacket)->RecvDesc = LocalRecvDesc;
//
// Attach the buffers
//
NdisAdjustBufferLength(LocalRecvDesc->NdisBuffer,
LocalRecvDesc->CurrentLength);
NdisRecalculatePacketCounts(NdisPacket);
ReleaseBundleLock(BundleCB);
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
NDIS_SET_PACKET_STATUS(NdisPacket, NDIS_STATUS_RESOURCES);
INSERT_DBG_RECV(PacketTypeNdis,
Adapter,
NULL,
RecvDesc->LinkCB,
NdisPacket);
//
// Indicate the packet
// This assumes that bloodhound is always a legacy transport
//
NdisMIndicateReceivePacket(Adapter->MiniportHandle,
&NdisPacket,
1);
KeLowerIrql(OldIrql);
AcquireBundleLock(BundleCB);
#if DBG
{
NDIS_STATUS Status;
Status = NDIS_GET_PACKET_STATUS(NdisPacket);
ASSERT(Status == NDIS_STATUS_RESOURCES);
REMOVE_DBG_RECV(PacketTypeNdis, Adapter, NdisPacket);
}
#endif
{
PNDIS_BUFFER NdisBuffer;
NdisWanFreeRecvDesc(LocalRecvDesc);
}
}
BOOLEAN
GetProtocolFromPPPId(
PBUNDLECB BundleCB,
USHORT Id,
PPROTOCOLCB *ProtocolCB
)
{
PPROTOCOLCB ppcb;
BOOLEAN Found;
*ProtocolCB = NULL;
ppcb = (PPROTOCOLCB)BundleCB->ProtocolCBList.Flink;
Found = FALSE;
while ((PVOID)ppcb != (PVOID)&BundleCB->ProtocolCBList) {
if (ppcb->State == PROTOCOL_ROUTED) {
if (ppcb->PPPProtocolID == Id) {
*ProtocolCB = ppcb;
Found = TRUE;
break;
}
}
ppcb = (PPROTOCOLCB)ppcb->Linkage.Flink;
}
return (Found);
}
#ifdef NT
NDIS_STATUS
CompleteIoRecvPacket(
PBUNDLECB BundleCB,
PRECV_DESC RecvDesc
)
{
KIRQL Irql;
USHORT ProtocolID;
UCHAR Header[] = {' ', 'R', 'E', 'C', 'V', 0xFF};
PNDISWAN_IO_PACKET IoPacket;
PIO_STACK_LOCATION IrpSp;
PIRP Irp;
LONG CopySize, BufferLength, DataLength;
PLIST_ENTRY Entry;
PUCHAR HeaderPointer;
PLINKCB LinkCB = RecvDesc->LinkCB;
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("CompleteIoRecvPacket: Enter"));
HeaderPointer =
RecvDesc->StartBuffer;
ProtocolID = RecvDesc->ProtocolID;
//
// Fill the frame out, and queue the data
//
NdisMoveMemory(HeaderPointer,
Header,
sizeof(Header));
NdisMoveMemory(&HeaderPointer[6],
Header,
sizeof(Header));
HeaderPointer[5] =
HeaderPointer[11] = (UCHAR)LinkCB->hLinkHandle;
HeaderPointer[12] = (UCHAR)(ProtocolID >> 8);
HeaderPointer[13] = (UCHAR)ProtocolID;
NdisMoveMemory(HeaderPointer + 14,
RecvDesc->CurrentBuffer,
RecvDesc->CurrentLength);
RecvDesc->CurrentBuffer = RecvDesc->StartBuffer;
RecvDesc->CurrentLength += 14;
#if DBG
if (gbDumpRecv) {
INT i;
DbgPrint("RecvData:");
for (i = 0; i < RecvDesc->CurrentLength; i++) {
if (i % 16 == 0) {
DbgPrint("\n");
}
DbgPrint("%2.2x ", RecvDesc->CurrentBuffer[i]);
}
DbgPrint("\n");
}
#endif
ReleaseBundleLock(BundleCB);
//
// See if someone has registered a recv context
// for this link or if there are any irps around
// to complete take this receive
//
NdisAcquireSpinLock(&IoRecvList.Lock);
NdisDprAcquireSpinLock(&LinkCB->Lock);
Entry = IoRecvList.IrpList.Flink;
Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
if ((LinkCB->hLinkContext == NULL) ||
(LinkCB->RecvDescCount > 0) ||
(IoRecvList.ulIrpCount == 0) ||
!IoSetCancelRoutine(Irp, NULL)) {
NDIS_STATUS Status;
//
// We will only buffer 5 packets for each link to avoid
// chewing up tons of non-paged memory if rasman is not
// reading at all.
//
if ((LinkCB->State == LINK_UP) &&
(LinkCB->RecvDescCount < 5)) {
InsertTailList(&IoRecvList.DescList,
&RecvDesc->Linkage);
LinkCB->RecvDescCount++;
IoRecvList.ulDescCount++;
if (IoRecvList.ulDescCount > IoRecvList.ulMaxDescCount) {
IoRecvList.ulMaxDescCount = IoRecvList.ulDescCount;
}
Status = NDIS_STATUS_PENDING;
} else {
Status = NDIS_STATUS_FAILURE;
}
NdisDprReleaseSpinLock(&LinkCB->Lock);
NdisReleaseSpinLock(&IoRecvList.Lock);
AcquireBundleLock(BundleCB);
return(Status);
}
RemoveHeadList(&IoRecvList.IrpList);
IoRecvList.ulIrpCount--;
INSERT_RECV_EVENT('a');
IrpSp = IoGetCurrentIrpStackLocation(Irp);
BufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
DataLength = BufferLength - sizeof(NDISWAN_IO_PACKET) + 1;
CopySize = (RecvDesc->CurrentLength > DataLength) ?
DataLength : RecvDesc->CurrentLength;
IoPacket = Irp->AssociatedIrp.SystemBuffer;
IoPacket->hHandle = LinkCB->hLinkContext;
IoPacket->usHandleType = LINKHANDLE;
IoPacket->usHeaderSize = 14;
IoPacket->usPacketSize = (USHORT)CopySize;
IoPacket->usPacketFlags = 0;
#if DBG
if (gbDumpRecv) {
INT i;
for (i = 0; i < RecvDesc->CurrentLength; i++) {
if (i % 16 == 0) {
DbgPrint("\n");
}
DbgPrint("%x ", RecvDesc->CurrentBuffer[i]);
}
DbgPrint("\n");
}
#endif
NdisMoveMemory(IoPacket->PacketData,
RecvDesc->CurrentBuffer,
CopySize);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(NDISWAN_IO_PACKET) - 1 + CopySize;
IoRecvList.LastPacketNumber = IoPacket->PacketNumber;
IoRecvList.LastIrp = Irp;
IoRecvList.LastIrpStatus = STATUS_SUCCESS;
IoRecvList.LastCopySize = (ULONG)Irp->IoStatus.Information;
ASSERT((LONG_PTR)Irp->IoStatus.Information > 0);
NdisDprReleaseSpinLock(&LinkCB->Lock);
NdisReleaseSpinLock(&IoRecvList.Lock);
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
AcquireBundleLock(BundleCB);
if (NdisWanCB.PromiscuousAdapter != NULL) {
IndicatePromiscuousRecv(BundleCB, RecvDesc, RECV_BUNDLE_PPP);
}
NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("CompleteIoRecvPacket: Exit"));
return(NDIS_STATUS_SUCCESS);
}
#endif // end ifdef NT