windows-nt/Source/XPSP1/NT/net/rras/ip/wanarp2/rcv.c

477 lines
10 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}