492 lines
11 KiB
C
492 lines
11 KiB
C
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
net\routing\ip\ipinip\rcv.c
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#define __FILE_SIG__ RCV_SIG
|
|
|
|
#include "inc.h"
|
|
|
|
|
|
IP_STATUS
|
|
IpIpRcvDatagram(
|
|
IN PVOID pvIpContext,
|
|
IN DWORD dwDestAddr,
|
|
IN DWORD dwSrcAddr,
|
|
IN DWORD dwAcceptAddr,
|
|
IN DWORD dwRcvAddr,
|
|
IN IPHeader UNALIGNED pHeader,
|
|
IN UINT uiHdrLen,
|
|
IN IPRcvBuf *pRcvBuf,
|
|
IN UINT uiTotalLen,
|
|
IN BOOLEAN bIsBCast,
|
|
IN BYTE byProtocol,
|
|
IN IPOptInfo *pOptInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
This
|
|
|
|
Locks
|
|
|
|
|
|
|
|
Arguments
|
|
|
|
pvIpContext IP's context for the receive indication. Currently this
|
|
is a pointer to the source NTE
|
|
dwDestAddr The Destination address in the header
|
|
dwSrcAddr The Source Address in the header
|
|
dwAcceptAddr The address of the NTE which "accepted" this packet
|
|
dwRcvAddr The address of the NTE on which the packet was received
|
|
pHeader Pointer to the IP Header
|
|
uiHdrLen The header length
|
|
pRcvBuf The COMPLETE packet in an IPRcvBuf structure
|
|
uiRcvdDataLen The size of the received datagram
|
|
bIsBCast Whether the packet was a link layer broadcast
|
|
byProtocol The Protocol ID in the header
|
|
pOptInfo Pointer to Option info
|
|
|
|
Return Value
|
|
|
|
IP_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
PTRANSFER_CONTEXT pXferCtxt;
|
|
PNDIS_BUFFER pnbFirstBuffer;
|
|
PVOID pvData;
|
|
PIRP pIrp;
|
|
IP_HEADER UNALIGNED *pInHeader, *pOutHeader;
|
|
ULARGE_INTEGER uliTunnelId;
|
|
PTUNNEL pTunnel;
|
|
ULONG ulOutHdrLen, ulDataLen;
|
|
BOOLEAN bNonUnicast;
|
|
|
|
TraceEnter(RCV, "TdixReceiveIpIp");
|
|
|
|
//
|
|
// Get a pointer to the first buffer
|
|
//
|
|
|
|
pvData = (PVOID)(pRcvBuf->ipr_buffer);
|
|
|
|
RtAssert(pvData);
|
|
|
|
//
|
|
// Figure out the tunnel for this receive
|
|
// Since the transport indicates atleast 128 bytes, we can safely read out
|
|
// the IP Header
|
|
//
|
|
|
|
RtAssert(uiTotalLen > sizeof(IP_HEADER));
|
|
|
|
|
|
pOutHeader = pHeader;
|
|
|
|
RtAssert(pOutHeader->byProtocol is PROTO_IPINIP);
|
|
RtAssert(pOutHeader->byVerLen >> 4 is IP_VERSION_4);
|
|
|
|
//
|
|
// These defines depend upon a variable being named "uliTunnelId"
|
|
//
|
|
|
|
REMADDR = dwSrcAddr;
|
|
LOCALADDR = dwDestAddr;
|
|
|
|
//
|
|
// Bunch of checks to make sure the packet and the handler
|
|
// are telling us the same thing
|
|
//
|
|
|
|
RtAssert(pOutHeader->dwSrc is dwSrcAddr);
|
|
RtAssert(pOutHeader->dwDest is dwDestAddr);
|
|
|
|
//
|
|
// Get a pointer to the inside header
|
|
//
|
|
|
|
ulOutHdrLen = LengthOfIPHeader(pOutHeader);
|
|
|
|
pInHeader = (IP_HEADER UNALIGNED *)((PBYTE)pOutHeader + ulOutHdrLen);
|
|
|
|
#if DBG
|
|
|
|
//
|
|
// The size of the inner data must be total bytes - outer header
|
|
//
|
|
|
|
ulDataLen = ntohs(pInHeader->wLength);
|
|
|
|
RtAssert((ulDataLen + ulOutHdrLen) is uiTotalLen);
|
|
|
|
//
|
|
// The outer header should also give a good length
|
|
//
|
|
|
|
ulDataLen = ntohs(pOutHeader->wLength);
|
|
|
|
//
|
|
// Data length and bytes available must match
|
|
//
|
|
|
|
RtAssert(ulDataLen is uiTotalLen);
|
|
|
|
#endif
|
|
|
|
//
|
|
// Find the TUNNEL. We need to acquire the tunnel list lock
|
|
//
|
|
|
|
EnterReaderAtDpcLevel(&g_rwlTunnelLock);
|
|
|
|
pTunnel = FindTunnel(&uliTunnelId);
|
|
|
|
ExitReaderFromDpcLevel(&g_rwlTunnelLock);
|
|
|
|
if(pTunnel is NULL)
|
|
{
|
|
Trace(RCV, WARN,
|
|
("TdixReceiveIpIp: Couldnt find tunnel for %d.%d.%d.%d/%d.%d.%d.%d\n",
|
|
PRINT_IPADDR(REMADDR),
|
|
PRINT_IPADDR(LOCALADDR)));
|
|
|
|
//
|
|
// Could not find a matching tunnel
|
|
//
|
|
|
|
TraceLeave(RCV, "TdixReceiveIpIp");
|
|
|
|
//
|
|
// Return a code that will cause IP to send the right ICMP message
|
|
//
|
|
|
|
return IP_DEST_PROT_UNREACHABLE;;
|
|
}
|
|
|
|
//
|
|
// Ok, so we have the tunnel and it is ref counted and locked
|
|
//
|
|
|
|
//
|
|
// The number of octets received
|
|
//
|
|
|
|
pTunnel->ulInOctets += ulBytesAvailable;
|
|
|
|
//
|
|
// Check the actual (inside) destination
|
|
//
|
|
|
|
if(IsUnicastAddr(pInHeader->dwDest))
|
|
{
|
|
//
|
|
// TODO: should we check to see that the address is not 0.0.0.0?
|
|
//
|
|
|
|
pTunnel->ulInUniPkts++;
|
|
|
|
bNonUnicast = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pTunnel->ulInNonUniPkts++;
|
|
|
|
if(IsClassEAddr(pInHeader->dwDest))
|
|
{
|
|
//
|
|
// Bad address - throw it away
|
|
//
|
|
|
|
pTunnel->ulInErrors++;
|
|
|
|
//
|
|
// Releaselock, free buffer chain
|
|
//
|
|
|
|
}
|
|
|
|
bNonUnicast = TRUE;
|
|
}
|
|
|
|
//
|
|
// If the tunnel is non operational yet we are getting packets, means
|
|
// it probably should be made operational
|
|
//
|
|
|
|
RtAssert(pTunnel->dwOperState is MIB_IF_OPER_STATUS_OPERATIONAL);
|
|
|
|
if((pTunnel->dwAdminState isnot MIB_IF_ADMIN_STATUS_UP) or
|
|
(pTunnel->dwOperState isnot MIB_IF_OPER_STATUS_OPERATIONAL))
|
|
{
|
|
Trace(RCV, WARN,
|
|
("TdixReceiveIpIp: Tunnel %x is not up\n",
|
|
pTunnel));
|
|
|
|
pTunnel->ulInDiscards++;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
|
|
|
|
DereferenceTunnel(pTunnel);
|
|
|
|
TraceLeave(RCV, "TdixReceiveIpIp");
|
|
|
|
return STATUS_DATA_NOT_ACCEPTED;
|
|
}
|
|
|
|
//
|
|
// Allocate a transfer context
|
|
//
|
|
|
|
pXferCtxt = AllocateTransferContext();
|
|
|
|
if(pXferCtxt is NULL)
|
|
{
|
|
Trace(RCV, ERROR,
|
|
("TdixReceiveIpIp: Couldnt allocate transfer context\n"));
|
|
|
|
//
|
|
// Could not allocate context, free the data, unlock and deref
|
|
// the tunnel
|
|
//
|
|
|
|
pTunnel->ulInDiscards++;
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
|
|
|
|
DereferenceTunnel(pTunnel);
|
|
|
|
TraceLeave(RCV, "TdixReceiveIpIp");
|
|
|
|
return STATUS_DATA_NOT_ACCEPTED;
|
|
}
|
|
|
|
//
|
|
// Ok, all statistics are done.
|
|
// Release the lock on the tunnel
|
|
//
|
|
|
|
RtReleaseSpinLockFromDpcLevel(&(pTunnel->rlLock));
|
|
|
|
|
|
//
|
|
// Fill in the read-datagram context with the information that won't
|
|
// otherwise be available in the completion routine.
|
|
//
|
|
|
|
pXferCtxt->pTunnel = pTunnel;
|
|
pXferCtxt->pRcvBuf = pRcvBuf;
|
|
pXferCtxt->uiTotalLen = uiTotalLen;
|
|
pXferCtxt->ulProtoOffset = ulOutHdrLen;
|
|
|
|
|
|
//
|
|
// The data starts at pInHeader
|
|
// We indicate the only the first buffer to IP which means
|
|
// (ulFirstBufLen - outer header length) bytes
|
|
// The total data is the (ulTotalLen - outer header)
|
|
// We associate a TRANSFER_CONTEXT with this indication,
|
|
// The Protocol Offset is just our outer header
|
|
//
|
|
|
|
g_pfnIPRcv(pTunnel->pvIpContext,
|
|
pInHeader,
|
|
ulFirstBufLen - ulOutHdrLen,
|
|
ulTotalLen - ulOutHdrLen,
|
|
pXferCtxt,
|
|
ulOutHdrLen,
|
|
bNonUnicast);
|
|
|
|
//
|
|
// Deref the tunnel (finally)
|
|
//
|
|
|
|
DereferenceTunnel(pTunnel);
|
|
|
|
TraceLeave(RCV, "TdixReceiveIpIp");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
IpIpTransferData(
|
|
PVOID pvContext,
|
|
NDIS_HANDLE nhMacContext,
|
|
UINT uiProtoOffset,
|
|
UINT uiTransferOffset,
|
|
UINT uiTransferLength,
|
|
PNDIS_PACKET pnpPacket,
|
|
PUINT puiTransferred
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
|
|
Locks
|
|
|
|
|
|
Arguments
|
|
|
|
|
|
Return Value
|
|
|
|
NO_ERROR
|
|
|
|
--*/
|
|
|
|
{
|
|
PTRANSFER_CONTEXT pXferCtxt;
|
|
|
|
TraceEnter(SEND, "IpIpTransferData");
|
|
|
|
pXferCtxt = (PTRANSFER_CONTEXT)nhMacContext;
|
|
|
|
RtAssert(pXferCtxt->pTunnel is pvContext);
|
|
RtAssert(pXferCtxt->ulProtoOffset is uiProtoOffset);
|
|
|
|
//
|
|
// Should not be asking to transfer more than was indicated
|
|
// Since the transfer will start at and offset of
|
|
// uiProtoOffset + uiTransferOffset, the following should hold
|
|
//
|
|
|
|
RtAssert((pXferContext->uiTotalLen - uiProtoOffset - uiTransferOffset) >=
|
|
uiTransferLength);
|
|
|
|
//
|
|
// Copy the data from the RCV buffer to the given NDIS_BUFFER
|
|
//
|
|
|
|
*puiTransferred = CopyRcvBufferToNdisBuffer(pXferCtxt->pRcvBuf,
|
|
pnbFirstBuffer,
|
|
uiTransferLength,
|
|
uiProtoOffset + uiTransferOffset,
|
|
uiTransferOffset);
|
|
|
|
|
|
TraceLeave(SEND, "IpIpTransferData");
|
|
|
|
return NDIS_STATUS_PENDING;
|
|
}
|
|
|
|
|
|
uint
|
|
CopyRcvBufferToNdisBuffer(
|
|
IN IPRcvBuf *pRcvBuffer,
|
|
IN OUT PNDIS_BUFFER pnbNdisBuffer,
|
|
IN uint Size,
|
|
IN uint RcvBufferOffset,
|
|
IN uint NdisBufferOffset
|
|
)
|
|
{
|
|
uint TotalBytesCopied = 0; // Bytes we've copied so far.
|
|
uint BytesCopied = 0; // Bytes copied out of each buffer.
|
|
uint DestSize, RcvSize; // Size left in current destination and
|
|
// recv. buffers, respectively.
|
|
uint BytesToCopy; // How many bytes to copy this time.
|
|
NTSTATUS Status;
|
|
|
|
|
|
RtAssert(RcvBuf != NULL);
|
|
|
|
RtAssert(RcvOffset <= RcvBuf->ipr_size);
|
|
|
|
//
|
|
// The destination buffer can be NULL - this is valid, if odd.
|
|
//
|
|
|
|
if(pnbDestBuf != NULL)
|
|
{
|
|
}
|
|
|
|
RcvSize = RcvBuf->ipr_size - RcvOffset;
|
|
DestSize = NdisBufferLength(DestBuf);
|
|
|
|
if (Size < DestSize)
|
|
{
|
|
DestSize = Size;
|
|
}
|
|
|
|
do
|
|
{
|
|
//
|
|
// Compute the amount to copy, and then copy from the
|
|
// appropriate offsets.
|
|
|
|
BytesToCopy = MIN(DestSize, RcvSize);
|
|
|
|
Status = TdiCopyBufferToMdl(RcvBuf->ipr_buffer,
|
|
RcvOffset,
|
|
BytesToCopy,
|
|
DestBuf,
|
|
DestOffset,
|
|
&BytesCopied);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
|
|
RtAssert(BytesCopied == BytesToCopy);
|
|
|
|
TotalBytesCopied += BytesCopied;
|
|
DestSize -= BytesCopied;
|
|
DestOffset += BytesCopied;
|
|
RcvSize -= BytesToCopy;
|
|
|
|
if (!RcvSize)
|
|
{
|
|
//
|
|
// Exhausted this buffer.
|
|
|
|
RcvBuf = RcvBuf->ipr_next;
|
|
|
|
//
|
|
// If we have another one, use it.
|
|
//
|
|
|
|
if (RcvBuf != NULL)
|
|
{
|
|
RcvOffset = 0;
|
|
RcvSize = RcvBuf->ipr_size;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Buffer not exhausted, update offset.
|
|
//
|
|
|
|
RcvOffset += BytesToCopy;
|
|
}
|
|
|
|
}while (DestSize);
|
|
|
|
return TotalBytesCopied;
|
|
}
|