⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 receive.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -