Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.

This commit is contained in:
Colin Finck 2017-10-03 07:45:34 +00:00
parent b94e2d8ca0
commit c2c66aff7d
24198 changed files with 0 additions and 37285 deletions

View file

@ -0,0 +1,166 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: transport/tcp/accept.c
* PURPOSE: Transmission Control Protocol Listen/Accept code
* PROGRAMMERS: Art Yerkes (arty@users.sf.net)
* REVISIONS:
* arty 12/21/2004 Created
*/
#include "precomp.h"
#include "rosip.h"
extern NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
NTSTATUS TCPCheckPeerForAccept(PVOID Context,
PTDI_REQUEST_KERNEL Request)
{
struct tcp_pcb *newpcb = (struct tcp_pcb*)Context;
NTSTATUS Status;
PTDI_CONNECTION_INFORMATION WhoIsConnecting;
PTA_IP_ADDRESS RemoteAddress;
struct ip_addr ipaddr;
if (Request->RequestFlags & TDI_QUERY_ACCEPT)
DbgPrint("TDI_QUERY_ACCEPT NOT SUPPORTED!!!\n");
WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)Request->ReturnConnectionInformation;
RemoteAddress = (PTA_IP_ADDRESS)WhoIsConnecting->RemoteAddress;
RemoteAddress->TAAddressCount = 1;
RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
Status = TCPTranslateError(LibTCPGetPeerName(newpcb,
&ipaddr,
&RemoteAddress->Address[0].Address[0].sin_port));
RemoteAddress->Address[0].Address[0].in_addr = ipaddr.addr;
return Status;
}
/* This listen is on a socket we keep as internal. That socket has the same
* lifetime as the address file */
NTSTATUS TCPListen(PCONNECTION_ENDPOINT Connection, UINT Backlog)
{
NTSTATUS Status = STATUS_SUCCESS;
struct ip_addr AddressToBind;
KIRQL OldIrql;
TA_IP_ADDRESS LocalAddress;
ASSERT(Connection);
LockObject(Connection, &OldIrql);
ASSERT_KM_POINTER(Connection->AddressFile);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Called\n"));
TI_DbgPrint(DEBUG_TCP, ("Connection->SocketContext %x\n",
Connection->SocketContext));
AddressToBind.addr = Connection->AddressFile->Address.Address.IPv4Address;
Status = TCPTranslateError(LibTCPBind(Connection,
&AddressToBind,
Connection->AddressFile->Port));
if (NT_SUCCESS(Status))
{
/* Check if we had an unspecified port */
if (!Connection->AddressFile->Port)
{
/* We did, so we need to copy back the port */
Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
if (NT_SUCCESS(Status))
{
/* Allocate the port in the port bitmap */
Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
/* This should never fail */
ASSERT(Connection->AddressFile->Port != 0xFFFF);
}
}
}
if (NT_SUCCESS(Status))
{
Connection->SocketContext = LibTCPListen(Connection, Backlog);
if (!Connection->SocketContext)
Status = STATUS_UNSUCCESSFUL;
}
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Leaving. Status = %x\n", Status));
return Status;
}
BOOLEAN TCPAbortListenForSocket
( PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection)
{
PLIST_ENTRY ListEntry;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
BOOLEAN Found = FALSE;
LockObject(Listener, &OldIrql);
ListEntry = Listener->ListenRequest.Flink;
while (ListEntry != &Listener->ListenRequest)
{
Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
if (Bucket->AssociatedEndpoint == Connection)
{
DereferenceObject(Bucket->AssociatedEndpoint);
RemoveEntryList( &Bucket->Entry );
ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
Found = TRUE;
break;
}
ListEntry = ListEntry->Flink;
}
UnlockObject(Listener, OldIrql);
return Found;
}
NTSTATUS TCPAccept ( PTDI_REQUEST Request,
PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context )
{
NTSTATUS Status;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
LockObject(Listener, &OldIrql);
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (Bucket)
{
Bucket->AssociatedEndpoint = Connection;
ReferenceObject(Bucket->AssociatedEndpoint);
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
Status = STATUS_PENDING;
}
else
Status = STATUS_NO_MEMORY;
UnlockObject(Listener, OldIrql);
return Status;
}

View file

