mirror of
https://github.com/reactos/reactos.git
synced 2024-09-10 12:54:51 +00:00
![Amine Khaldi](/assets/img/avatar_default.png)
* Create a branch for some evul shell experiments. svn path=/branches/shell-experiments/; revision=61927
248 lines
7.3 KiB
C
248 lines
7.3 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS TCP/IP protocol driver
|
|
* FILE: network/transmit.c
|
|
* PURPOSE: Internet Protocol transmit routines
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* REVISIONS:
|
|
* CSH 01/08-2000 Created
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
BOOLEAN PrepareNextFragment(PIPFRAGMENT_CONTEXT IFC);
|
|
NTSTATUS IPSendFragment(PNDIS_PACKET NdisPacket,
|
|
PNEIGHBOR_CACHE_ENTRY NCE,
|
|
PIPFRAGMENT_CONTEXT IFC);
|
|
|
|
VOID IPSendComplete
|
|
(PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS NdisStatus)
|
|
/*
|
|
* FUNCTION: IP datagram fragment send completion handler
|
|
* ARGUMENTS:
|
|
* Context = Pointer to context information (IP_INTERFACE)
|
|
* Packet = Pointer to NDIS packet that was sent
|
|
* NdisStatus = NDIS status of operation
|
|
* NOTES:
|
|
* This routine is called when an IP datagram fragment has been sent
|
|
*/
|
|
{
|
|
PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)Context;
|
|
|
|
TI_DbgPrint
|
|
(MAX_TRACE,
|
|
("Called. Context (0x%X) NdisPacket (0x%X) NdisStatus (0x%X)\n",
|
|
Context, NdisPacket, NdisStatus));
|
|
|
|
IFC->Status = NdisStatus;
|
|
KeSetEvent(&IFC->Event, 0, FALSE);
|
|
}
|
|
|
|
NTSTATUS IPSendFragment(
|
|
PNDIS_PACKET NdisPacket,
|
|
PNEIGHBOR_CACHE_ENTRY NCE,
|
|
PIPFRAGMENT_CONTEXT IFC)
|
|
/*
|
|
* FUNCTION: Sends an IP datagram fragment to a neighbor
|
|
* ARGUMENTS:
|
|
* NdisPacket = Pointer to an NDIS packet containing fragment
|
|
* NCE = Pointer to NCE for first hop to destination
|
|
* RETURNS:
|
|
* Status of operation
|
|
* NOTES:
|
|
* Lowest level IP send routine
|
|
*/
|
|
{
|
|
TI_DbgPrint(MAX_TRACE, ("Called. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket, NCE));
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State));
|
|
return NBQueuePacket(NCE, NdisPacket, IPSendComplete, IFC);
|
|
}
|
|
|
|
BOOLEAN PrepareNextFragment(
|
|
PIPFRAGMENT_CONTEXT IFC)
|
|
/*
|
|
* FUNCTION: Prepares the next fragment of an IP datagram for transmission
|
|
* ARGUMENTS:
|
|
* IFC = Pointer to IP fragment context
|
|
* RETURNS:
|
|
* TRUE if a fragment was prepared for transmission, FALSE if
|
|
* there are no more fragments to send
|
|
*/
|
|
{
|
|
UINT MaxData;
|
|
UINT DataSize;
|
|
PIPv4_HEADER Header;
|
|
BOOLEAN MoreFragments;
|
|
USHORT FragOfs;
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Called. IFC (0x%X)\n", IFC));
|
|
|
|
if (IFC->BytesLeft > 0) {
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n"));
|
|
|
|
MaxData = IFC->PathMTU - IFC->HeaderSize;
|
|
/* Make fragment a multiplum of 64bit */
|
|
MaxData -= MaxData % 8;
|
|
if (IFC->BytesLeft > MaxData) {
|
|
DataSize = MaxData;
|
|
MoreFragments = TRUE;
|
|
} else {
|
|
DataSize = IFC->BytesLeft;
|
|
MoreFragments = FALSE;
|
|
}
|
|
|
|
TI_DbgPrint(MID_TRACE,("Copying data from %x to %x (%d)\n",
|
|
IFC->DatagramData, IFC->Data, DataSize));
|
|
|
|
RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize); // SAFE
|
|
|
|
/* Fragment offset is in 8 byte blocks */
|
|
FragOfs = (USHORT)(IFC->Position / 8);
|
|
|
|
if (MoreFragments)
|
|
FragOfs |= IPv4_MF_MASK;
|
|
else
|
|
FragOfs &= ~IPv4_MF_MASK;
|
|
|
|
Header = IFC->Header;
|
|
Header->FlagsFragOfs = WH2N(FragOfs);
|
|
Header->TotalLength = WH2N((USHORT)(DataSize + IFC->HeaderSize));
|
|
|
|
/* FIXME: Handle options */
|
|
|
|
/* Calculate checksum of IP header */
|
|
Header->Checksum = 0;
|
|
Header->Checksum = (USHORT)IPv4Checksum(Header, IFC->HeaderSize, 0);
|
|
TI_DbgPrint(MID_TRACE,("IP Check: %x\n", Header->Checksum));
|
|
|
|
/* Update pointers */
|
|
IFC->DatagramData = (PVOID)((ULONG_PTR)IFC->DatagramData + DataSize);
|
|
IFC->Position += DataSize;
|
|
IFC->BytesLeft -= DataSize;
|
|
|
|
return TRUE;
|
|
} else {
|
|
TI_DbgPrint(MAX_TRACE, ("No more fragments.\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
NTSTATUS SendFragments(
|
|
PIP_PACKET IPPacket,
|
|
PNEIGHBOR_CACHE_ENTRY NCE,
|
|
UINT PathMTU)
|
|
/*
|
|
* FUNCTION: Fragments and sends the first fragment of an IP datagram
|
|
* ARGUMENTS:
|
|
* IPPacket = Pointer to an IP packet
|
|
* NCE = Pointer to NCE for first hop to destination
|
|
* PathMTU = Size of Maximum Transmission Unit of path
|
|
* RETURNS:
|
|
* Status of operation
|
|
* NOTES:
|
|
* IP datagram is larger than PathMTU when this is called
|
|
*/
|
|
{
|
|
PIPFRAGMENT_CONTEXT IFC;
|
|
NDIS_STATUS NdisStatus;
|
|
PVOID Data;
|
|
UINT BufferSize = PathMTU, InSize;
|
|
PCHAR InData;
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
|
|
IPPacket, NCE, PathMTU));
|
|
|
|
/* Make a smaller buffer if we will only send one fragment */
|
|
GetDataPtr( IPPacket->NdisPacket, IPPacket->Position, &InData, &InSize );
|
|
if( InSize < BufferSize ) BufferSize = InSize;
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Fragment buffer is %d bytes\n", BufferSize));
|
|
|
|
IFC = ExAllocatePoolWithTag(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT), IFC_TAG);
|
|
if (IFC == NULL)
|
|
{
|
|
IPPacket->Free(IPPacket);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Allocate NDIS packet */
|
|
NdisStatus = AllocatePacketWithBuffer
|
|
( &IFC->NdisPacket, NULL, BufferSize );
|
|
|
|
if( !NT_SUCCESS(NdisStatus) ) {
|
|
IPPacket->Free(IPPacket);
|
|
ExFreePoolWithTag( IFC, IFC_TAG );
|
|
return NdisStatus;
|
|
}
|
|
|
|
GetDataPtr( IFC->NdisPacket, 0, (PCHAR *)&Data, &InSize );
|
|
|
|
IFC->Header = ((PCHAR)Data);
|
|
IFC->Datagram = IPPacket->NdisPacket;
|
|
IFC->DatagramData = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
|
|
IFC->HeaderSize = IPPacket->HeaderSize;
|
|
IFC->PathMTU = PathMTU;
|
|
IFC->NCE = NCE;
|
|
IFC->Position = 0;
|
|
IFC->BytesLeft = IPPacket->TotalSize - IPPacket->HeaderSize;
|
|
IFC->Data = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize);
|
|
KeInitializeEvent(&IFC->Event, NotificationEvent, FALSE);
|
|
|
|
TI_DbgPrint(MID_TRACE,("Copying header from %x to %x (%d)\n",
|
|
IPPacket->Header, IFC->Header,
|
|
IPPacket->HeaderSize));
|
|
|
|
RtlCopyMemory( IFC->Header, IPPacket->Header, IPPacket->HeaderSize );
|
|
|
|
while (PrepareNextFragment(IFC))
|
|
{
|
|
NdisStatus = IPSendFragment(IFC->NdisPacket, NCE, IFC);
|
|
if (NT_SUCCESS(NdisStatus))
|
|
{
|
|
KeWaitForSingleObject(&IFC->Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
NdisStatus = IFC->Status;
|
|
}
|
|
|
|
if (!NT_SUCCESS(NdisStatus))
|
|
break;
|
|
}
|
|
|
|
FreeNdisPacket(IFC->NdisPacket);
|
|
ExFreePoolWithTag(IFC, IFC_TAG);
|
|
IPPacket->Free(IPPacket);
|
|
|
|
return NdisStatus;
|
|
}
|
|
|
|
NTSTATUS IPSendDatagram(PIP_PACKET IPPacket, PNEIGHBOR_CACHE_ENTRY NCE)
|
|
/*
|
|
* FUNCTION: Sends an IP datagram to a remote address
|
|
* ARGUMENTS:
|
|
* IPPacket = Pointer to an IP packet
|
|
* RCN = Pointer to route cache node
|
|
* RETURNS:
|
|
* Status of operation
|
|
* NOTES:
|
|
* This is the highest level IP send routine. It possibly breaks the packet
|
|
* into two or more fragments before passing it on to the next lower level
|
|
* send routine (IPSendFragment)
|
|
*/
|
|
{
|
|
TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket, NCE));
|
|
|
|
DISPLAY_IP_PACKET(IPPacket);
|
|
|
|
/* Fetch path MTU now, because it may change */
|
|
TI_DbgPrint(MID_TRACE,("PathMTU: %d\n", NCE->Interface->MTU));
|
|
|
|
return SendFragments(IPPacket, NCE, NCE->Interface->MTU);
|
|
}
|
|
|
|
/* EOF */
|