📄 receive.c
字号:
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: network/receive.c
* PURPOSE: Internet Protocol receive routines
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* NOTES: The IP datagram reassembly algorithm is taken from
* from RFC 815
* REVISIONS:
* CSH 01/08-2000 Created
*/
#include "precomp.h"
LIST_ENTRY ReassemblyListHead;
KSPIN_LOCK ReassemblyListLock;
NPAGED_LOOKASIDE_LIST IPDRList;
NPAGED_LOOKASIDE_LIST IPFragmentList;
NPAGED_LOOKASIDE_LIST IPHoleList;
VOID ReflectPacketComplete(
PVOID Context,
PNDIS_PACKET Packet,
NDIS_STATUS Status ) {
}
PIPDATAGRAM_HOLE CreateHoleDescriptor(
ULONG First,
ULONG Last)
/*
* FUNCTION: Returns a pointer to a IP datagram hole descriptor
* ARGUMENTS:
* First = Offset of first octet of the hole
* Last = Offset of last octet of the hole
* RETURNS:
* Pointer to descriptor, NULL if there was not enough free
* resources
*/
{
PIPDATAGRAM_HOLE Hole;
TI_DbgPrint(DEBUG_IP, ("Called. First (%d) Last (%d).\n", First, Last));
Hole = TcpipAllocateFromNPagedLookasideList(&IPHoleList);
if (!Hole) {
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return NULL;
}
Hole->First = First;
Hole->Last = Last;
TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));
return Hole;
}
VOID FreeIPDR(
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Frees an IP datagram reassembly structure
* ARGUMENTS:
* IPDR = Pointer to IP datagram reassembly structure
*/
{
PLIST_ENTRY CurrentEntry;
PLIST_ENTRY NextEntry;
PIPDATAGRAM_HOLE CurrentH;
PIP_FRAGMENT CurrentF;
TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));
/* Free all descriptors */
CurrentEntry = IPDR->HoleListHead.Flink;
while (CurrentEntry != &IPDR->HoleListHead) {
NextEntry = CurrentEntry->Flink;
CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
/* Unlink it from the list */
RemoveEntryList(CurrentEntry);
TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));
/* And free the hole descriptor */
TcpipFreeToNPagedLookasideList(&IPHoleList, CurrentH);
CurrentEntry = NextEntry;
}
/* Free all fragments */
CurrentEntry = IPDR->FragmentListHead.Flink;
while (CurrentEntry != &IPDR->FragmentListHead) {
NextEntry = CurrentEntry->Flink;
CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
/* Unlink it from the list */
RemoveEntryList(CurrentEntry);
TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data));
/* Free the fragment data buffer */
exFreePool(CurrentF->Data);
TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
/* And free the fragment descriptor */
TcpipFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
CurrentEntry = NextEntry;
}
TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
TcpipFreeToNPagedLookasideList(&IPDRList, IPDR);
}
VOID RemoveIPDR(
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Removes an IP datagram reassembly structure from the global list
* ARGUMENTS:
* IPDR = Pointer to IP datagram reassembly structure
*/
{
KIRQL OldIrql;
TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
RemoveEntryList(&IPDR->ListEntry);
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
}
PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
PIP_PACKET IPPacket)
/*
* FUNCTION: Returns a pointer to an IP datagram reassembly structure
* ARGUMENTS:
* IPPacket = Pointer to IP packet
* NOTES:
* A datagram is identified by four paramters, which are
* Source and destination address, protocol number and
* identification number
*/
{
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
PIPDATAGRAM_REASSEMBLY Current;
PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
/* FIXME: Assume IPv4 */
CurrentEntry = ReassemblyListHead.Flink;
while (CurrentEntry != &ReassemblyListHead) {
Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
(Header->Id == Current->Id) &&
(Header->Protocol == Current->Protocol) &&
(AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
return Current;
}
CurrentEntry = CurrentEntry->Flink;
}
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
return NULL;
}
PIP_PACKET ReassembleDatagram(
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Reassembles an IP datagram
* ARGUMENTS:
* IPDR = Pointer to IP datagram reassembly structure
* NOTES:
* This routine concatenates fragments into a complete IP datagram.
* The lock is held when this routine is called
* RETURNS:
* Pointer to IP packet, NULL if there was not enough free resources
* NOTES:
* At this point, header is expected to point to the IP header
*/
{
PIP_PACKET IPPacket;
PLIST_ENTRY CurrentEntry;
PIP_FRAGMENT Current;
PVOID Data;
TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
TI_DbgPrint(DEBUG_IP, ("IPDR->HeaderSize = %d\n", IPDR->HeaderSize));
TI_DbgPrint(DEBUG_IP, ("IPDR->DataSize = %d\n", IPDR->DataSize));
TI_DbgPrint(DEBUG_IP, ("Fragment header:\n"));
//OskitDumpBuffer((PCHAR)IPDR->IPv4Header, IPDR->HeaderSize);
/* FIXME: Assume IPv4 */
IPPacket = IPCreatePacket(IP_ADDRESS_V4);
if (!IPPacket)
return NULL;
IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
IPPacket->ContigSize = IPPacket->TotalSize;
IPPacket->HeaderSize = IPDR->HeaderSize;
/*IPPacket->Position = IPDR->HeaderSize;*/
RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
/* Allocate space for full IP datagram */
IPPacket->Header = exAllocatePool(NonPagedPool, IPPacket->TotalSize);
if (!IPPacket->Header) {
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
(*IPPacket->Free)(IPPacket);
return NULL;
}
/* Copy the header into the buffer */
RtlCopyMemory(IPPacket->Header, &IPDR->IPv4Header, IPDR->HeaderSize);
Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
IPPacket->Data = Data;
/* Copy data from all fragments into buffer */
CurrentEntry = IPDR->FragmentListHead.Flink;
while (CurrentEntry != &IPDR->FragmentListHead) {
Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",
Current->Size, Data, Current->Offset));
/* Copy fragment data to the destination buffer at the correct offset */
RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset),
Current->Data,
Current->Size);
//OskitDumpBuffer( Data, Current->Offset + Current->Size );
CurrentEntry = CurrentEntry->Flink;
}
return IPPacket;
}
__inline VOID Cleanup(
PKSPIN_LOCK Lock,
KIRQL OldIrql,
PIPDATAGRAM_REASSEMBLY IPDR,
PVOID Buffer OPTIONAL)
/*
* FUNCTION: Performs cleaning operations on errors
* ARGUMENTS:
* Lock = Pointer to spin lock to be released
* OldIrql = Value of IRQL when spin lock was acquired
* IPDR = Pointer to IP datagram reassembly structure to free
* Buffer = Optional pointer to a buffer to free
*/
{
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
TcpipReleaseSpinLock(Lock, OldIrql);
RemoveIPDR(IPDR);
FreeIPDR(IPDR);
if (Buffer)
exFreePool(Buffer);
}
VOID ProcessFragment(
PIP_INTERFACE IF,
PIP_PACKET IPPacket)
/*
* FUNCTION: Processes an IP datagram or fragment
* ARGUMENTS:
* IF = Pointer to IP interface packet was receive on
* IPPacket = Pointer to IP packet
* NOTES:
* This routine reassembles fragments and, if a whole datagram can
* be assembled, passes the datagram on to the IP protocol dispatcher
*/
{
KIRQL OldIrql;
PIPDATAGRAM_REASSEMBLY IPDR;
PLIST_ENTRY CurrentEntry;
PIPDATAGRAM_HOLE Hole, NewHole;
USHORT FragFirst;
USHORT FragLast;
BOOLEAN MoreFragments;
PIPv4_HEADER IPv4Header;
PIP_PACKET Datagram;
PIP_FRAGMENT Fragment;
/* FIXME: Assume IPv4 */
IPv4Header = (PIPv4_HEADER)IPPacket->Header;
/* Check if we already have an reassembly structure for this datagram */
IPDR = GetReassemblyInfo(IPPacket);
if (IPDR) {
TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
/* We have a reassembly structure */
TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
CurrentEntry = IPDR->HoleListHead.Flink;
Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -