mirror of https://github.com/tongzx/nt5src
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.
476 lines
10 KiB
476 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
net\routing\ip\ipinip\rcv.c
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#define __FILE_SIG__ RCV_SIG
|
|
|
|
#include "inc.h"
|
|
|
|
INT
|
|
WanNdisReceivePacket(
|
|
IN NDIS_HANDLE nhProtocolContext,
|
|
IN PNDIS_PACKET pnpPacket
|
|
)
|
|
{
|
|
PNDIS_BUFFER pnbBuffer;
|
|
PVOID pvFirstBuffer;
|
|
UINT uiFirstBufLen, uiTotalPacketLen;
|
|
INT iClientCount;
|
|
NDIS_STATUS nsStatus;
|
|
|
|
TraceEnter(RCV, "NdisReceivePacket");
|
|
|
|
NdisGetFirstBufferFromPacket(pnpPacket,
|
|
&pnbBuffer,
|
|
&pvFirstBuffer,
|
|
&uiFirstBufLen,
|
|
&uiTotalPacketLen);
|
|
|
|
//
|
|
// The first buffer better contain enough data
|
|
//
|
|
|
|
RtAssert(uiFirstBufLen >= sizeof(ETH_HEADER) + sizeof(IP_HEADER));
|
|
|
|
iClientCount = 0;
|
|
|
|
nsStatus = WanReceiveCommon(nhProtocolContext,
|
|
pnpPacket,
|
|
pvFirstBuffer,
|
|
sizeof(ETH_HEADER),
|
|
(PVOID)((ULONG_PTR)pvFirstBuffer + sizeof(ETH_HEADER)),
|
|
uiFirstBufLen - sizeof(ETH_HEADER),
|
|
uiTotalPacketLen - sizeof(ETH_HEADER),
|
|
pnbBuffer,
|
|
&iClientCount);
|
|
|
|
return iClientCount;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
WanNdisReceive(
|
|
NDIS_HANDLE nhProtocolContext,
|
|
NDIS_HANDLE nhXferContext,
|
|
VOID UNALIGNED *pvHeader,
|
|
UINT uiHeaderLen,
|
|
VOID UNALIGNED *pvData,
|
|
UINT uiFirstBufferLen,
|
|
UINT uiTotalDataLen
|
|
)
|
|
{
|
|
TraceEnter(RCV, "NdisReceive");
|
|
|
|
return WanReceiveCommon(nhProtocolContext,
|
|
nhXferContext,
|
|
pvHeader,
|
|
uiHeaderLen,
|
|
pvData,
|
|
uiFirstBufferLen,
|
|
uiTotalDataLen,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
NDIS_STATUS
|
|
WanReceiveCommon(
|
|
NDIS_HANDLE nhProtocolContext,
|
|
NDIS_HANDLE nhXferContext,
|
|
VOID UNALIGNED *pvHeader,
|
|
UINT uiHeaderLen,
|
|
VOID UNALIGNED *pvData,
|
|
UINT uiFirstBufferLen,
|
|
UINT uiTotalDataLen,
|
|
PMDL pMdl,
|
|
PINT piClientCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The common receive handler for packet based or buffer based receives
|
|
|
|
Locks:
|
|
|
|
Called at DPC (usually).
|
|
Acquires the g_rlConnTable lock to get a pointer to the connection
|
|
entry. Then locks either the entry itself or the adapter.
|
|
|
|
Arguments:
|
|
|
|
nhProtocolContext
|
|
nhXferContext
|
|
pvHeader
|
|
uiHeaderLen
|
|
pvData
|
|
uiFirstBufferLen
|
|
uiTotalDataLen
|
|
pMdl
|
|
piClientCount
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_NOT_ACCEPTED
|
|
|
|
--*/
|
|
|
|
{
|
|
PCONN_ENTRY pConnEntry;
|
|
PADAPTER pAdapter;
|
|
PUMODE_INTERFACE pInterface;
|
|
ETH_HEADER UNALIGNED *pEthHeader;
|
|
KIRQL kiIrql;
|
|
WORD wType;
|
|
ULONG ulIndex;
|
|
BOOLEAN bNonUnicast;
|
|
|
|
#if DBG
|
|
|
|
IP_HEADER UNALIGNED *pIpHeader;
|
|
|
|
#endif
|
|
|
|
//
|
|
// Pick out connection index from the buffer
|
|
//
|
|
|
|
pEthHeader = (ETH_HEADER UNALIGNED *)pvHeader;
|
|
|
|
ulIndex = GetConnIndexFromAddr(pEthHeader->rgbyDestAddr);
|
|
|
|
RtAcquireSpinLock(&g_rlConnTableLock,
|
|
&kiIrql);
|
|
|
|
if(ulIndex >= g_ulConnTableSize)
|
|
{
|
|
Trace(RCV, ERROR,
|
|
("ReceiveCommon: Invalid index for conn entry %d\n",
|
|
ulIndex));
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
|
|
pConnEntry = GetConnEntryGivenIndex(ulIndex);
|
|
|
|
if(pConnEntry is NULL)
|
|
{
|
|
Trace(RCV, ERROR,
|
|
("ReceiveCommon: Couldnt find entry for conn %d\n",
|
|
ulIndex));
|
|
|
|
RtReleaseSpinLock(&g_rlConnTableLock,
|
|
kiIrql);
|
|
|
|
return NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
|
|
//
|
|
// Lock the connection entry or adapter
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(pConnEntry->prlLock);
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&g_rlConnTableLock);
|
|
|
|
//
|
|
// We can get this only on a connected entry
|
|
//
|
|
|
|
RtAssert(pConnEntry->byState is CS_CONNECTED);
|
|
|
|
pAdapter = pConnEntry->pAdapter;
|
|
|
|
//
|
|
// A connected entry must have an adapter
|
|
//
|
|
|
|
RtAssert(pAdapter);
|
|
|
|
//
|
|
// The interface better also be present
|
|
//
|
|
|
|
pInterface = pAdapter->pInterface;
|
|
|
|
RtAssert(pInterface);
|
|
|
|
if(pConnEntry->duUsage isnot DU_CALLIN)
|
|
{
|
|
//
|
|
// For non clients, also lock the interface
|
|
//
|
|
|
|
RtAcquireSpinLockAtDpcLevel(&(pInterface->rlLock));
|
|
}
|
|
|
|
#if DBG
|
|
|
|
Trace(RCV, INFO,
|
|
("ReceiveCommon: Extracted adapter %x with name %s\n",
|
|
pAdapter,
|
|
pAdapter->asDeviceNameA.Buffer));
|
|
|
|
pIpHeader = (IP_HEADER UNALIGNED *)pvData;
|
|
|
|
RtAssert((pIpHeader->byVerLen & 0xF0) is 0x40);
|
|
RtAssert(LengthOfIpHeader(pIpHeader) >= 20);
|
|
|
|
//
|
|
// If the packet is not fragmented, then the data from its header
|
|
// should be <= the data ndis gives us (<= because there may be
|
|
// padding and ndis may be giving us trailing bytes)
|
|
//
|
|
|
|
//RtAssert(RtlUshortByteSwap(pIpHeader->wLength) <= uiTotalDataLen);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Increment some stats. For the server interface, these can be
|
|
// inconsistent
|
|
//
|
|
|
|
pInterface->ulInOctets += (uiTotalDataLen + uiHeaderLen);
|
|
|
|
//
|
|
// Verify this is a well formed packet
|
|
//
|
|
|
|
wType = RtlUshortByteSwap(pEthHeader->wType);
|
|
|
|
if(wType isnot ARP_ETYPE_IP)
|
|
{
|
|
pInterface->ulInUnknownProto++;
|
|
|
|
Trace(RCV, ERROR,
|
|
("ReceiveCommon: Type %d is wrong\n", wType));
|
|
|
|
if(pConnEntry->duUsage isnot DU_CALLIN)
|
|
{
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
}
|
|
|
|
RtReleaseSpinLock(pConnEntry->prlLock,
|
|
kiIrql);
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
|
|
return NDIS_STATUS_NOT_RECOGNIZED;
|
|
}
|
|
|
|
//
|
|
// Need to figure out if this is a unicast or a broadcast. At the
|
|
// link layer we dont have a concept of broadcast. So, we always mark
|
|
// this as unicast. We can be smarter about this and look at the
|
|
// IPHeader and decide based on the IP dest addr
|
|
//
|
|
|
|
bNonUnicast = FALSE;
|
|
|
|
pInterface->ulInUniPkts++;
|
|
|
|
//
|
|
// Check if the filtering of the Netbios packets is enabled on this
|
|
// connection. If so then do not indicate the packet.
|
|
//
|
|
|
|
if((pConnEntry->bFilterNetBios is TRUE) and
|
|
(WanpDropNetbiosPacket((PBYTE)pvData,uiFirstBufferLen)))
|
|
{
|
|
pInterface->ulInDiscards++;
|
|
|
|
Trace(RCV, TRACE,
|
|
("ReceiveCommon: Dropping Netbios packet\n", wType));
|
|
|
|
if(pConnEntry->duUsage isnot DU_CALLIN)
|
|
{
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
}
|
|
|
|
RtReleaseSpinLock(pConnEntry->prlLock,
|
|
kiIrql);
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
|
|
return NDIS_STATUS_NOT_ACCEPTED;
|
|
}
|
|
|
|
//
|
|
// Release the lock BEFORE we tell IP
|
|
//
|
|
|
|
if(pConnEntry->duUsage isnot DU_CALLIN)
|
|
{
|
|
RtReleaseSpinLockFromDpcLevel(&(pInterface->rlLock));
|
|
}
|
|
|
|
RtReleaseSpinLock(pConnEntry->prlLock,
|
|
kiIrql);
|
|
|
|
#if PKT_DBG
|
|
|
|
Trace(RCV, ERROR,
|
|
("ReceiveCommon: \nMdl %x Pkt %x Hdr %x Data %x\n",
|
|
pMdl,
|
|
nhXferContext,
|
|
pvHeader,
|
|
pvData));
|
|
|
|
#endif // PKT_DBG
|
|
|
|
if(pMdl)
|
|
{
|
|
g_pfnIpRcvPkt(pAdapter->pvIpContext,
|
|
(PBYTE)pvData,
|
|
uiFirstBufferLen,
|
|
uiTotalDataLen,
|
|
nhXferContext,
|
|
0,
|
|
bNonUnicast,
|
|
sizeof(ETH_HEADER),
|
|
pMdl,
|
|
piClientCount,
|
|
pConnEntry->pvIpLinkContext);
|
|
}
|
|
else
|
|
{
|
|
g_pfnIpRcv(pAdapter->pvIpContext,
|
|
(PBYTE)pvData,
|
|
uiFirstBufferLen,
|
|
uiTotalDataLen,
|
|
nhXferContext,
|
|
0,
|
|
bNonUnicast,
|
|
pConnEntry->pvIpLinkContext);
|
|
}
|
|
|
|
DereferenceConnEntry(pConnEntry);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
WanNdisReceiveComplete(
|
|
NDIS_HANDLE nhBindHandle
|
|
)
|
|
{
|
|
TraceEnter(RCV, "NdisReceiveComplete");
|
|
|
|
g_pfnIpRcvComplete();
|
|
}
|
|
|
|
NDIS_STATUS
|
|
WanIpTransferData(
|
|
PVOID pvContext,
|
|
NDIS_HANDLE nhMacContext,
|
|
UINT uiProtoOffset,
|
|
UINT uiTransferOffset,
|
|
UINT uiTransferLength,
|
|
PNDIS_PACKET pnpPacket,
|
|
PUINT puiTransferred
|
|
)
|
|
{
|
|
RtAssert(FALSE);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
WanNdisTransferDataComplete(
|
|
NDIS_HANDLE nhProtocolContext,
|
|
PNDIS_PACKET pnpPacket,
|
|
NDIS_STATUS nsStatus,
|
|
UINT uiBytesCopied
|
|
)
|
|
{
|
|
RtAssert(FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
UINT
|
|
WanIpReturnPacket(
|
|
PVOID pvContext,
|
|
PNDIS_PACKET pnpPacket
|
|
)
|
|
{
|
|
Trace(RCV, ERROR,
|
|
("IpReturnPacket: %x\n",
|
|
pnpPacket));
|
|
|
|
NdisReturnPackets(&pnpPacket,
|
|
1);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
WanpDropNetbiosPacket(
|
|
PBYTE pbyBuffer,
|
|
ULONG ulBufferLen
|
|
)
|
|
{
|
|
IP_HEADER UNALIGNED *pIpHeader;
|
|
PBYTE pbyUdpPacket;
|
|
WORD wSrcPort;
|
|
ULONG ulIpHdrLen;
|
|
|
|
pIpHeader = (IP_HEADER UNALIGNED *)pbyBuffer;
|
|
|
|
if(pIpHeader->byProtocol is 0x11)
|
|
{
|
|
ulIpHdrLen = LengthOfIpHeader(pIpHeader);
|
|
|
|
//
|
|
// If we cant get to the 10th byte in the UDP packet in this
|
|
// buffer, we just let the packet go
|
|
//
|
|
|
|
if(ulBufferLen < ulIpHdrLen + 10)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pbyUdpPacket = (PBYTE)((ULONG_PTR)pbyBuffer + ulIpHdrLen);
|
|
|
|
wSrcPort = *((WORD UNALIGNED *)pbyUdpPacket);
|
|
|
|
if(wSrcPort is PORT137_NBO)
|
|
{
|
|
//
|
|
// UDP port 137 is NETBIOS/IP traffic
|
|
//
|
|
|
|
//
|
|
// Allow only WINS Query Requests to go through
|
|
// WINS Query packets have x0000xxx in the 10th byte
|
|
//
|
|
|
|
if(((*(pbyUdpPacket + 10)) & 0x78) isnot 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|