/*++ Copyright (c) 1995 Microsoft Corporation Module Name: net\routing\ip\wanarp2\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); if (pvFirstBuffer==NULL) return 0; // // The first buffer better contain enough data // if (uiFirstBufLen < sizeof(ETH_HEADER) + sizeof(IP_HEADER)) return 0; 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; }