reactos/drivers/network/tcpip/ip/network/transmit.c
Victor Perevertkin 1734f29721 [IP][LWIP][TCPIP] Move ip and lwip libraries to drivers/network/tcpip
These libraries are used only inside tcpip.sys driver so move them close
to it.
2023-02-01 02:31:14 +03:00

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 */