@ -0,0 +1,499 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: transport/tcp/event.c
* PURPOSE: Transmission Control Protocol
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
*/
#include "precomp.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
#include "rosip.h"
extern NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
static
VOID
BucketCompletionWorker(PVOID Context)
{
PTDI_BUCKET Bucket = (PTDI_BUCKET)Context;
PTCP_COMPLETION_ROUTINE Complete;
Complete = (PTCP_COMPLETION_ROUTINE)Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
DereferenceObject(Bucket->AssociatedEndpoint);
ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
}
VOID
CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous)
{
ReferenceObject(Connection);
Bucket->AssociatedEndpoint = Connection;
if (Synchronous)
{
BucketCompletionWorker(Bucket);
}
else
{
ChewCreate(BucketCompletionWorker, Bucket);
}
}
VOID
FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
if (interlocked)
{
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
TI_DbgPrint(DEBUG_TCP,
("Completing Receive request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
}
else
{
while (!IsListEmpty(&Connection->ReceiveRequest))
{
Entry = RemoveHeadList(&Connection->ReceiveRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
DereferenceObject(Connection);
}
VOID
FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
if (interlocked)
{
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
}
else
{
while (!IsListEmpty(&Connection->SendRequest))
{
Entry = RemoveHeadList(&Connection->SendRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
DereferenceObject(Connection);
}
VOID
FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
if (interlocked)
{
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ShutdownRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
}
else
{
while (!IsListEmpty(&Connection->ShutdownRequest))
{
Entry = RemoveHeadList(&Connection->ShutdownRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
DereferenceObject(Connection);
}
VOID
FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
}
VOID
FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
DereferenceObject(Bucket->AssociatedEndpoint);
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
}
VOID
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
{
ReferenceObject(Connection);
// flush receive queue
FlushReceiveQueue(Connection, Status, TRUE);
/* We completed the reads successfully but we need to return failure now */
if (Status == STATUS_SUCCESS)
{
Status = STATUS_FILE_CLOSED;
}
// flush listen queue
FlushListenQueue(Connection, Status);
// flush send queue
FlushSendQueue(Connection, Status, TRUE);
// flush connect queue
FlushConnectQueue(Connection, Status);
// flush shutdown queue
FlushShutdownQueue(Connection, Status, TRUE);
DereferenceObject(Connection);
}
VOID
TCPFinEventHandler(void *arg, const err_t err)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg, LastConnection;
const NTSTATUS Status = TCPTranslateError(err);
KIRQL OldIrql;
ASSERT(Connection->SocketContext == NULL);
ASSERT(Connection->AddressFile);
ASSERT(err != ERR_OK);
/* Complete all outstanding requests now */
FlushAllQueues(Connection, Status);
LockObject(Connection, &OldIrql);
LockObjectAtDpcLevel(Connection->AddressFile);
/* Unlink this connection from the address file */
if (Connection->AddressFile->Connection == Connection)
{
Connection->AddressFile->Connection = Connection->Next;
DereferenceObject(Connection);
}
else if (Connection->AddressFile->Listener == Connection)
{
Connection->AddressFile->Listener = NULL;
DereferenceObject(Connection);
}
else
{
LastConnection = Connection->AddressFile->Connection;
while (LastConnection->Next != Connection && LastConnection->Next != NULL)
LastConnection = LastConnection->Next;
if (LastConnection->Next == Connection)
{
LastConnection->Next = Connection->Next;
DereferenceObject(Connection);
}
}
UnlockObjectFromDpcLevel(Connection->AddressFile);
/* Remove the address file from this connection */
DereferenceObject(Connection->AddressFile);
Connection->AddressFile = NULL;
UnlockObject(Connection, OldIrql);
}
VOID
TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
KIRQL OldIrql;
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
{
PIO_STACK_LOCATION IrpSp;
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
TI_DbgPrint(DEBUG_TCP,("[IP, TCPAcceptEventHandler] Getting the socket\n"));
Status = TCPCheckPeerForAccept(newpcb,
(PTDI_REQUEST_KERNEL)&IrpSp->Parameters);
TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n", Status));
Bucket->Status = Status;
Bucket->Information = 0;
if (Status == STATUS_SUCCESS)
{
LockObject(Bucket->AssociatedEndpoint, &OldIrql);
/* sanity assert...this should never be in anything else but a CLOSED state */
ASSERT( ((PTCP_PCB)Bucket->AssociatedEndpoint->SocketContext)->state == CLOSED );
/* free socket context created in FileOpenConnection, as we're using a new one */
LibTCPClose(Bucket->AssociatedEndpoint, TRUE, FALSE);
/* free previously created socket context (we don't use it, we use newpcb) */
Bucket->AssociatedEndpoint->SocketContext = newpcb;
LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint);
UnlockObject(Bucket->AssociatedEndpoint, OldIrql);
}
DereferenceObject(Bucket->AssociatedEndpoint);
CompleteBucket(Connection, Bucket, FALSE);
if (Status == STATUS_SUCCESS)
{
break;
}
}
DereferenceObject(Connection);
}
VOID
TCPSendEventHandler(void *arg, const u16_t space)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
PMDL Mdl;
ULONG BytesSent;
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
{
UINT SendLen = 0;
PVOID SendBuffer = 0;
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
TI_DbgPrint(DEBUG_TCP,
("Getting the user buffer from %x\n", Mdl));
NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
TI_DbgPrint(DEBUG_TCP,
("Writing %d bytes to %x\n", SendLen, SendBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
Status = TCPTranslateError(LibTCPSend(Connection,
SendBuffer,
SendLen, &BytesSent, TRUE));
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", BytesSent));
if( Status == STATUS_PENDING )
{
ExInterlockedInsertHeadList(&Connection->SendRequest,
&Bucket->Entry,
&Connection->Lock);
break;
}
else
{
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? BytesSent : 0;
CompleteBucket(Connection, Bucket, FALSE);
}
}
// If we completed all outstanding send requests then finish all pending shutdown requests,
// cancel the timer and dereference the connection
if (IsListEmpty(&Connection->SendRequest))
{
FlushShutdownQueue(Connection, STATUS_SUCCESS, FALSE);
if (KeCancelTimer(&Connection->DisconnectTimer))
{
DereferenceObject(Connection);
}
}
DereferenceObject(Connection);
}
VOID
TCPRecvEventHandler(void *arg)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
PMDL Mdl;
UINT Received;
UINT RecvLen;
PUCHAR RecvBuffer;
NTSTATUS Status;
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
Status = LibTCPGetDataFromConnectionQueue(Connection, RecvBuffer, RecvLen, &Received);
if (Status == STATUS_PENDING)
{
ExInterlockedInsertHeadList(&Connection->ReceiveRequest,
&Bucket->Entry,
&Connection->Lock);
break;
}
Bucket->Status = Status;
Bucket->Information = Received;
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
}
VOID
TCPConnectEventHandler(void *arg, const err_t err)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ReferenceObject(Connection);
while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = TCPTranslateError(err);
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
DereferenceObject(Connection);
}

View file

@ -0,0 +1,172 @@
#include "precomp.h"
#include "lwip/pbuf.h"
#include "lwip/netifapi.h"
#include "lwip/ip.h"
#include "lwip/api.h"
#include "lwip/tcpip.h"
err_t
TCPSendDataCallback(struct netif *netif, struct pbuf *p, struct ip_addr *dest)
{
NDIS_STATUS NdisStatus;
PNEIGHBOR_CACHE_ENTRY NCE;
IP_PACKET Packet;
IP_ADDRESS RemoteAddress, LocalAddress;
PIPv4_HEADER Header;
ULONG Length;
ULONG TotalLength;
/* The caller frees the pbuf struct */
if (((*(u8_t*)p->payload) & 0xF0) == 0x40)
{
Header = p->payload;
LocalAddress.Type = IP_ADDRESS_V4;
LocalAddress.Address.IPv4Address = Header->SrcAddr;
RemoteAddress.Type = IP_ADDRESS_V4;
RemoteAddress.Address.IPv4Address = Header->DstAddr;
}
else
{
return ERR_IF;
}
IPInitializePacket(&Packet, LocalAddress.Type);
if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
{
return ERR_RTE;
}
NdisStatus = AllocatePacketWithBuffer(&Packet.NdisPacket, NULL, p->tot_len);
if (NdisStatus != NDIS_STATUS_SUCCESS)
{
return ERR_MEM;
}
GetDataPtr(Packet.NdisPacket, 0, (PCHAR*)&Packet.Header, &Packet.TotalSize);
Packet.MappedHeader = TRUE;
ASSERT(Packet.TotalSize == p->tot_len);
TotalLength = p->tot_len;
Length = 0;
while (Length < TotalLength)
{
ASSERT(p->len <= TotalLength - Length);
ASSERT(p->tot_len == TotalLength - Length);
RtlCopyMemory((PCHAR)Packet.Header + Length, p->payload, p->len);
Length += p->len;
p = p->next;
}
ASSERT(Length == TotalLength);
Packet.HeaderSize = sizeof(IPv4_HEADER);
Packet.TotalSize = TotalLength;
Packet.SrcAddr = LocalAddress;
Packet.DstAddr = RemoteAddress;
NdisStatus = IPSendDatagram(&Packet, NCE);
if (!NT_SUCCESS(NdisStatus))
return ERR_RTE;
return 0;
}
VOID
TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF)
{
#if 0
ULONG OperationalStatus;
GetInterfaceConnectionStatus(IF, &OperationalStatus);
if (OperationalStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
netif_set_link_up(IF->TCPContext);
else
netif_set_link_down(IF->TCPContext);
#endif
}
err_t
TCPInterfaceInit(struct netif *netif)
{
PIP_INTERFACE IF = netif->state;
netif->hwaddr_len = IF->AddressLength;
RtlCopyMemory(netif->hwaddr, IF->Address, netif->hwaddr_len);
netif->output = TCPSendDataCallback;
netif->mtu = IF->MTU;
netif->name[0] = 'e';
netif->name[1] = 'n';
netif->flags |= NETIF_FLAG_BROADCAST;
TCPUpdateInterfaceLinkStatus(IF);
TCPUpdateInterfaceIPInformation(IF);
return 0;
}
VOID
TCPRegisterInterface(PIP_INTERFACE IF)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
gw.addr = 0;
ipaddr.addr = 0;
netmask.addr = 0;
IF->TCPContext = netif_add(IF->TCPContext,
&ipaddr,
&netmask,
&gw,
IF,
TCPInterfaceInit,
tcpip_input);
}
VOID
TCPUnregisterInterface(PIP_INTERFACE IF)
{
netif_remove(IF->TCPContext);
}
VOID
TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF)
{
struct ip_addr ipaddr;
struct ip_addr netmask;
struct ip_addr gw;
gw.addr = 0;
GetInterfaceIPv4Address(IF,
ADE_UNICAST,
(PULONG)&ipaddr.addr);
GetInterfaceIPv4Address(IF,
ADE_ADDRMASK,
(PULONG)&netmask.addr);
netif_set_addr(IF->TCPContext, &ipaddr, &netmask, &gw);
if (ipaddr.addr != 0)
{
netif_set_up(IF->TCPContext);
netif_set_default(IF->TCPContext);
}
else
{
netif_set_down(IF->TCPContext);
}
}

