|
|
/*++
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; }
|