View file

@ -0,0 +1,695 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: transport/tcp/tcp.c
* PURPOSE: Transmission Control Protocol
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* Art Yerkes (arty@users.sf.net)
* REVISIONS:
* CSH 01/08-2000 Created
* arty 12/21/2004 Added accept
*/
#include "precomp.h"
LONG TCP_IPIdentification = 0;
static BOOLEAN TCPInitialized = FALSE;
PORT_SET TCPPorts;
#include "lwip/pbuf.h"
#include "lwip/ip.h"
#include "lwip/init.h"
#include "lwip/arch.h"
#include "rosip.h"
NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
VOID NTAPI
DisconnectTimeoutDpc(PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext;
PLIST_ENTRY Entry;
PTDI_BUCKET Bucket;
LockObjectAtDpcLevel(Connection);
/* We timed out waiting for pending sends so force it to shutdown */
TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
while (!IsListEmpty(&Connection->SendRequest))
{
Entry = RemoveHeadList(&Connection->SendRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = STATUS_FILE_CLOSED;
CompleteBucket(Connection, Bucket, FALSE);
}
while (!IsListEmpty(&Connection->ShutdownRequest))
{
Entry = RemoveHeadList( &Connection->ShutdownRequest );
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = STATUS_TIMEOUT;
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
UnlockObjectFromDpcLevel(Connection);
DereferenceObject(Connection);
}
VOID ConnectionFree(PVOID Object)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object;
KIRQL OldIrql;
TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
RemoveEntryList(&Connection->ListEntry);
TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
}
PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext )
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)
ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT), CONN_ENDPT_TAG);
if (!Connection)
return Connection;
TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
/* Initialize spin lock that protects the connection endpoint file object */
KeInitializeSpinLock(&Connection->Lock);
InitializeListHead(&Connection->ConnectRequest);
InitializeListHead(&Connection->ListenRequest);
InitializeListHead(&Connection->ReceiveRequest);
InitializeListHead(&Connection->SendRequest);
InitializeListHead(&Connection->ShutdownRequest);
InitializeListHead(&Connection->PacketQueue);
/* Initialize disconnect timer */
KeInitializeTimer(&Connection->DisconnectTimer);
KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection);
/* Save client context pointer */
Connection->ClientContext = ClientContext;
Connection->RefCount = 1;
Connection->Free = ConnectionFree;
/* Add connection endpoint to global list */
ExInterlockedInsertTailList(&ConnectionEndpointListHead,
&Connection->ListEntry,
&ConnectionEndpointListLock);
return Connection;
}
NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
UINT Family, UINT Type, UINT Proto )
{
NTSTATUS Status;
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Called: Connection %x, Family %d, Type %d, "
"Proto %d, sizeof(CONNECTION_ENDPOINT) = %d\n",
Connection, Family, Type, Proto, sizeof(CONNECTION_ENDPOINT)));
Connection->SocketContext = LibTCPSocket(Connection);
if (Connection->SocketContext)
Status = STATUS_SUCCESS;
else
Status = STATUS_INSUFFICIENT_RESOURCES;
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Leaving. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection )
{
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
FlushAllQueues(Connection, STATUS_CANCELLED);
LibTCPClose(Connection, FALSE, TRUE);
UnlockObject(Connection, OldIrql);
DereferenceObject(Connection);
return STATUS_SUCCESS;
}
VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
/*
* FUNCTION: Receives and queues TCP data
* ARGUMENTS:
* IPPacket = Pointer to an IP packet that was received
* NOTES:
* This is the low level interface for receiving TCP data
*/
{
TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n",
IPPacket->TotalSize,
IPPacket->HeaderSize));
LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize);
}
NTSTATUS TCPStartup(VOID)
/*
* FUNCTION: Initializes the TCP subsystem
* RETURNS:
* Status of operation
*/
{
NTSTATUS Status;
Status = PortsStartup( &TCPPorts, 1, 0xfffe );
if (!NT_SUCCESS(Status))
{
return Status;
}
ExInitializeNPagedLookasideList(&TdiBucketLookasideList,
NULL,
NULL,
0,
sizeof(TDI_BUCKET),
TDI_BUCKET_TAG,
0);
/* Initialize our IP library */
LibIPInitialize();
/* Register this protocol with IP layer */
IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
TCPInitialized = TRUE;
return STATUS_SUCCESS;
}
NTSTATUS TCPShutdown(VOID)
/*
* FUNCTION: Shuts down the TCP subsystem
* RETURNS:
* Status of operation
*/
{
if (!TCPInitialized)
return STATUS_SUCCESS;
ExDeleteNPagedLookasideList(&TdiBucketLookasideList);
LibIPShutdown();
/* Deregister this protocol with IP layer */
IPRegisterProtocol(IPPROTO_TCP, NULL);
TCPInitialized = FALSE;
PortsShutdown( &TCPPorts );
return STATUS_SUCCESS;
}
NTSTATUS TCPTranslateError(const err_t err)
{
NTSTATUS Status;
switch (err)
{
case ERR_OK: Status = STATUS_SUCCESS; return Status; //0
case ERR_MEM: Status = STATUS_INSUFFICIENT_RESOURCES; break; //-1
case ERR_BUF: Status = STATUS_BUFFER_TOO_SMALL; break; //-2
case ERR_TIMEOUT: Status = STATUS_TIMEOUT; break; // -3
case ERR_RTE: Status = STATUS_NETWORK_UNREACHABLE; break; //-4
case ERR_INPROGRESS: Status = STATUS_PENDING; return Status; //-5
case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-6
case ERR_WOULDBLOCK: Status = STATUS_CANT_WAIT; break; //-7
case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-8
case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-9 (FIXME)
case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-10
case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-11
case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-12
case ERR_CONN: Status = STATUS_INVALID_CONNECTION; break; //-13
case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-14
case ERR_IF: Status = STATUS_UNEXPECTED_NETWORK_ERROR; break; //-15
default:
DbgPrint("Invalid error value: %d\n", err);
ASSERT(FALSE);
Status = STATUS_UNSUCCESSFUL;
break;
}
DbgPrint("TCP operation failed: 0x%x (%d)\n", Status, err);
return Status;
}
NTSTATUS TCPConnect
( PCONNECTION_ENDPOINT Connection,
PTDI_CONNECTION_INFORMATION ConnInfo,
PTDI_CONNECTION_INFORMATION ReturnInfo,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context )
{
NTSTATUS Status;
struct ip_addr bindaddr, connaddr;
IP_ADDRESS RemoteAddress;
USHORT RemotePort;
TA_IP_ADDRESS LocalAddress;
PTDI_BUCKET Bucket;
PNEIGHBOR_CACHE_ENTRY NCE;
KIRQL OldIrql;
TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n"));
Status = AddrBuildAddress
((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
&RemoteAddress,
&RemotePort);
if (!NT_SUCCESS(Status))
{
TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
return Status;
}
/* Freed in TCPSocketState */
TI_DbgPrint(DEBUG_TCP,
("Connecting to address %x:%x\n",
RemoteAddress.Address.IPv4Address,
RemotePort));
LockObject(Connection, &OldIrql);
if (!Connection->AddressFile)
{
UnlockObject(Connection, OldIrql);
return STATUS_INVALID_PARAMETER;
}
if (AddrIsUnspecified(&Connection->AddressFile->Address))
{
if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
{
UnlockObject(Connection, OldIrql);
return STATUS_NETWORK_UNREACHABLE;
}
bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address;
}
else
{
bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address;
}
Status = TCPTranslateError(LibTCPBind(Connection,
&bindaddr,
Connection->AddressFile->Port));
if (NT_SUCCESS(Status))
{
/* Copy bind address into connection */
Connection->AddressFile->Address.Address.IPv4Address = bindaddr.addr;
/* Check if we had an unspecified port */
if (!Connection->AddressFile->Port)
{
/* We did, so we need to copy back the port */
Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
if (NT_SUCCESS(Status))
{
/* Allocate the port in the port bitmap */
Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
/* This should never fail */
ASSERT(Connection->AddressFile->Port != 0xFFFF);
}
}
if (NT_SUCCESS(Status))
{
connaddr.addr = RemoteAddress.Address.IPv4Address;
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection, OldIrql);
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = (PVOID)Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
Status = TCPTranslateError(LibTCPConnect(Connection,
&connaddr,
RemotePort));
}
}
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS TCPDisconnect
( PCONNECTION_ENDPOINT Connection,
UINT Flags,
PLARGE_INTEGER Timeout,
PTDI_CONNECTION_INFORMATION ConnInfo,
PTDI_CONNECTION_INFORMATION ReturnInfo,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context )
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
LARGE_INTEGER ActualTimeout;
TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));
LockObject(Connection, &OldIrql);
if (Connection->SocketContext)
{
if (Flags & TDI_DISCONNECT_RELEASE)
{
if (IsListEmpty(&Connection->SendRequest))
{
Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
}
else if (Timeout && Timeout->QuadPart == 0)
{
FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
Status = STATUS_TIMEOUT;
}
else
{
/* Use the timeout specified or 1 second if none was specified */
if (Timeout)
{
ActualTimeout = *Timeout;
}
else
{
ActualTimeout.QuadPart = -1000000;
}
/* We couldn't complete the request now because we need to wait for outstanding I/O */
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection, OldIrql);
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = (PVOID)Complete;
Bucket->Request.RequestContext = Context;
InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry);
ReferenceObject(Connection);
if (KeCancelTimer(&Connection->DisconnectTimer))
{
DereferenceObject(Connection);
}
KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc);
Status = STATUS_PENDING;
}
}
if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
{
FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE);
FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE);
Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
}
}
else
{
/* We already got closed by the other side so just return success */
Status = STATUS_SUCCESS;
}
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));
return Status;
}
NTSTATUS TCPReceiveData
( PCONNECTION_ENDPOINT Connection,
PNDIS_BUFFER Buffer,
ULONG ReceiveLength,
PULONG BytesReceived,
ULONG ReceiveFlags,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context )
{
PTDI_BUCKET Bucket;
PUCHAR DataBuffer;
UINT DataLen, Received;
NTSTATUS Status;
TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n",
ReceiveLength, Connection->SocketContext));
NdisQueryBuffer(Buffer, &DataBuffer, &DataLen);
Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received);
if (Status == STATUS_PENDING)
{
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Failed to allocate bucket\n"));
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n"));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n"));
(*BytesReceived) = 0;
}
else
{
(*BytesReceived) = Received;
}
return Status;
}
NTSTATUS TCPSendData
( PCONNECTION_ENDPOINT Connection,
PCHAR BufferData,
ULONG SendLength,
PULONG BytesSent,
ULONG Flags,
PTCP_COMPLETION_ROUTINE Complete,
PVOID Context )
{
NTSTATUS Status;
PTDI_BUCKET Bucket;
KIRQL OldIrql;
LockObject(Connection, &OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n",
SendLength, Connection->SocketContext));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n",
Connection->SocketContext));
Status = TCPTranslateError(LibTCPSend(Connection,
BufferData,
SendLength,
BytesSent,
FALSE));
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength));
/* Keep this request around ... there was no data yet */
if (Status == STATUS_PENDING)
{
/* Freed in TCPSocketState */
Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
if (!Bucket)
{
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n"));
return STATUS_NO_MEMORY;
}
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
InsertTailList( &Connection->SendRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
}
UnlockObject(Connection, OldIrql);
TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status));
return Status;
}
UINT TCPAllocatePort(const UINT HintPort)
{
if (HintPort)
{
if (AllocatePort(&TCPPorts, HintPort))
return HintPort;
else
{
TI_DbgPrint(MID_TRACE,("We got a hint port but couldn't allocate it\n"));
return (UINT)-1;
}
}
else
return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
}
VOID TCPFreePort(const UINT Port)
{
DeallocatePort(&TCPPorts, Port);
}
NTSTATUS TCPGetSockAddress
( PCONNECTION_ENDPOINT Connection,
PTRANSPORT_ADDRESS Address,
BOOLEAN GetRemote )
{
PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
struct ip_addr ipaddr;
NTSTATUS Status;
KIRQL OldIrql;
AddressIP->TAAddressCount = 1;
AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
LockObject(Connection, &OldIrql);
if (GetRemote)
{
Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext,
&ipaddr,
&AddressIP->Address[0].Address[0].sin_port));
}
else
{
Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext,
&ipaddr,
&AddressIP->Address[0].Address[0].sin_port));
}
UnlockObject(Connection, OldIrql);
AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
RtlZeroMemory(&AddressIP->Address[0].Address[0].sin_zero,
sizeof(AddressIP->Address[0].Address[0].sin_zero));
return Status;
}
BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
{
PLIST_ENTRY Entry;
PLIST_ENTRY ListHead[5];
KIRQL OldIrql;
PTDI_BUCKET Bucket;
UINT i = 0;
BOOLEAN Found = FALSE;
ListHead[0] = &Endpoint->SendRequest;
ListHead[1] = &Endpoint->ReceiveRequest;
ListHead[2] = &Endpoint->ConnectRequest;
ListHead[3] = &Endpoint->ListenRequest;
ListHead[4] = &Endpoint->ShutdownRequest;
LockObject(Endpoint, &OldIrql);
for( i = 0; i < 5; i++ )
{
for( Entry = ListHead[i]->Flink;
Entry != ListHead[i];
Entry = Entry->Flink )
{
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
if( Bucket->Request.RequestContext == Irp )
{
RemoveEntryList( &Bucket->Entry );
ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
Found = TRUE;
break;
}
}
}
UnlockObject(Endpoint, OldIrql);
return Found;
}
NTSTATUS
TCPSetNoDelay(
PCONNECTION_ENDPOINT Connection,
BOOLEAN Set)
{
if (!Connection)
return STATUS_UNSUCCESSFUL;
if (Connection->SocketContext == NULL)
return STATUS_UNSUCCESSFUL;
LibTCPSetNoDelay(Connection->SocketContext, Set);
return STATUS_SUCCESS;
}
/* EOF */