From 459e41372555c60b03076333f624d8a04a4582c9 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 21 Sep 2010 06:11:24 +0000 Subject: [PATCH] [IP] - Rewrite most of the lower TCP layer code to work with lwIP [LWIP] - Write all of the implementation-specific code and headers [TCPIP] - Add assertions in the object reference functions - Remove the completion queue hack This is still isn't totally finished yet. There are still two main issues that need to be overcome: listen/accept don't work at all and the performance is horrible. I hope that once I tune some of the options, I can get it to perform reasonably well. If any curious testers want to try this out, be my guest but realize that not a lot of apps will work yet. Suggestions are welcome! :) svn path=/branches/tcp-rewrite-branch/; revision=48840 --- drivers/network/tcpip/include/precomp.h | 1 - drivers/network/tcpip/include/tcp.h | 38 +- drivers/network/tcpip/include/tcpip.h | 16 +- drivers/network/tcpip/include/titypes.h | 8 +- drivers/network/tcpip/tcpip.rbuild | 5 +- lib/drivers/directory.rbuild | 3 + lib/drivers/ip/ip.rbuild | 3 +- lib/drivers/ip/network/ip.c | 22 +- lib/drivers/ip/network/routines.c | 51 -- lib/drivers/ip/transport/tcp/accept.c | 120 ++-- lib/drivers/ip/transport/tcp/event.c | 537 +++++++++------- lib/drivers/ip/transport/tcp/if.c | 265 ++++---- lib/drivers/ip/transport/tcp/tcp.c | 627 ++++--------------- lib/drivers/lwip/lwip.rbuild | 37 ++ lib/drivers/lwip/src/include/arch/bpstruct.h | 1 + lib/drivers/lwip/src/include/arch/cc.h | 63 ++ lib/drivers/lwip/src/include/arch/epstruct.h | 1 + lib/drivers/lwip/src/include/arch/perf.h | 4 + lib/drivers/lwip/src/include/arch/sys_arch.h | 45 ++ lib/drivers/lwip/src/include/lwipopts.h | 194 ++++++ lib/drivers/lwip/src/include/rosip.h | 31 + lib/drivers/lwip/src/rosip.c | 45 ++ lib/drivers/lwip/src/rosmem.c | 38 ++ lib/drivers/lwip/src/rostcp.c | 581 +++++++++++++++++ lib/drivers/lwip/src/sys_arch.c | 380 +++++++++++ 25 files changed, 2116 insertions(+), 1000 deletions(-) create mode 100755 lib/drivers/lwip/lwip.rbuild create mode 100755 lib/drivers/lwip/src/include/arch/bpstruct.h create mode 100755 lib/drivers/lwip/src/include/arch/cc.h create mode 100755 lib/drivers/lwip/src/include/arch/epstruct.h create mode 100755 lib/drivers/lwip/src/include/arch/perf.h create mode 100755 lib/drivers/lwip/src/include/arch/sys_arch.h create mode 100755 lib/drivers/lwip/src/include/lwipopts.h create mode 100755 lib/drivers/lwip/src/include/rosip.h create mode 100755 lib/drivers/lwip/src/rosip.c create mode 100755 lib/drivers/lwip/src/rosmem.c create mode 100755 lib/drivers/lwip/src/rostcp.c create mode 100755 lib/drivers/lwip/src/sys_arch.c diff --git a/drivers/network/tcpip/include/precomp.h b/drivers/network/tcpip/include/precomp.h index f37046d128e..124df675e7d 100644 --- a/drivers/network/tcpip/include/precomp.h +++ b/drivers/network/tcpip/include/precomp.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/network/tcpip/include/tcp.h b/drivers/network/tcpip/include/tcp.h index 637900a5424..8724d16cc9a 100644 --- a/drivers/network/tcpip/include/tcp.h +++ b/drivers/network/tcpip/include/tcp.h @@ -24,15 +24,6 @@ typedef struct TCPv4_HEADER { USHORT Urgent; /* Pointer to urgent data */ } TCPv4_HEADER, *PTCPv4_HEADER; -/* TCPv4 header flags */ -#define TCP_URG 0x20 -#define TCP_ACK 0x10 -#define TCP_PSH 0x08 -#define TCP_RST 0x04 -#define TCP_SYN 0x02 -#define TCP_FIN 0x01 - - #define TCPOPT_END_OF_LIST 0x0 #define TCPOPT_NO_OPERATION 0x1 #define TCPOPT_MAX_SEG_SIZE 0x2 @@ -79,6 +70,19 @@ typedef struct _CLIENT_DATA { /* Delay variance factor */ #define TCP_BETA_RETRANSMISSION_TIMEOUT(x)(((x)*16)/10) /* 1.6 */ +#define SEL_CONNECT 1 +#define SEL_FIN 2 +#define SEL_RST 4 +#define SEL_ABRT 8 +#define SEL_READ 16 +#define SEL_WRITE 32 +#define SEL_ACCEPT 64 +#define SEL_OOB 128 +#define SEL_ERROR 256 +#define SEL_FINOUT 512 + +#define FREAD 0x0001 +#define FWRITE 0x0002 /* Datagram/segment send request flags */ @@ -93,9 +97,8 @@ extern LONG TCP_IPIdentification; extern CLIENT_DATA ClientInfo; /* accept.c */ -NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener, - PCONNECTION_ENDPOINT Connection, - PTDI_REQUEST_KERNEL Request ); +NTSTATUS TCPCheckPeerForAccept(PVOID Context, + PTDI_REQUEST_KERNEL Request); NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ); BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener, PCONNECTION_ENDPOINT Connection ); @@ -163,7 +166,7 @@ NTSTATUS TCPSendData( NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection ); -NTSTATUS TCPTranslateError( int OskitError ); +NTSTATUS TCPTranslateError( INT8 err ); UINT TCPAllocatePort( UINT HintPort ); @@ -181,3 +184,12 @@ NTSTATUS TCPShutdown( VOID); BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Connection, PIRP Irp ); + +VOID +TCPUpdateInterfaceLinkStatus(PIP_INTERFACE IF); + +VOID +TCPUpdateInterfaceIPInformation(PIP_INTERFACE IF); + +VOID +FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status); diff --git a/drivers/network/tcpip/include/tcpip.h b/drivers/network/tcpip/include/tcpip.h index 563e662f602..9b077841cfd 100644 --- a/drivers/network/tcpip/include/tcpip.h +++ b/drivers/network/tcpip/include/tcpip.h @@ -135,19 +135,9 @@ struct in_addr #define s_impno S_un.S_un_b.s_b4 #define s_lh S_un.S_un_b.s_b3 }; -struct sockaddr_in -{ - short sin_family; - u_short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; -}; -typedef struct sockaddr_in SOCKADDR_IN; -struct sockaddr -{ - u_short sa_family; - char sa_data[14]; -}; + +#define __LWIP_INET_H__ +#include "lwip/sockets.h" /* Sufficient information to manage the entity list */ typedef struct { diff --git a/drivers/network/tcpip/include/titypes.h b/drivers/network/tcpip/include/titypes.h index 5400010db5e..cb48cb4d30b 100644 --- a/drivers/network/tcpip/include/titypes.h +++ b/drivers/network/tcpip/include/titypes.h @@ -13,6 +13,7 @@ */ #define ReferenceObject(Object) \ { \ + ASSERT(((Object)->RefCount) > 0); \ InterlockedIncrement(&((Object)->RefCount)); \ } @@ -22,6 +23,7 @@ */ #define DereferenceObject(Object) \ { \ + ASSERT(((Object)->RefCount) > 0); \ if (InterlockedDecrement(&((Object)->RefCount)) == 0) \ (((Object)->Free)(Object)); \ } @@ -33,7 +35,7 @@ { \ ReferenceObject(Object); \ KeAcquireSpinLock(&((Object)->Lock), Irql); \ - memcpy(&(Object)->OldIrql, Irql, sizeof(KIRQL)); \ + (Object)->OldIrql = *Irql; \ } /* @@ -266,10 +268,6 @@ typedef struct _CONNECTION_ENDPOINT { LIST_ENTRY ListenRequest; /* Queued listen requests */ LIST_ENTRY ReceiveRequest; /* Queued receive requests */ LIST_ENTRY SendRequest; /* Queued send requests */ - LIST_ENTRY CompletionQueue;/* Completed requests to finish */ - - /* Signals */ - UINT SignalState; /* Active signals from oskit */ } CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT; diff --git a/drivers/network/tcpip/tcpip.rbuild b/drivers/network/tcpip/tcpip.rbuild index f3c6114e568..698254de4d9 100644 --- a/drivers/network/tcpip/tcpip.rbuild +++ b/drivers/network/tcpip/tcpip.rbuild @@ -3,11 +3,12 @@ include - include + src/include + src/include/ipv4 ip - oskittcp + lwip ndis pseh chew diff --git a/lib/drivers/directory.rbuild b/lib/drivers/directory.rbuild index 3f84d4447ea..5533ea771b0 100644 --- a/lib/drivers/directory.rbuild +++ b/lib/drivers/directory.rbuild @@ -10,6 +10,9 @@ + + + diff --git a/lib/drivers/ip/ip.rbuild b/lib/drivers/ip/ip.rbuild index 6a3e5500c30..248aa6dd358 100644 --- a/lib/drivers/ip/ip.rbuild +++ b/lib/drivers/ip/ip.rbuild @@ -3,7 +3,8 @@ include - include + src/include + src/include/ipv4 diff --git a/lib/drivers/ip/network/ip.c b/lib/drivers/ip/network/ip.c index a24cd4e6d39..b2d3eae745b 100644 --- a/lib/drivers/ip/network/ip.c +++ b/lib/drivers/ip/network/ip.c @@ -10,6 +10,9 @@ #include "precomp.h" +#define __LWIP_INET_H__ +#include "lwip/netifapi.h" + LIST_ENTRY InterfaceListHead; KSPIN_LOCK InterfaceListLock; @@ -21,6 +24,12 @@ BOOLEAN IpWorkItemQueued = FALSE; IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE]; +VOID +TCPRegisterInterface(PIP_INTERFACE IF); + +VOID +TCPUnregisterInterface(PIP_INTERFACE IF); + VOID DontFreePacket( PVOID Object) /* @@ -162,13 +171,14 @@ PIP_INTERFACE IPCreateInterface( TcpipInitializeSpinLock(&IF->Lock); - IF->TCPContext = ExAllocatePoolWithTag - ( NonPagedPool, sizeof(OSK_IFADDR) + 3 * sizeof( struct sockaddr_in ), - OSKITTCP_CONTEXT_TAG ); + IF->TCPContext = ExAllocatePool + ( NonPagedPool, sizeof(struct netif)); if (!IF->TCPContext) { ExFreePoolWithTag(IF, IP_INTERFACE_TAG); return NULL; } + + TCPRegisterInterface(IF); #ifdef __NTDRIVER__ InsertTDIInterfaceEntity( IF ); @@ -191,8 +201,10 @@ VOID IPDestroyInterface( #ifdef __NTDRIVER__ RemoveTDIInterfaceEntity( IF ); #endif + + TCPUnregisterInterface(IF); - ExFreePoolWithTag(IF->TCPContext, OSKITTCP_CONTEXT_TAG); + ExFreePool(IF->TCPContext); ExFreePoolWithTag(IF, IP_INTERFACE_TAG); } @@ -219,6 +231,8 @@ VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) { * other computers */ if (IF != Loopback) ARPTransmit(NULL, NULL, IF); + + TCPUpdateInterfaceIPInformation(IF); } BOOLEAN IPRegisterInterface( diff --git a/lib/drivers/ip/network/routines.c b/lib/drivers/ip/network/routines.c index 44aa2761076..1c01c1b7833 100644 --- a/lib/drivers/ip/network/routines.c +++ b/lib/drivers/ip/network/routines.c @@ -54,46 +54,9 @@ static VOID DisplayIPHeader( ((IPHeader->DstAddr >> 16) & 0xFF), ((IPHeader->DstAddr >> 24) & 0xFF)); } -static VOID DisplayTCPHeader( - PCHAR Header, - UINT Length) -{ - /* FIXME: IPv4 only */ - PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header; - PTCPv4_HEADER TCPHeader; - - if (IPHeader->Protocol != IPPROTO_TCP) { - DbgPrint("This is not a TCP datagram. Protocol is %d\n", IPHeader->Protocol); - return; - } - - TCPHeader = (PTCPv4_HEADER)((PCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4); - - DbgPrint("TCP header:\n"); - DbgPrint(" SourcePort: %d\n", WN2H(TCPHeader->SourcePort)); - DbgPrint(" DestinationPort: %d\n", WN2H(TCPHeader->DestinationPort)); - DbgPrint(" SequenceNumber: 0x%x\n", DN2H(TCPHeader->SequenceNumber)); - DbgPrint(" AckNumber: 0x%x\n", DN2H(TCPHeader->AckNumber)); - DbgPrint(" DataOffset: 0x%x (0x%x) 32-bit words\n", TCPHeader->DataOffset, TCPHeader->DataOffset >> 4); - DbgPrint(" Flags: 0x%x (0x%x)\n", TCPHeader->Flags, TCPHeader->Flags & 0x3F); - if ((TCPHeader->Flags & TCP_URG) > 0) DbgPrint(" TCP_URG - Urgent Pointer field significant\n"); - if ((TCPHeader->Flags & TCP_ACK) > 0) DbgPrint(" TCP_ACK - Acknowledgement field significant\n"); - if ((TCPHeader->Flags & TCP_PSH) > 0) DbgPrint(" TCP_PSH - Push Function\n"); - if ((TCPHeader->Flags & TCP_RST) > 0) DbgPrint(" TCP_RST - Reset the connection\n"); - if ((TCPHeader->Flags & TCP_SYN) > 0) DbgPrint(" TCP_SYN - Synchronize sequence numbers\n"); - if ((TCPHeader->Flags & TCP_FIN) > 0) DbgPrint(" TCP_FIN - No more data from sender\n"); - DbgPrint(" Window: 0x%x\n", WN2H(TCPHeader->Window)); - DbgPrint(" Checksum: 0x%x\n", WN2H(TCPHeader->Checksum)); - DbgPrint(" Urgent: 0x%x\n", WN2H(TCPHeader->Urgent)); -} - - VOID DisplayTCPPacket( PIP_PACKET IPPacket) { - UINT Length; - PCHAR Buffer; - if ((DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_PBUFFER | DPFLTR_MASK) != TRUE) || (DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_TCP | DPFLTR_MASK) != TRUE)) { return; @@ -112,20 +75,6 @@ VOID DisplayTCPPacket( TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize)); TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize)); TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket)); - - if (IPPacket->NdisPacket) { - NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length); - Buffer = ExAllocatePool(NonPagedPool, Length); - if (Buffer) { - Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, 0, Length); - DisplayTCPHeader(Buffer, Length); - ExFreePool(Buffer); - } - } else { - Buffer = IPPacket->Header; - Length = IPPacket->ContigSize; - DisplayTCPHeader(Buffer, Length); - } } #endif diff --git a/lib/drivers/ip/transport/tcp/accept.c b/lib/drivers/ip/transport/tcp/accept.c index 643f59da208..ae98ad34cd7 100644 --- a/lib/drivers/ip/transport/tcp/accept.c +++ b/lib/drivers/ip/transport/tcp/accept.c @@ -10,55 +10,32 @@ #include "precomp.h" -/* Listener->Lock MUST be acquired */ -NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener, - PCONNECTION_ENDPOINT Connection, - PTDI_REQUEST_KERNEL Request ) { +#include "rosip.h" + +NTSTATUS TCPCheckPeerForAccept(PVOID Context, + PTDI_REQUEST_KERNEL Request) { + struct tcp_pcb *newpcb = Context; NTSTATUS Status; - SOCKADDR_IN OutAddr; - OSK_UINT OutAddrLen; - PTA_IP_ADDRESS RequestAddressReturn; 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"); - /* Unpack TDI info -- We need the return connection information - * struct to return the address so it can be filtered if needed - * by WSAAccept -- The returned address will be passed on to - * userland after we complete this irp */ - WhoIsConnecting = (PTDI_CONNECTION_INFORMATION) - Request->ReturnConnectionInformation; - - Status = TCPTranslateError - ( OskitTCPAccept( Listener->SocketContext, - &Connection->SocketContext, - Connection, - &OutAddr, - sizeof(OutAddr), - &OutAddrLen, - Request->RequestFlags & TDI_QUERY_ACCEPT ? 0 : 1 ) ); - - TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status)); - - if( NT_SUCCESS(Status) && Status != STATUS_PENDING ) { - RequestAddressReturn = WhoIsConnecting->RemoteAddress; - - TI_DbgPrint(DEBUG_TCP,("Copying address to %x (Who %x)\n", - RequestAddressReturn, WhoIsConnecting)); - - RequestAddressReturn->TAAddressCount = 1; - RequestAddressReturn->Address[0].AddressLength = OutAddrLen; - - /* BSD uses the first byte of the sockaddr struct as a length. - * Since windows doesn't do that we strip it */ - RequestAddressReturn->Address[0].AddressType = - (OutAddr.sin_family >> 8) & 0xff; - - RtlCopyMemory( &RequestAddressReturn->Address[0].Address, - ((PCHAR)&OutAddr) + sizeof(USHORT), - sizeof(RequestAddressReturn->Address[0].Address[0]) ); - - TI_DbgPrint(DEBUG_TCP,("Done copying\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; + TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status)); return Status; @@ -68,7 +45,7 @@ NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener, * lifetime as the address file */ NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) { NTSTATUS Status = STATUS_SUCCESS; - SOCKADDR_IN AddressToBind; + struct ip_addr AddressToBind; KIRQL OldIrql; ASSERT(Connection); @@ -80,21 +57,19 @@ NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) { TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n", Connection->SocketContext)); + + AddressToBind.addr = Connection->AddressFile->Address.Address.IPv4Address; - AddressToBind.sin_family = AF_INET; - memcpy( &AddressToBind.sin_addr, - &Connection->AddressFile->Address.Address.IPv4Address, - sizeof(AddressToBind.sin_addr) ); - AddressToBind.sin_port = Connection->AddressFile->Port; - - TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port)); - - Status = TCPTranslateError( OskitTCPBind( Connection->SocketContext, - &AddressToBind, - sizeof(AddressToBind) ) ); + Status = TCPTranslateError(LibTCPBind(Connection->SocketContext, + &AddressToBind, + Connection->AddressFile->Port)); if (NT_SUCCESS(Status)) - Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) ); + { + Connection->SocketContext = LibTCPListen(Connection->SocketContext, Backlog); + if (!Connection->SocketContext) + Status = STATUS_UNSUCCESSFUL; + } UnlockObject(Connection, OldIrql); @@ -145,22 +120,17 @@ NTSTATUS TCPAccept ( PTDI_REQUEST Request, LockObject(Listener, &OldIrql); - Status = TCPServiceListeningSocket( Listener, Connection, - (PTDI_REQUEST_KERNEL)Request ); - - if( Status == STATUS_PENDING ) { - Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), - TDI_BUCKET_TAG ); - - if( Bucket ) { - ReferenceObject(Connection); - Bucket->AssociatedEndpoint = Connection; - Bucket->Request.RequestNotifyObject = Complete; - Bucket->Request.RequestContext = Context; - InsertTailList( &Listener->ListenRequest, &Bucket->Entry ); - } else - Status = STATUS_NO_MEMORY; - } + Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), + TDI_BUCKET_TAG ); + + if( Bucket ) { + Bucket->AssociatedEndpoint = Connection; + Bucket->Request.RequestNotifyObject = Complete; + Bucket->Request.RequestContext = Context; + InsertTailList( &Listener->ListenRequest, &Bucket->Entry ); + Status = STATUS_PENDING; + } else + Status = STATUS_NO_MEMORY; UnlockObject(Listener, OldIrql); diff --git a/lib/drivers/ip/transport/tcp/event.c b/lib/drivers/ip/transport/tcp/event.c index 4534da39c05..3b80db3f1bf 100644 --- a/lib/drivers/ip/transport/tcp/event.c +++ b/lib/drivers/ip/transport/tcp/event.c @@ -2,248 +2,327 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS TCP/IP protocol driver * FILE: transport/tcp/event.c - * PURPOSE: Transmission Control Protocol -- Events from oskittcp - * PROGRAMMERS: Art Yerkes - * REVISIONS: - * CSH 01/08-2000 Created + * PURPOSE: Transmission Control Protocol + * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) */ #include "precomp.h" -int TCPSocketState(void *ClientData, - void *WhichSocket, - void *WhichConnection, - OSK_UINT NewState ) { - PCONNECTION_ENDPOINT Connection = WhichConnection; +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/pbuf.h" +#include "lwip/tcp.h" +#include "lwip/api.h" - TI_DbgPrint(DEBUG_TCP,("Connection: %x Flags: %c%c%c%c%c\n", - Connection, - NewState & SEL_CONNECT ? 'C' : 'c', - NewState & SEL_READ ? 'R' : 'r', - NewState & SEL_FIN ? 'F' : 'f', - NewState & SEL_ACCEPT ? 'A' : 'a', - NewState & SEL_WRITE ? 'W' : 'w')); +#include "rosip.h" - /* If this socket is missing its socket context, that means that it - * has been created as a new connection in sonewconn but not accepted - * yet. We can safely ignore event notifications on these sockets. - * Once they are accepted, they will get a socket context and we will - * be able to process them. - */ - if (!Connection) - return 0; - - TI_DbgPrint(DEBUG_TCP,("Called: NewState %x (Conn %x) (Change %x)\n", - NewState, Connection, - Connection->SignalState ^ NewState, - NewState)); - - Connection->SignalState = NewState; - - HandleSignalledConnection(Connection); - - return 0; -} - -void TCPPacketSendComplete( PVOID Context, - PNDIS_PACKET NdisPacket, - NDIS_STATUS NdisStatus ) { - TI_DbgPrint(DEBUG_TCP,("called %x\n", NdisPacket)); - FreeNdisPacket(NdisPacket); - TI_DbgPrint(DEBUG_TCP,("done\n")); -} - -#define STRINGIFY(x) #x - -int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) { - NDIS_STATUS NdisStatus; - PNEIGHBOR_CACHE_ENTRY NCE; - IP_PACKET Packet = { 0 }; - IP_ADDRESS RemoteAddress, LocalAddress; - PIPv4_HEADER Header; - - if( *data == 0x45 ) { /* IPv4 */ - Header = (PIPv4_HEADER)data; - LocalAddress.Type = IP_ADDRESS_V4; - LocalAddress.Address.IPv4Address = Header->SrcAddr; - RemoteAddress.Type = IP_ADDRESS_V4; - RemoteAddress.Address.IPv4Address = Header->DstAddr; - } else { - TI_DbgPrint(MIN_TRACE,("Outgoing packet is not IPv4\n")); - OskitDumpBuffer( data, len ); - return OSK_EINVAL; - } - - if(!(NCE = RouteGetRouteToDestination( &RemoteAddress ))) { - TI_DbgPrint(MIN_TRACE,("Unable to get route to %s\n", A2S(&RemoteAddress))); - return OSK_EADDRNOTAVAIL; - } - - NdisStatus = AllocatePacketWithBuffer( &Packet.NdisPacket, NULL, len ); - - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(DEBUG_TCP, ("Error from NDIS: %08x\n", NdisStatus)); - return OSK_ENOBUFS; - } - - GetDataPtr( Packet.NdisPacket, 0, - (PCHAR *)&Packet.Header, &Packet.ContigSize ); - - RtlCopyMemory( Packet.Header, data, len ); - - Packet.HeaderSize = sizeof(IPv4_HEADER); - Packet.TotalSize = len; - Packet.SrcAddr = LocalAddress; - Packet.DstAddr = RemoteAddress; - - if (!NT_SUCCESS(IPSendDatagram( &Packet, NCE, TCPPacketSendComplete, NULL ))) - { - FreeNdisPacket(Packet.NdisPacket); - return OSK_EINVAL; - } - - return 0; -} - -/* Memory management routines - * - * By far the most requests for memory are either for 128 or 2049 byte blocks, - * so we want to satisfy those from lookaside lists. Unfortunately, the - * TCPFree() function doesn't pass the size of the block to be freed, so we - * need to keep track of it ourselves. We do it by prepending each block with - * 4 bytes, indicating if this is a 'L'arge (2049), 'S'mall (128) or 'O'ther - * block. - */ - -/* Set to some non-zero value to get a profile of memory allocation sizes */ -#define MEM_PROFILE 0 - -#define SMALL_SIZE 128 -#define LARGE_SIZE 2049 - -#define SIGNATURE_LARGE 'LLLL' -#define SIGNATURE_SMALL 'SSSS' -#define SIGNATURE_OTHER 'OOOO' -static NPAGED_LOOKASIDE_LIST LargeLookasideList; -static NPAGED_LOOKASIDE_LIST SmallLookasideList; - -NTSTATUS -TCPMemStartup( void ) +VOID +FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status) { - ExInitializeNPagedLookasideList( &LargeLookasideList, - NULL, - NULL, - 0, - LARGE_SIZE + sizeof( ULONG ), - OSK_LARGE_TAG, - 0 ); - ExInitializeNPagedLookasideList( &SmallLookasideList, - NULL, - NULL, - 0, - SMALL_SIZE + sizeof( ULONG ), - OSK_SMALL_TAG, - 0 ); - - return STATUS_SUCCESS; -} - -void *TCPMalloc( void *ClientData, - OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) { - void *v; - ULONG Signature; - -#if 0 != MEM_PROFILE - static OSK_UINT *Sizes = NULL, *Counts = NULL, ArrayAllocated = 0; - static OSK_UINT ArrayUsed = 0, AllocationCount = 0; - OSK_UINT i, NewSize, *NewArray; - int Found; - - Found = 0; - for ( i = 0; i < ArrayUsed && ! Found; i++ ) { - Found = ( Sizes[i] == Bytes ); - if ( Found ) { - Counts[i]++; - } - } - if ( ! Found ) { - if ( ArrayAllocated <= ArrayUsed ) { - NewSize = ( 0 == ArrayAllocated ? 16 : 2 * ArrayAllocated ); - NewArray = exAllocatePool( NonPagedPool, 2 * NewSize * sizeof( OSK_UINT ) ); - if ( NULL != NewArray ) { - if ( 0 != ArrayAllocated ) { - memcpy( NewArray, Sizes, - ArrayAllocated * sizeof( OSK_UINT ) ); - exFreePool( Sizes ); - memcpy( NewArray + NewSize, Counts, - ArrayAllocated * sizeof( OSK_UINT ) ); - exFreePool( Counts ); - } - Sizes = NewArray; - Counts = NewArray + NewSize; - ArrayAllocated = NewSize; - } else if ( 0 != ArrayAllocated ) { - exFreePool( Sizes ); - exFreePool( Counts ); - ArrayAllocated = 0; - } - } - if ( ArrayUsed < ArrayAllocated ) { - Sizes[ArrayUsed] = Bytes; - Counts[ArrayUsed] = 1; - ArrayUsed++; - } - } - - if ( 0 == (++AllocationCount % MEM_PROFILE) ) { - TI_DbgPrint(DEBUG_TCP, ("Memory allocation size profile:\n")); - for ( i = 0; i < ArrayUsed; i++ ) { + PTCP_COMPLETION_ROUTINE Complete; + PTDI_BUCKET Bucket; + PLIST_ENTRY Entry; + + ReferenceObject(Connection); + + DbgPrint("Flushing recv/all with status: 0x%x\n", Status); + + while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) { + Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); + TI_DbgPrint(DEBUG_TCP, - ("Size %4u Count %5u\n", Sizes[i], Counts[i])); + ("Completing Receive request: %x %x\n", + Bucket->Request, Status)); + + Bucket->Status = Status; + Bucket->Information = 0; + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); } - TI_DbgPrint(DEBUG_TCP, ("End of memory allocation size profile\n")); + + if (Status == STATUS_SUCCESS) Status = STATUS_FILE_CLOSED; + + while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) { + Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); + + Bucket->Status = Status; + Bucket->Information = 0; + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); } -#endif /* MEM_PROFILE */ - - if ( SMALL_SIZE == Bytes ) { - v = ExAllocateFromNPagedLookasideList( &SmallLookasideList ); - Signature = SIGNATURE_SMALL; - } else if ( LARGE_SIZE == Bytes ) { - v = ExAllocateFromNPagedLookasideList( &LargeLookasideList ); - Signature = SIGNATURE_LARGE; - } else { - v = ExAllocatePoolWithTag( NonPagedPool, Bytes + sizeof(ULONG), - OSK_OTHER_TAG ); - Signature = SIGNATURE_OTHER; + + 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; + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); } - if( v ) { - *((ULONG *) v) = Signature; - v = (void *)((char *) v + sizeof(ULONG)); + + while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) { + Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); + + Bucket->Status = Status; + Bucket->Information = 0; + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); } - - return v; + + DereferenceObject(Connection); } -void TCPFree( void *ClientData, - void *data, OSK_PCHAR File, OSK_UINT Line ) { - ULONG Signature; - - data = (void *)((char *) data - sizeof(ULONG)); - Signature = *((ULONG *) data); - if ( SIGNATURE_SMALL == Signature ) { - ExFreeToNPagedLookasideList( &SmallLookasideList, data ); - } else if ( SIGNATURE_LARGE == Signature ) { - ExFreeToNPagedLookasideList( &LargeLookasideList, data ); - } else if ( SIGNATURE_OTHER == Signature ) { - ExFreePoolWithTag( data, OSK_OTHER_TAG ); - } else { - ASSERT( FALSE ); - } -} - -void -TCPMemShutdown( void ) +VOID +TCPFinEventHandler(void *arg, err_t err) { - ExDeleteNPagedLookasideList( &SmallLookasideList ); - ExDeleteNPagedLookasideList( &LargeLookasideList ); + PCONNECTION_ENDPOINT Connection = arg; + + FlushAllQueues(Connection, TCPTranslateError(err)); + + /* We're already closed so we don't want to call lwip_close */ + Connection->SocketContext = NULL; } + +VOID +TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb) +{ + PCONNECTION_ENDPOINT Connection = arg; + PTCP_COMPLETION_ROUTINE Complete; + PTDI_BUCKET Bucket; + PLIST_ENTRY Entry; + PIRP Irp; + NTSTATUS Status; + KIRQL OldIrql; + + DbgPrint("TCPAcceptEventHandler\n"); + + 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,("Getting the socket\n")); + + Status = TCPCheckPeerForAccept(newpcb, + (PTDI_REQUEST_KERNEL)&IrpSp->Parameters); + + TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n")); + + Bucket->Status = Status; + Bucket->Information = 0; + + DbgPrint("Associated with: 0x%x\n", Bucket->AssociatedEndpoint->SocketContext); + + DbgPrint("Completing accept event %x\n", Status); + + Complete = Bucket->Request.RequestNotifyObject; + + if (Status == STATUS_SUCCESS) + { + LockObject(Bucket->AssociatedEndpoint, &OldIrql); + Bucket->AssociatedEndpoint->SocketContext = newpcb; + + LibTCPAccept(newpcb, Bucket->AssociatedEndpoint); + UnlockObject(Bucket->AssociatedEndpoint, OldIrql); + } + + DbgPrint("Done!\n"); + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); + } + + DereferenceObject(Connection); +} + +VOID +TCPSendEventHandler(void *arg, u16_t space) +{ + PCONNECTION_ENDPOINT Connection = arg; + PTCP_COMPLETION_ROUTINE Complete; + PTDI_BUCKET Bucket; + PLIST_ENTRY Entry; + PIRP Irp; + NTSTATUS Status; + PMDL Mdl; + + DbgPrint("TCPSendEventHandler\n"); + + 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->SocketContext, + SendBuffer, + SendLen)); + + TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", SendLen)); + + 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) ? SendLen : 0; + + DbgPrint("Completing send req %x\n", Status); + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); + } + } + + DereferenceObject(Connection); +} + +u32_t +TCPRecvEventHandler(void *arg, struct pbuf *p) +{ + PCONNECTION_ENDPOINT Connection = arg; + PTCP_COMPLETION_ROUTINE Complete; + PTDI_BUCKET Bucket; + PLIST_ENTRY Entry; + PIRP Irp; + PMDL Mdl; + UINT Received = 0; + UINT RecvLen; + PUCHAR RecvBuffer; + + ASSERT(p); + + ReferenceObject(Connection); + + DbgPrint("TCPRecvEventHandler\n"); + + if ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) { + 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, &RecvBuffer, &RecvLen ); + + TI_DbgPrint(DEBUG_TCP, + ("Reading %d bytes to %x\n", RecvLen, RecvBuffer)); + + TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection)); + TI_DbgPrint + (DEBUG_TCP, + ("Connection->SocketContext: %x\n", + Connection->SocketContext)); + TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer)); + + RecvLen = MIN(p->tot_len, RecvLen); + + for (Received = 0; Received < RecvLen; Received += p->len, p = p->next) + { + DbgPrint("0x%x: Copying %d bytes to 0x%x from 0x%x\n", p, p->len, ((PUCHAR)RecvBuffer) + Received, p->payload); + RtlCopyMemory(RecvBuffer + Received, p->payload, p->len); + } + + TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received)); + + Bucket->Status = STATUS_SUCCESS; + Bucket->Information = Received; + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); + } + + DereferenceObject(Connection); + + return Received; +} + +VOID +TCPConnectEventHandler(void *arg, err_t err) +{ + PCONNECTION_ENDPOINT Connection = arg; + PTCP_COMPLETION_ROUTINE Complete; + PTDI_BUCKET Bucket; + PLIST_ENTRY Entry; + + DbgPrint("TCPConnectEventHandler\n"); + + ReferenceObject(Connection); + + while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) { + + Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); + + Bucket->Status = TCPTranslateError(err); + Bucket->Information = 0; + + DbgPrint("Completing connection request! (0x%x)\n", err); + + Complete = Bucket->Request.RequestNotifyObject; + + Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); + + ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); + } + + DereferenceObject(Connection); +} \ No newline at end of file diff --git a/lib/drivers/ip/transport/tcp/if.c b/lib/drivers/ip/transport/tcp/if.c index c12bc45e918..c5ed8a855c8 100644 --- a/lib/drivers/ip/transport/tcp/if.c +++ b/lib/drivers/ip/transport/tcp/if.c @@ -1,117 +1,170 @@ -/* - * Copyright (c) 1997-1998 University of Utah and the Flux Group. - * All rights reserved. - * - * This file is part of the Flux OSKit. The OSKit is free software, also known - * as "open source;" you can redistribute it and/or modify it under the terms - * of the GNU General Public License (GPL), version 2, as published by the Free - * Software Foundation (FSF). To explore alternate licensing terms, contact - * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. - * - * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have - * received a copy of the GPL along with the OSKit; see the file COPYING. If - * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. - */ #include "precomp.h" -int if_index = 0; -struct ifaddr **ifnet_addrs; +#include "lwip/pbuf.h" +#include "lwip/netifapi.h" +#include "lwip/ip.h" +#include "lwip/api.h" +#include "lwip/tcpip.h" -int ifqmaxlen = OSK_IFQ_MAXLEN; -struct ifnet *ifnet; - -/* - * Network interface utility routines. - * - * Routines with ifa_ifwith* names take sockaddr *'s as - * parameters. - */ - -POSK_IFADDR TCPGetInterfaceData( PIP_INTERFACE IF ) { - NTSTATUS Status; - POSK_IFADDR ifaddr = IF->TCPContext; - struct sockaddr_in *addr_in; - struct sockaddr_in *dstaddr_in; - struct sockaddr_in *netmask_in; - ASSERT(ifaddr); - - RtlZeroMemory(ifaddr, sizeof(OSK_IFADDR) + 3 * sizeof( struct sockaddr_in )); - - addr_in = (struct sockaddr_in *)&ifaddr[1]; - dstaddr_in = (struct sockaddr_in *)&addr_in[1]; - netmask_in = (struct sockaddr_in *)&dstaddr_in[1]; - - TI_DbgPrint(DEBUG_TCPIF,("Called\n")); - - ifaddr->ifa_addr = (struct sockaddr *)addr_in; - Status = GetInterfaceIPv4Address( IF, - ADE_UNICAST, - (PULONG)&addr_in->sin_addr.s_addr ); - - ASSERT(NT_SUCCESS(Status)); - - ifaddr->ifa_dstaddr = (struct sockaddr *)dstaddr_in; - Status = GetInterfaceIPv4Address(IF, - ADE_POINTOPOINT, - (PULONG)&dstaddr_in->sin_addr.s_addr ); - - ASSERT(NT_SUCCESS(Status)); - - ifaddr->ifa_netmask = (struct sockaddr *)netmask_in; - Status = GetInterfaceIPv4Address(IF, - ADE_ADDRMASK, - (PULONG)&netmask_in->sin_addr.s_addr ); - - ASSERT(NT_SUCCESS(Status)); - - TI_DbgPrint(DEBUG_TCPIF,("interface %x : addr %x\n", - IF, addr_in->sin_addr.s_addr)); - - ifaddr->ifa_flags = 0; - ifaddr->ifa_refcnt = 0; /* Anachronistic */ - ifaddr->ifa_metric = 1; /* We can get it like in ninfo.c, if we want */ - ifaddr->ifa_mtu = IF->MTU; - - TI_DbgPrint(DEBUG_TCPIF,("Leaving\n")); - - return ifaddr; +void TCPPacketSendComplete(PVOID Context, PNDIS_PACKET NdisPacket, NDIS_STATUS NdisStatus) +{ + FreeNdisPacket(NdisPacket); } -POSK_IFADDR TCPFindInterface( void *ClientData, - OSK_UINT AddrType, - OSK_UINT FindType, - OSK_SOCKADDR *ReqAddr, - OSK_IFADDR *Interface ) { +err_t +TCPSendDataCallback(struct netif *netif, struct pbuf *p, struct ip_addr *dest) +{ + NDIS_STATUS NdisStatus; PNEIGHBOR_CACHE_ENTRY NCE; - IP_ADDRESS Destination; - struct sockaddr_in *addr_in = (struct sockaddr_in *)ReqAddr; - POSK_IFADDR InterfaceData; - - TI_DbgPrint(DEBUG_TCPIF,("called for type %d\n", FindType)); - - if( !ReqAddr ) { - TI_DbgPrint(DEBUG_TCPIF,("no addr or no ifaddr (%x)\n", ReqAddr)); - return NULL; + IP_PACKET Packet = { 0 }; + IP_ADDRESS RemoteAddress, LocalAddress; + PIPv4_HEADER Header; + UINT i; + struct pbuf *p1; + + /* The caller frees the pbuf struct */ + + DbgPrint("Sending data out on %c%c\n", netif->name[0], netif->name[1]); + + 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 EINVAL; } - Destination.Type = IP_ADDRESS_V4; - Destination.Address.IPv4Address = addr_in->sin_addr.s_addr; - - TI_DbgPrint(DEBUG_TCPIF,("Address is %x\n", addr_in->sin_addr.s_addr)); - - NCE = RouteGetRouteToDestination(&Destination); - if (!NCE) return NULL; - - InterfaceData = TCPGetInterfaceData(NCE->Interface); - - addr_in = (struct sockaddr_in *) - InterfaceData->ifa_addr; - - TI_DbgPrint(DEBUG_TCPIF,("returning addr %x\n", addr_in->sin_addr.s_addr)); - - return InterfaceData; + if (!(NCE = RouteGetRouteToDestination(&RemoteAddress))) + { + return EINVAL; + } + + NdisStatus = AllocatePacketWithBuffer(&Packet.NdisPacket, NULL, p->tot_len); + if (NdisStatus != NDIS_STATUS_SUCCESS) + { + return ENOBUFS; + } + + GetDataPtr(Packet.NdisPacket, 0, (PCHAR*)&Packet.Header, &Packet.ContigSize); + + for (i = 0, p1 = p; i < p->tot_len; i += p1->len, p1 = p1->next) + { + ASSERT(p1); + RtlCopyMemory(((PUCHAR)Packet.Header) + i, p1->payload, p1->len); + } + + Packet.HeaderSize = sizeof(IPv4_HEADER); + Packet.TotalSize = p->tot_len; + Packet.SrcAddr = LocalAddress; + Packet.DstAddr = RemoteAddress; + + if (!NT_SUCCESS(IPSendDatagram(&Packet, NCE, TCPPacketSendComplete, NULL))) + { + FreeNdisPacket(Packet.NdisPacket); + return EINVAL; + } + + 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); + } +} diff --git a/lib/drivers/ip/transport/tcp/tcp.c b/lib/drivers/ip/transport/tcp/tcp.c index e980f6b1e15..90350d31fad 100644 --- a/lib/drivers/ip/transport/tcp/tcp.c +++ b/lib/drivers/ip/transport/tcp/tcp.c @@ -14,237 +14,22 @@ LONG TCP_IPIdentification = 0; static BOOLEAN TCPInitialized = FALSE; -static NPAGED_LOOKASIDE_LIST TCPSegmentList; PORT_SET TCPPorts; -CLIENT_DATA ClientInfo; -VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection) -{ - PTDI_BUCKET Bucket; - PLIST_ENTRY Entry; - NTSTATUS Status; - PIRP Irp; - PMDL Mdl; - KIRQL OldIrql; - PTCP_COMPLETION_ROUTINE Complete; +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "lwip/arch.h" - if (ClientInfo.Unlocked) - LockObjectAtDpcLevel(Connection); - - TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n", - Connection, Connection->SocketContext)); - - /* Things that can happen when we try the initial connection */ - if( Connection->SignalState & (SEL_CONNECT | SEL_FIN) ) { - while (!IsListEmpty(&Connection->ConnectRequest)) { - Entry = RemoveHeadList( &Connection->ConnectRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - Bucket->Status = (Connection->SignalState & SEL_CONNECT) ? STATUS_SUCCESS : STATUS_CANCELLED; - Bucket->Information = 0; - - InsertTailList(&Connection->CompletionQueue, &Bucket->Entry); - } - } - - if( Connection->SignalState & (SEL_ACCEPT | SEL_FIN) ) { - /* Handle readable on a listening socket -- - * TODO: Implement filtering - */ - TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n", - Connection, - IsListEmpty(&Connection->ListenRequest) ? - "empty" : "nonempty")); - - while (!IsListEmpty(&Connection->ListenRequest)) { - PIO_STACK_LOCATION IrpSp; - - Entry = RemoveHeadList( &Connection->ListenRequest ); - - Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); - - Irp = Bucket->Request.RequestContext; - IrpSp = IoGetCurrentIrpStackLocation( Irp ); - - TI_DbgPrint(DEBUG_TCP,("Getting the socket\n")); - - Status = TCPServiceListeningSocket - ( Connection->AddressFile->Listener, - Bucket->AssociatedEndpoint, - (PTDI_REQUEST_KERNEL)&IrpSp->Parameters ); - - TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n")); - - if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) { - InsertHeadList( &Connection->ListenRequest, &Bucket->Entry ); - break; - } else { - Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status; - Bucket->Information = 0; - DereferenceObject(Bucket->AssociatedEndpoint); - - InsertTailList(&Connection->CompletionQueue, &Bucket->Entry); - } - } - } - - /* Things that happen after we're connected */ - if( Connection->SignalState & (SEL_READ | SEL_FIN) ) { - TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n", - IsListEmpty(&Connection->ReceiveRequest) ? - "empty" : "nonempty")); - - while (!IsListEmpty(&Connection->ReceiveRequest)) { - OSK_UINT RecvLen = 0, Received = 0; - PVOID RecvBuffer = 0; - - Entry = RemoveHeadList( &Connection->ReceiveRequest ); - - 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, &RecvBuffer, &RecvLen ); - - TI_DbgPrint(DEBUG_TCP, - ("Reading %d bytes to %x\n", RecvLen, RecvBuffer)); - - TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection)); - TI_DbgPrint - (DEBUG_TCP, - ("Connection->SocketContext: %x\n", - Connection->SocketContext)); - TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer)); - - Status = TCPTranslateError - ( OskitTCPRecv( Connection->SocketContext, - RecvBuffer, - RecvLen, - &Received, - 0 ) ); - - TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received)); - - if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) { - InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry ); - break; - } else { - TI_DbgPrint(DEBUG_TCP, - ("Completing Receive request: %x %x\n", - Bucket->Request, Status)); - - Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status; - Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Received : 0; - - InsertTailList(&Connection->CompletionQueue, &Bucket->Entry); - } - } - } - if( Connection->SignalState & (SEL_WRITE | SEL_FIN) ) { - TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n", - IsListEmpty(&Connection->SendRequest) ? - "empty" : "nonempty")); - - while (!IsListEmpty(&Connection->SendRequest)) { - OSK_UINT SendLen = 0, Sent = 0; - PVOID SendBuffer = 0; - - Entry = RemoveHeadList( &Connection->SendRequest ); - - 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 - ( OskitTCPSend( Connection->SocketContext, - SendBuffer, - SendLen, - &Sent, - 0 ) ); - - TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent)); - - if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) { - InsertHeadList( &Connection->SendRequest, &Bucket->Entry ); - break; - } else { - TI_DbgPrint(DEBUG_TCP, - ("Completing Send request: %x %x\n", - Bucket->Request, Status)); - - Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status; - Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Sent : 0; - - InsertTailList(&Connection->CompletionQueue, &Bucket->Entry); - } - } - } - - ReferenceObject(Connection); - if (ClientInfo.Unlocked) - { - UnlockObjectFromDpcLevel(Connection); - KeReleaseSpinLock(&ClientInfo.Lock, ClientInfo.OldIrql); - } - else - { - UnlockObject(Connection, Connection->OldIrql); - } - - while ((Entry = ExInterlockedRemoveHeadList(&Connection->CompletionQueue, - &Connection->Lock))) - { - Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); - Complete = Bucket->Request.RequestNotifyObject; - - Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); - - ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG); - } - - if (!ClientInfo.Unlocked) - { - LockObject(Connection, &OldIrql); - } - else - { - KeAcquireSpinLock(&ClientInfo.Lock, &ClientInfo.OldIrql); - } - DereferenceObject(Connection); - - /* If the socket is dead, remove the reference we added for oskit */ - if (Connection->SignalState & SEL_FIN) - { - Connection->SocketContext = NULL; - DereferenceObject(Connection); - } -} +#include "rosip.h" VOID ConnectionFree(PVOID Object) { PCONNECTION_ENDPOINT Connection = Object; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n")); + + DbgPrint("CONNECTION ENDPOINT: Freeing 0x%x\n", Object); TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql); RemoveEntryList(&Connection->ListEntry); @@ -270,13 +55,11 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) { InitializeListHead(&Connection->ListenRequest); InitializeListHead(&Connection->ReceiveRequest); InitializeListHead(&Connection->SendRequest); - InitializeListHead(&Connection->CompletionQueue); /* Save client context pointer */ Connection->ClientContext = ClientContext; - /* Add an extra reference for oskit */ - Connection->RefCount = 2; + Connection->RefCount = 1; Connection->Free = ConnectionFree; /* Add connection endpoint to global list */ @@ -298,16 +81,11 @@ NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection, "Proto %d\n", Connection, Family, Type, Proto)); - Status = TCPTranslateError( OskitTCPSocket( Connection, - &Connection->SocketContext, - Family, - Type, - Proto ) ); - - ASSERT_KM_POINTER(Connection->SocketContext); - - TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n", - Connection->SocketContext)); + Connection->SocketContext = LibTCPSocket(Connection); + if (Connection->SocketContext) + Status = STATUS_SUCCESS; + else + Status = STATUS_INSUFFICIENT_RESOURCES; UnlockObject(Connection, OldIrql); @@ -323,110 +101,13 @@ VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket) * This is the low level interface for receiving TCP data */ { - KIRQL OldIrql; + DbgPrint("Got packet from network stack\n"); - TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n", + TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n", IPPacket->TotalSize, IPPacket->HeaderSize)); - - KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql); - ClientInfo.Unlocked = TRUE; - ClientInfo.OldIrql = OldIrql; - - OskitTCPReceiveDatagram( IPPacket->Header, - IPPacket->TotalSize, - IPPacket->HeaderSize ); - - ClientInfo.Unlocked = FALSE; - KeReleaseSpinLock(&ClientInfo.Lock, OldIrql); -} - -/* event.c */ -int TCPSocketState( void *ClientData, - void *WhichSocket, - void *WhichConnection, - OSK_UINT NewState ); - -int TCPPacketSend( void *ClientData, - OSK_PCHAR Data, - OSK_UINT Len ); - -POSK_IFADDR TCPFindInterface( void *ClientData, - OSK_UINT AddrType, - OSK_UINT FindType, - OSK_SOCKADDR *ReqAddr ); - -NTSTATUS TCPMemStartup( void ); -void *TCPMalloc( void *ClientData, - OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line ); -void TCPFree( void *ClientData, - void *data, OSK_PCHAR file, OSK_UINT line ); -void TCPMemShutdown( void ); - -OSKITTCP_EVENT_HANDLERS EventHandlers = { - NULL, /* Client Data */ - TCPSocketState, /* SocketState */ - TCPPacketSend, /* PacketSend */ - TCPFindInterface, /* FindInterface */ - TCPMalloc, /* Malloc */ - TCPFree, /* Free */ - NULL, /* Sleep */ - NULL, /* Wakeup */ -}; - -static KEVENT TimerLoopEvent; -static HANDLE TimerThreadHandle; - -/* - * We are running 2 timers here, one with a 200ms interval (fast) and the other - * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600, - * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the - * "slow" events at 500 and 1000. - */ -static VOID NTAPI -TimerThread(PVOID Context) -{ - LARGE_INTEGER Timeout; - NTSTATUS Status; - unsigned Current, NextFast, NextSlow, Next; - - Current = 0; - Next = 0; - NextFast = 0; - NextSlow = 0; - while ( 1 ) { - if (Next == NextFast) { - NextFast += 2; - } - if (Next == NextSlow) { - NextSlow += 5; - } - Next = min(NextFast, NextSlow); - Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */ - Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode, - FALSE, &Timeout); - if (Status != STATUS_TIMEOUT) { - PsTerminateSystemThread(Status); - } - - TimerOskitTCP( Next == NextFast, Next == NextSlow ); - - Current = Next; - if (10 <= Current) { - Current = 0; - Next = 0; - NextFast = 0; - NextSlow = 0; - } - } -} - -static VOID -StartTimer(VOID) -{ - KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE); - PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, - TimerThread, NULL); + + LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize); } NTSTATUS TCPStartup(VOID) @@ -438,37 +119,17 @@ NTSTATUS TCPStartup(VOID) { NTSTATUS Status; - Status = TCPMemStartup(); - if ( ! NT_SUCCESS(Status) ) { - return Status; - } - Status = PortsStartup( &TCPPorts, 1, 0xfffe ); if( !NT_SUCCESS(Status) ) { - TCPMemShutdown(); return Status; } - - KeInitializeSpinLock(&ClientInfo.Lock); - ClientInfo.Unlocked = FALSE; - - RegisterOskitTCPEventHandlers( &EventHandlers ); - InitOskitTCP(); - + + /* Initialize our IP library */ + LibIPInitialize(); + /* Register this protocol with IP layer */ IPRegisterProtocol(IPPROTO_TCP, TCPReceive); - - ExInitializeNPagedLookasideList( - &TCPSegmentList, /* Lookaside list */ - NULL, /* Allocate routine */ - NULL, /* Free routine */ - 0, /* Flags */ - sizeof(TCP_SEGMENT), /* Size of each entry */ - 'SPCT', /* Tag */ - 0); /* Depth */ - - StartTimer(); - + TCPInitialized = TRUE; return STATUS_SUCCESS; @@ -482,59 +143,50 @@ NTSTATUS TCPShutdown(VOID) * Status of operation */ { - LARGE_INTEGER WaitForThread; - if (!TCPInitialized) return STATUS_SUCCESS; - - WaitForThread.QuadPart = -2500000; /* 250 ms */ - KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE); - ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread); + + LibIPShutdown(); /* Deregister this protocol with IP layer */ IPRegisterProtocol(IPPROTO_TCP, NULL); - ExDeleteNPagedLookasideList(&TCPSegmentList); - TCPInitialized = FALSE; - DeinitOskitTCP(); - PortsShutdown( &TCPPorts ); - TCPMemShutdown(); - return STATUS_SUCCESS; } -NTSTATUS TCPTranslateError( int OskitError ) { +NTSTATUS TCPTranslateError( err_t err ) { NTSTATUS Status; - switch( OskitError ) { - case 0: Status = STATUS_SUCCESS; break; - case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break; - case OSK_EADDRINUSE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; - case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break; - case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break; - case OSK_ECONNRESET: Status = STATUS_REMOTE_DISCONNECT; break; - case OSK_ECONNABORTED: Status = STATUS_LOCAL_DISCONNECT; break; - case OSK_EWOULDBLOCK: - case OSK_EINPROGRESS: Status = STATUS_PENDING; break; - case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break; - case OSK_ENOMEM: - case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break; - case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break; - case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break; - case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break; - case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break; - case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break; - default: - DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError); - Status = STATUS_INVALID_CONNECTION; - break; + switch (err) + { + case ERR_OK: Status = STATUS_SUCCESS; break; //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_HOST_UNREACHABLE; break; //-4 + case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-5 + case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-6 + case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-7 + case ERR_CONN: Status = STATUS_UNSUCCESSFUL; break; //-8 (FIXME) + case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-9 + case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-10 + case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-11 + case ERR_IF: Status = STATUS_NETWORK_UNREACHABLE; break; //-12 + case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-13 (FIXME) + case ERR_INPROGRESS: Status = STATUS_PENDING; break; //-14 + default: + DbgPrint("Invalid error value: %d\n", err); + ASSERT(FALSE); + Status = STATUS_UNSUCCESSFUL; + break; } - - TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status)); + + DbgPrint("TCPTranslateError: %d -> %x\n", (unsigned int)err, Status); + return Status; } @@ -545,7 +197,7 @@ NTSTATUS TCPConnect PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; - SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 }; + struct ip_addr bindaddr, connaddr; IP_ADDRESS RemoteAddress; USHORT RemotePort; PTDI_BUCKET Bucket; @@ -570,9 +222,6 @@ NTSTATUS TCPConnect RemoteAddress.Address.IPv4Address, RemotePort)); - AddressToConnect.sin_family = AF_INET; - AddressToBind = AddressToConnect; - LockObject(Connection, &OldIrql); if (!Connection->AddressFile) @@ -589,28 +238,27 @@ NTSTATUS TCPConnect return STATUS_NETWORK_UNREACHABLE; } - AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address; + bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address; } else { - AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address; + bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address; } - Status = TCPTranslateError - ( OskitTCPBind( Connection->SocketContext, - &AddressToBind, - sizeof(AddressToBind) ) ); + Status = TCPTranslateError(LibTCPBind(Connection->SocketContext, + &bindaddr, + Connection->AddressFile->Port)); + + DbgPrint("LibTCPBind: 0x%x\n", Status); if (NT_SUCCESS(Status)) { - memcpy( &AddressToConnect.sin_addr, - &RemoteAddress.Address.IPv4Address, - sizeof(AddressToConnect.sin_addr) ); - AddressToConnect.sin_port = RemotePort; - - Status = TCPTranslateError - ( OskitTCPConnect( Connection->SocketContext, - &AddressToConnect, - sizeof(AddressToConnect) ) ); + connaddr.addr = RemoteAddress.Address.IPv4Address; + + Status = TCPTranslateError(LibTCPConnect(Connection->SocketContext, + &connaddr, + RemotePort)); + + DbgPrint("LibTCPConnect: 0x%x\n", Status); if (Status == STATUS_PENDING) { @@ -648,10 +296,20 @@ NTSTATUS TCPDisconnect LockObject(Connection, &OldIrql); if (Flags & TDI_DISCONNECT_RELEASE) - Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext)); + { + /* FIXME */ + LibTCPClose(Connection->SocketContext); + } if ((Flags & TDI_DISCONNECT_ABORT) || !Flags) - Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD)); + { + /* FIXME */ + LibTCPClose(Connection->SocketContext); + } + + Status = STATUS_SUCCESS; + + DbgPrint("LibTCPClose: %x\n", Status); UnlockObject(Connection, OldIrql); @@ -664,7 +322,6 @@ NTSTATUS TCPClose ( PCONNECTION_ENDPOINT Connection ) { KIRQL OldIrql; - NTSTATUS Status; PVOID Socket; PADDRESS_FILE AddressFile = NULL; PCONNECTION_ENDPOINT AddressConnection = NULL; @@ -676,21 +333,9 @@ NTSTATUS TCPClose /* Don't try to close again if the other side closed us already */ if (Socket) { - /* We need to close here otherwise oskit will never indicate - * SEL_FIN and we will never fully close the connection */ - Status = TCPTranslateError( OskitTCPClose( Socket ) ); - - if (!NT_SUCCESS(Status)) - { - Connection->SocketContext = Socket; - UnlockObject(Connection, OldIrql); - return Status; - } - } - else - { - /* We are already closed by the other end so return success */ - Status = STATUS_SUCCESS; + LibTCPClose(Socket); + + FlushAllQueues(Connection, STATUS_CANCELLED); } if (Connection->AddressFile) @@ -715,7 +360,7 @@ NTSTATUS TCPClose if (AddressFile) DereferenceObject(AddressFile); - return Status; + return STATUS_SUCCESS; } NTSTATUS TCPReceiveData @@ -726,57 +371,32 @@ NTSTATUS TCPReceiveData ULONG ReceiveFlags, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { - PVOID DataBuffer; - UINT DataLen, Received = 0; - NTSTATUS Status; PTDI_BUCKET Bucket; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n", ReceiveLength, Connection->SocketContext)); - NdisQueryBuffer( Buffer, &DataBuffer, &DataLen ); - - TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen)); - LockObject(Connection, &OldIrql); - - Status = TCPTranslateError - ( OskitTCPRecv - ( Connection->SocketContext, - DataBuffer, - DataLen, - &Received, - ReceiveFlags ) ); - - TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received)); - - /* Keep this request around ... there was no data yet */ - if( Status == STATUS_PENDING ) { - /* Freed in TCPSocketState */ - Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG ); - if( !Bucket ) { - TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n")); - UnlockObject(Connection, OldIrql); - return STATUS_NO_MEMORY; - } - - Bucket->Request.RequestNotifyObject = Complete; - Bucket->Request.RequestContext = Context; - *BytesReceived = 0; - - InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry ); - TI_DbgPrint(DEBUG_TCP,("Queued read irp\n")); - } else { - TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received)); - *BytesReceived = Received; + + /* Freed in TCPSocketState */ + Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG ); + if( !Bucket ) { + TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n")); + UnlockObject(Connection, OldIrql); + return STATUS_NO_MEMORY; } + + Bucket->Request.RequestNotifyObject = Complete; + Bucket->Request.RequestContext = Context; + *BytesReceived = 0; + + InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry ); + TI_DbgPrint(DEBUG_TCP,("Queued read irp\n")); UnlockObject(Connection, OldIrql); - TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status)); - - return Status; + return STATUS_PENDING; } NTSTATUS TCPSendData @@ -787,7 +407,6 @@ NTSTATUS TCPSendData ULONG Flags, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { - UINT Sent = 0; NTSTATUS Status; PTDI_BUCKET Bucket; KIRQL OldIrql; @@ -801,12 +420,13 @@ NTSTATUS TCPSendData TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n", Connection->SocketContext)); - Status = TCPTranslateError - ( OskitTCPSend( Connection->SocketContext, - (OSK_PCHAR)BufferData, SendLength, - &Sent, 0 ) ); + Status = TCPTranslateError(LibTCPSend(Connection->SocketContext, + BufferData, + SendLength)); + + DbgPrint("LibTCPSend: 0x%x\n", Status); - TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent)); + TI_DbgPrint(DEBUG_TCP,("Send: %x, %d\n", Status, SendLength)); /* Keep this request around ... there was no data yet */ if( Status == STATUS_PENDING ) { @@ -825,8 +445,8 @@ NTSTATUS TCPSendData InsertTailList( &Connection->SendRequest, &Bucket->Entry ); TI_DbgPrint(DEBUG_TCP,("Queued write irp\n")); } else { - TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent)); - *BytesSent = Sent; + TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, SendLength)); + *BytesSent = SendLength; } UnlockObject(Connection, OldIrql); @@ -855,28 +475,35 @@ NTSTATUS TCPGetSockAddress ( PCONNECTION_ENDPOINT Connection, PTRANSPORT_ADDRESS Address, BOOLEAN GetRemote ) { - OSK_UINT LocalAddress, RemoteAddress; - OSK_UI16 LocalPort, RemotePort; PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address; + struct ip_addr ipaddr; NTSTATUS Status; KIRQL OldIrql; - - LockObject(Connection, &OldIrql); - - Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext, - &LocalAddress, &LocalPort, - &RemoteAddress, &RemotePort)); - - UnlockObject(Connection, OldIrql); - - if (!NT_SUCCESS(Status)) - return Status; - + AddressIP->TAAddressCount = 1; AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; - AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort; - AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress; + + 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; + + DbgPrint("LibTCPGetXXXName: 0x%x\n", Status); return Status; } diff --git a/lib/drivers/lwip/lwip.rbuild b/lib/drivers/lwip/lwip.rbuild new file mode 100755 index 00000000000..f19417b7f82 --- /dev/null +++ b/lib/drivers/lwip/lwip.rbuild @@ -0,0 +1,37 @@ + + + + src/include + src/include/ipv4 + + rosip.c + rostcp.c + rosmem.c + sys_arch.c + + err.c + netbuf.c + netifapi.c + tcpip.c + + + init.c + mem.c + memp.c + netif.c + pbuf.c + stats.c + sys.c + tcp_in.c + tcp_out.c + tcp.c + + inet_chksum.c + inet.c + ip.c + ip_addr.c + ip_frag.c + + + + diff --git a/lib/drivers/lwip/src/include/arch/bpstruct.h b/lib/drivers/lwip/src/include/arch/bpstruct.h new file mode 100755 index 00000000000..1d81e3f7b89 --- /dev/null +++ b/lib/drivers/lwip/src/include/arch/bpstruct.h @@ -0,0 +1 @@ +#pragma pack(push,1) diff --git a/lib/drivers/lwip/src/include/arch/cc.h b/lib/drivers/lwip/src/include/arch/cc.h new file mode 100755 index 00000000000..0709ed13732 --- /dev/null +++ b/lib/drivers/lwip/src/include/arch/cc.h @@ -0,0 +1,63 @@ +/* ReactOS-Specific lwIP binding header - by Cameron Gutman */ + +#include + +#define LWIP_PROVIDE_ERRNO + +/* ROS-specific mem defs */ +void * +malloc(size_t size); + +void * +calloc(size_t count, size_t size); + +void +free(void *mem); + +void * +realloc(void *mem, size_t size); + +#define mem_realloc(_m_, _s_) realloc(_m_, _s_) + +/* Unsigned int types */ +typedef unsigned char u8_t; +typedef unsigned short u16_t; +typedef unsigned long u32_t; + +/* Signed int types */ +typedef signed char s8_t; +typedef signed short s16_t; +typedef signed long s32_t; + +/* Memory pointer */ +typedef u32_t mem_ptr_t; + +/* Printf/DPRINT formatters */ +#define U16_F "hu" +#define S16_F "hd" +#define X16_F "hx" +#define U32_F "lu" +#define S32_F "ld" +#define X32_F "lx" + +/* Endianness */ +#define BYTE_ORDER LITTLE_ENDIAN + +/* Checksum calculation algorithm choice */ +#define LWIP_CHKSUM_ALGORITHM 3 + +/* Diagnostics */ +#define LWIP_PLATFORM_DIAG(x) DbgPrint(x) +#define LWIP_PLATFORM_ASSERT(x) ASSERTMSG(x, FALSE) + +/* Synchronization */ +#define SYS_ARCH_DECL_PROTECT(lev) \ + sys_prot_t lev; \ + sys_arch_decl_protect(&lev) +#define SYS_ARCH_PROTECT(lev) sys_arch_protect(&lev) +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(&lev) + +/* Compiler hints for packing structures */ +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_USE_INCLUDES + diff --git a/lib/drivers/lwip/src/include/arch/epstruct.h b/lib/drivers/lwip/src/include/arch/epstruct.h new file mode 100755 index 00000000000..65898b54bb5 --- /dev/null +++ b/lib/drivers/lwip/src/include/arch/epstruct.h @@ -0,0 +1 @@ +#pragma pack(pop) diff --git a/lib/drivers/lwip/src/include/arch/perf.h b/lib/drivers/lwip/src/include/arch/perf.h new file mode 100755 index 00000000000..3e00e34ec03 --- /dev/null +++ b/lib/drivers/lwip/src/include/arch/perf.h @@ -0,0 +1,4 @@ +/* ReactOS-Specific lwIP binding header - by Cameron Gutman */ + +#define PERF_START +#define PERF_STOP \ No newline at end of file diff --git a/lib/drivers/lwip/src/include/arch/sys_arch.h b/lib/drivers/lwip/src/include/arch/sys_arch.h new file mode 100755 index 00000000000..1d1582c7a9c --- /dev/null +++ b/lib/drivers/lwip/src/include/arch/sys_arch.h @@ -0,0 +1,45 @@ +/* ReactOS-Specific lwIP binding header - by Cameron Gutman */ + +/* Implmentation specific structs */ +typedef PRKEVENT sys_sem_t; + +typedef struct _sys_mbox_t +{ + KSPIN_LOCK Lock; + LIST_ENTRY ListHead; + KEVENT Event; +} *sys_mbox_t; + +typedef struct _sys_prot_t +{ + KSPIN_LOCK Lock; + KIRQL OldIrql; +} sys_prot_t; + +typedef u32_t sys_thread_t; + +typedef struct _LWIP_MESSAGE_CONTAINER +{ + PVOID Message; + LIST_ENTRY ListEntry; +} LWIP_MESSAGE_CONTAINER, *PLWIP_MESSAGE_CONTAINER; + +#define sys_jiffies() sys_now() + +/* NULL definitions */ +#define SYS_MBOX_NULL NULL +#define SYS_SEM_NULL NULL +#define SYS_ARCH_NULL NULL + +void +sys_arch_protect(sys_prot_t *lev); + +void +sys_arch_unprotect(sys_prot_t *lev); + +void +sys_arch_decl_protect(sys_prot_t *lev); + +void +sys_shutdown(void); + diff --git a/lib/drivers/lwip/src/include/lwipopts.h b/lib/drivers/lwip/src/include/lwipopts.h new file mode 100755 index 00000000000..02a0b2a7fee --- /dev/null +++ b/lib/drivers/lwip/src/include/lwipopts.h @@ -0,0 +1,194 @@ +/* + ------------------------------------ + ---------- Memory options ---------- + ------------------------------------ +*/ + +/* This combo allows us to implement malloc, free, and realloc ourselves */ +#define MEM_LIBC_MALLOC 1 +#define MEMP_MEM_MALLOC 1 + +#define MEM_ALIGNMENT 4 + +#define LWIP_ARP 0 + +#define ARP_QUEUEING 0 + +#define IP_FORWARD 0 + +#define IP_REASS_MAX_PBUFS 0xFFFFFFFF + +#define IP_DEFAULT_TTL 128 + +#define IP_SOF_BROADCAST 1 + +#define IP_SOF_BROADCAST_RECV 1 + +#define LWIP_ICMP 0 + +#define LWIP_RAW 0 + +#define LWIP_DHCP 0 + +#define LWIP_AUTOIP 0 + +#define LWIP_SNMP 0 + +#define LWIP_IGMP 0 + +#define LWIP_DNS 0 + +#define LWIP_UDP 0 + +#define LWIP_UDPLITE 0 + +#define LWIP_TCP 1 + +#define TCP_QUEUE_OOSEQ 1 + +#define TCP_MSS 1024 + +#define TCP_SND_BUF (TCP_MSS * 8) + +#define TCP_SND_QUEUELEN (8 * (TCP_SND_BUF / TCP_MSS)) + +#define TCP_SNDLOWAT TCP_MSS + +#define TCP_WND 0xFFFF + +#define TCP_MAXRTX 12 + +#define TCP_SYNMAXRTX 4 + +#define TCP_LISTEN_BACKLOG 1 + +#define LWIP_TCP_TIMESTAMPS 1 + +#define LWIP_CALLBACK_API 1 + +#define LWIP_NETIF_API 1 + +#define LWIP_SOCKET 0 + +#define LWIP_NETCONN 0 + +#define LWIP_NETIF_HWADDRHINT 0 + +#define LWIP_STATS 0 + +#define ICMP_STATS 0 + +#define PPP_SUPPORT 0 + +#define PPPOE_SUPPORT 0 + +#define PPPOS_SUPPORT 0 + +/* + --------------------------------------- + ---------- Debugging options ---------- + --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#define NETIF_DEBUG LWIP_DBG_OFF + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#define PBUF_DEBUG LWIP_DBG_OFF + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#define INET_DEBUG LWIP_DBG_OFF + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#define IP_DEBUG LWIP_DBG_OFF + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#define IP_REASS_DEBUG LWIP_DBG_OFF + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#define MEM_DEBUG LWIP_DBG_OFF + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#define MEMP_DEBUG LWIP_DBG_OFF + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#define SYS_DEBUG LWIP_DBG_OFF + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#define TCP_DEBUG LWIP_DBG_OFF + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#define TCP_INPUT_DEBUG LWIP_DBG_OFF + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#define TCP_FR_DEBUG LWIP_DBG_OFF + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#define TCP_RTO_DEBUG LWIP_DBG_OFF + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#define TCP_CWND_DEBUG LWIP_DBG_OFF + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#define TCP_WND_DEBUG LWIP_DBG_OFF + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#define TCP_RST_DEBUG LWIP_DBG_OFF + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#define TCP_QLEN_DEBUG LWIP_DBG_OFF + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#define TCPIP_DEBUG LWIP_DBG_OFF \ No newline at end of file diff --git a/lib/drivers/lwip/src/include/rosip.h b/lib/drivers/lwip/src/include/rosip.h new file mode 100755 index 00000000000..8dba52daa21 --- /dev/null +++ b/lib/drivers/lwip/src/include/rosip.h @@ -0,0 +1,31 @@ +#ifndef _ROS_IP_H_ +#define _ROS_IP_H_ + +#include "lwip/tcp.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +/* External TCP event handlers */ +extern void TCPConnectEventHandler(void *arg, err_t err); +extern void TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb); +extern void TCPSendEventHandler(void *arg, u16_t space); +extern void TCPFinEventHandler(void *arg, err_t err); +extern u32_t TCPRecvEventHandler(void *arg, struct pbuf *p); + +/* TCP functions */ +struct tcp_pcb *LibTCPSocket(void *arg); +err_t LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port); +struct tcp_pcb *LibTCPListen(struct tcp_pcb *pcb, u8_t backlog); +err_t LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len); +err_t LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port); +err_t LibTCPClose(struct tcp_pcb *pcb); +err_t LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port); +err_t LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port); +void LibTCPAccept(struct tcp_pcb *pcb, void *arg); + +/* IP functions */ +void LibIPInsertPacket(void *ifarg, void *data, u32_t size); +void LibIPInitialize(void); +void LibIPShutdown(void); + +#endif \ No newline at end of file diff --git a/lib/drivers/lwip/src/rosip.c b/lib/drivers/lwip/src/rosip.c new file mode 100755 index 00000000000..1b5b41c1b25 --- /dev/null +++ b/lib/drivers/lwip/src/rosip.c @@ -0,0 +1,45 @@ +#include "lwip/sys.h" +#include "lwip/tcpip.h" + +#include "rosip.h" + +#include + +void +LibIPInsertPacket(void *ifarg, + void *data, + u32_t size) +{ + struct pbuf *p, *p1; + u32_t i; + + ASSERT(ifarg); + ASSERT(data); + ASSERT(size > 0); + + p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_POOL); + if (p) + { + for (i = 0, p1 = p; i < size; i += p1->len, p1 = p1->next) + { + ASSERT(p1); + RtlCopyMemory(p1->payload, ((PUCHAR)data) + i, p1->len); + } + + ((struct netif *)ifarg)->input(p, ifarg); + } +} + +void +LibIPInitialize(void) +{ + /* This completes asynchronously */ + tcpip_init(NULL, NULL); +} + +void +LibIPShutdown(void) +{ + /* This is synchronous */ + sys_shutdown(); +} \ No newline at end of file diff --git a/lib/drivers/lwip/src/rosmem.c b/lib/drivers/lwip/src/rosmem.c new file mode 100755 index 00000000000..53673c7d9e7 --- /dev/null +++ b/lib/drivers/lwip/src/rosmem.c @@ -0,0 +1,38 @@ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/mem.h" + +#define LWIP_TAG 'PIwl' + +void * +malloc(mem_size_t size) +{ + return ExAllocatePoolWithTag(NonPagedPool, size, LWIP_TAG); +} + +void * +calloc(mem_size_t count, mem_size_t size) +{ + void *mem = malloc(count * size); + + if (!mem) return NULL; + + RtlZeroMemory(mem, count * size); + + return mem; +} + +void +free(void *mem) +{ + ExFreePoolWithTag(mem, LWIP_TAG); +} + +void * +realloc(void *mem, size_t size) +{ + free(mem); + return malloc(size); +} \ No newline at end of file diff --git a/lib/drivers/lwip/src/rostcp.c b/lib/drivers/lwip/src/rostcp.c new file mode 100755 index 00000000000..a7678ed8e2b --- /dev/null +++ b/lib/drivers/lwip/src/rostcp.c @@ -0,0 +1,581 @@ +#include "lwip/sys.h" +#include "lwip/tcpip.h" + +#include "rosip.h" + +#include + +/* The way that lwIP does multi-threading is really not ideal for our purposes but + * we best go along with it unless we want another unstable TCP library. lwIP uses + * a thread called the "tcpip thread" which is the only one allowed to call raw API + * functions. Since this is the case, for each of our LibTCP* functions, we queue a request + * for a callback to "tcpip thread" which calls our LibTCP*Callback functions. Yes, this is + * a lot of unnecessary thread swapping and it could definitely be faster, but I don't want + * to going messing around in lwIP because I have no desire to create another mess like oskittcp */ + +extern KEVENT TerminationEvent; + +static +BOOLEAN +WaitForEventSafely(PRKEVENT Event) +{ + PVOID WaitObjects[] = {Event, &TerminationEvent}; + + if (KeWaitForMultipleObjects(2, + WaitObjects, + WaitAny, + Executive, + KernelMode, + FALSE, + NULL, + NULL) == STATUS_WAIT_0) + { + /* Signalled by the caller's event */ + return TRUE; + } + else /* if KeWaitForMultipleObjects() == STATUS_WAIT_1 */ + { + /* Signalled by our termination event */ + return FALSE; + } +} + +static +err_t +InternalSendEventHandler(void *arg, struct tcp_pcb *pcb, u16_t space) +{ + DbgPrint("SendEvent(0x%x, 0x%x, %d)\n", arg, pcb, (unsigned int)space); + + /* Make sure the socket didn't get closed */ + if (!arg) return ERR_OK; + + TCPSendEventHandler(arg, space); + + return ERR_OK; +} + +static +err_t +InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ + u32_t len; + + DbgPrint("RecvEvent(0x%x, 0x%x, 0x%x, %d)\n", arg, pcb, p, (unsigned int)err); + + /* Make sure the socket didn't get closed */ + if (!arg) + { + if (p) pbuf_free(p); + return ERR_OK; + } + + if (!p) + { + TCPFinEventHandler(arg, ERR_OK); + } + else + { + DbgPrint("RECV - p:0x%x p->payload:0x%x p->len:%d p->tot_len:%d\n", p, p->payload, p->len, p->tot_len); + + if (err == ERR_OK) + { + len = TCPRecvEventHandler(arg, p); + if (len != 0) + { + tcp_recved(pcb, len); + + pbuf_free(p); + + return ERR_OK; + } + else + { + /* We want lwIP to store the pbuf on its queue for later */ + return ERR_TIMEOUT; + } + } + else + { + pbuf_free(p); + } + } + + return ERR_OK; +} + +static +err_t +InternalAcceptEventHandler(void *arg, struct tcp_pcb *newpcb, err_t err) +{ + DbgPrint("AcceptEvent(0x%x, 0x%x, %d)\n", arg, newpcb, (unsigned int)err); + + /* Make sure the socket didn't get closed */ + if (!arg) return ERR_ABRT; + + TCPAcceptEventHandler(arg, newpcb); + + /* Set in LibTCPAccept (called from TCPAcceptEventHandler) */ + if (newpcb->callback_arg) + return ERR_OK; + else + return ERR_ABRT; +} + +static +err_t +InternalConnectEventHandler(void *arg, struct tcp_pcb *pcb, err_t err) +{ + DbgPrint("ConnectEvent(0x%x, 0x%x, %d)\n", arg, pcb, (unsigned int)err); + + /* Make sure the socket didn't get closed */ + if (!arg) return ERR_OK; + + TCPConnectEventHandler(arg, err); + + tcp_recv(pcb, InternalRecvEventHandler); + + return ERR_OK; +} + +static +void +InternalErrorEventHandler(void *arg, err_t err) +{ + DbgPrint("ErrorEvent(0x%x, %d)\n", arg, (unsigned int)err); + + /* Make sure the socket didn't get closed */ + if (!arg) return; + + TCPFinEventHandler(arg, err); +} + +struct socket_callback_msg +{ + /* Synchronization */ + KEVENT Event; + + /* Input */ + PVOID Arg; + + /* Output */ + PVOID NewPcb; +}; + +static +void +LibTCPSocketCallback(void *arg) +{ + struct socket_callback_msg *msg = arg; + + ASSERT(msg); + + msg->NewPcb = tcp_new(); + + if (msg->NewPcb) + { + tcp_arg(msg->NewPcb, msg->Arg); + tcp_err(msg->NewPcb, InternalErrorEventHandler); + } + + KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); +} + +struct tcp_pcb * +LibTCPSocket(void *arg) +{ + struct socket_callback_msg *msg = ExAllocatePool(NonPagedPool, sizeof(struct socket_callback_msg)); + void *ret; + + if (msg) + { + KeInitializeEvent(&msg->Event, NotificationEvent, FALSE); + msg->Arg = arg; + + tcpip_callback_with_block(LibTCPSocketCallback, msg, 1); + + if (WaitForEventSafely(&msg->Event)) + ret = msg->NewPcb; + else + ret = NULL; + + DbgPrint("LibTCPSocket(0x%x) = 0x%x\n", arg, ret); + + ExFreePool(msg); + + return ret; + } + + return NULL; +} + +struct bind_callback_msg +{ + /* Synchronization */ + KEVENT Event; + + /* Input */ + struct tcp_pcb *Pcb; + struct ip_addr *IpAddress; + u16_t Port; + + /* Output */ + err_t Error; +}; + +static +void +LibTCPBindCallback(void *arg) +{ + struct bind_callback_msg *msg = arg; + + ASSERT(msg); + + msg->Error = tcp_bind(msg->Pcb, msg->IpAddress, ntohs(msg->Port)); + + KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); +} + +err_t +LibTCPBind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct bind_callback_msg *msg; + err_t ret; + + if (!pcb) + return ERR_CLSD; + + msg = ExAllocatePool(NonPagedPool, sizeof(struct bind_callback_msg)); + if (msg) + { + KeInitializeEvent(&msg->Event, NotificationEvent, FALSE); + msg->Pcb = pcb; + msg->IpAddress = ipaddr; + msg->Port = port; + + tcpip_callback_with_block(LibTCPBindCallback, msg, 1); + + if (WaitForEventSafely(&msg->Event)) + ret = msg->Error; + else + ret = ERR_CLSD; + + DbgPrint("LibTCPBind(0x%x)\n", pcb); + + ExFreePool(msg); + + return ret; + } + + return ERR_MEM; +} + +struct listen_callback_msg +{ + /* Synchronization */ + KEVENT Event; + + /* Input */ + struct tcp_pcb *Pcb; + u8_t Backlog; + + /* Output */ + struct tcp_pcb *NewPcb; +}; + +static +void +LibTCPListenCallback(void *arg) +{ + struct listen_callback_msg *msg = arg; + void *p; + + ASSERT(msg); + + p = msg->Pcb->callback_arg; + msg->NewPcb = tcp_listen_with_backlog(msg->Pcb, msg->Backlog); + + if (msg->NewPcb) + { + tcp_arg(msg->NewPcb, p); + tcp_accept(msg->NewPcb, InternalAcceptEventHandler); + tcp_err(msg->NewPcb, InternalErrorEventHandler); + } + + KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); +} + +struct tcp_pcb * +LibTCPListen(struct tcp_pcb *pcb, u8_t backlog) +{ + struct listen_callback_msg *msg; + void *ret; + + if (!pcb) + return NULL; + + msg = ExAllocatePool(NonPagedPool, sizeof(struct listen_callback_msg)); + if (msg) + { + KeInitializeEvent(&msg->Event, NotificationEvent, FALSE); + msg->Pcb = pcb; + msg->Backlog = backlog; + + tcpip_callback_with_block(LibTCPListenCallback, msg, 1); + + if (WaitForEventSafely(&msg->Event)) + ret = msg->NewPcb; + else + ret = NULL; + + DbgPrint("LibTCPListen(0x%x,0x%x)\n", pcb, ret); + + ExFreePool(msg); + + return ret; + } + + return NULL; +} + +struct send_callback_msg +{ + /* Synchronization */ + KEVENT Event; + + /* Input */ + struct tcp_pcb *Pcb; + void *Data; + u16_t DataLength; + + /* Output */ + err_t Error; +}; + +static +void +LibTCPSendCallback(void *arg) +{ + struct send_callback_msg *msg = arg; + + ASSERT(msg); + + if (tcp_sndbuf(msg->Pcb) < msg->DataLength) + { + msg->Error = ERR_INPROGRESS; + } + else + { + tcp_sent(msg->Pcb, InternalSendEventHandler); + + msg->Error = tcp_write(msg->Pcb, msg->Data, msg->DataLength, TCP_WRITE_FLAG_COPY); + + tcp_output(msg->Pcb); + } + + KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); +} + +err_t +LibTCPSend(struct tcp_pcb *pcb, void *dataptr, u16_t len) +{ + struct send_callback_msg *msg; + err_t ret; + + if (!pcb) + return ERR_CLSD; + + msg = ExAllocatePool(NonPagedPool, sizeof(struct send_callback_msg)); + if (msg) + { + KeInitializeEvent(&msg->Event, NotificationEvent, FALSE); + msg->Pcb = pcb; + msg->Data = dataptr; + msg->DataLength = len; + + tcpip_callback_with_block(LibTCPSendCallback, msg, 1); + + if (WaitForEventSafely(&msg->Event)) + ret = msg->Error; + else + ret = ERR_CLSD; + + DbgPrint("LibTCPSend(0x%x)\n", pcb); + + ExFreePool(msg); + + return ret; + } + + return ERR_MEM; +} + +struct connect_callback_msg +{ + /* Synchronization */ + KEVENT Event; + + /* Input */ + struct tcp_pcb *Pcb; + struct ip_addr *IpAddress; + u16_t Port; + + /* Output */ + err_t Error; +}; + +static +void +LibTCPConnectCallback(void *arg) +{ + struct connect_callback_msg *msg = arg; + + ASSERT(arg); + + msg->Error = tcp_connect(msg->Pcb, msg->IpAddress, ntohs(msg->Port), InternalConnectEventHandler); + if (msg->Error == ERR_OK) + msg->Error = ERR_INPROGRESS; + + KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); +} + +err_t +LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ + struct connect_callback_msg *msg; + err_t ret; + + if (!pcb) + return ERR_CLSD; + + msg = ExAllocatePool(NonPagedPool, sizeof(struct connect_callback_msg)); + if (msg) + { + KeInitializeEvent(&msg->Event, NotificationEvent, FALSE); + msg->Pcb = pcb; + msg->IpAddress = ipaddr; + msg->Port = port; + + tcpip_callback_with_block(LibTCPConnectCallback, msg, 1); + + if (WaitForEventSafely(&msg->Event)) + ret = msg->Error; + else + ret = ERR_CLSD; + + ExFreePool(msg); + + DbgPrint("LibTCPConnect(0x%x)\n", pcb); + + return ret; + } + + return ERR_MEM; +} + +struct close_callback_msg +{ + /* Synchronization */ + KEVENT Event; + + /* Input */ + struct tcp_pcb *Pcb; + + /* Output */ + err_t Error; +}; + +static +void +LibTCPCloseCallback(void *arg) +{ + struct close_callback_msg *msg = arg; + + msg->Error = tcp_close(msg->Pcb); + + KeSetEvent(&msg->Event, IO_NO_INCREMENT, FALSE); +} + +err_t +LibTCPClose(struct tcp_pcb *pcb) +{ + struct close_callback_msg *msg; + err_t ret; + + if (!pcb) + return ERR_CLSD; + + tcp_arg(pcb, NULL); + tcp_recv(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_err(pcb, NULL); + tcp_accept(pcb, NULL); + + msg = ExAllocatePool(NonPagedPool, sizeof(struct close_callback_msg)); + if (msg) + { + KeInitializeEvent(&msg->Event, NotificationEvent, FALSE); + msg->Pcb = pcb; + + tcpip_callback_with_block(LibTCPCloseCallback, msg, 1); + + if (WaitForEventSafely(&msg->Event)) + ret = msg->Error; + else + ret = ERR_CLSD; + + ExFreePool(msg); + + DbgPrint("LibTCPClose(0x%x)\n", pcb); + + return ret; + } + + return ERR_MEM; +} + +void +LibTCPAccept(struct tcp_pcb *pcb, void *arg) +{ + DbgPrint("LibTCPAccept(0x%x, 0x%x)\n", pcb, arg); + + ASSERT(arg); + + tcp_arg(pcb, NULL); + tcp_recv(pcb, InternalRecvEventHandler); + tcp_sent(pcb, InternalSendEventHandler); + tcp_arg(pcb, arg); + + tcp_accepted(pcb); +} + +err_t +LibTCPGetHostName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port) +{ + DbgPrint("LibTCPGetHostName(0x%x)\n", pcb); + + if (!pcb) + return ERR_CLSD; + + *ipaddr = pcb->local_ip; + *port = pcb->local_port; + + DbgPrint("Got host port: %d\n", *port); + + return ERR_OK; +} + +err_t +LibTCPGetPeerName(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t *port) +{ + DbgPrint("LibTCPGetPeerName(0x%x)\n", pcb); + + if (!pcb) + return ERR_CLSD; + + *ipaddr = pcb->remote_ip; + *port = pcb->remote_port; + + DbgPrint("Got remote port: %d\n", *port); + + return ERR_OK; +} diff --git a/lib/drivers/lwip/src/sys_arch.c b/lib/drivers/lwip/src/sys_arch.c new file mode 100755 index 00000000000..3692b2cefcb --- /dev/null +++ b/lib/drivers/lwip/src/sys_arch.c @@ -0,0 +1,380 @@ +#include "lwip/sys.h" + +#include "lwip/tcp.h" +#include "lwip/pbuf.h" +#include "lwip/err.h" + +#include + +static LIST_ENTRY ThreadListHead; +static KSPIN_LOCK ThreadListLock; + +KEVENT TerminationEvent; + +static LARGE_INTEGER StartTime; + +typedef struct _thread_t +{ + PVOID ThreadId; + HANDLE Handle; + struct sys_timeouts Timeouts; + void (* ThreadFunction)(void *arg); + void *ThreadContext; + LIST_ENTRY ListEntry; + char Name[1]; +} *thread_t; + +u32_t sys_now(void) +{ + LARGE_INTEGER CurrentTime; + + KeQuerySystemTime(&CurrentTime); + + return (CurrentTime.QuadPart - StartTime.QuadPart) / 10000; +} + +void +sys_arch_protect(sys_prot_t *lev) +{ + KIRQL OldIrql; + + KeAcquireSpinLock(&lev->Lock, &OldIrql); + + lev->OldIrql = OldIrql; +} + +void +sys_arch_unprotect(sys_prot_t *lev) +{ + KeReleaseSpinLock(&lev->Lock, lev->OldIrql); +} + +void +sys_arch_decl_protect(sys_prot_t *lev) +{ + KeInitializeSpinLock(&lev->Lock); +} + +sys_sem_t +sys_sem_new(u8_t count) +{ + sys_sem_t sem = ExAllocatePool(NonPagedPool, sizeof(KEVENT)); + if (!sem) + return SYS_SEM_NULL; + + ASSERT(count == 0 || count == 1); + + /* It seems lwIP uses the semaphore implementation as either a completion event or a lock + * so I optimize for this case by using a synchronization event and setting its initial state + * to signalled for a lock and non-signalled for a completion event */ + + KeInitializeEvent(sem, SynchronizationEvent, count); + + return sem; +} + +void +sys_sem_free(sys_sem_t sem) +{ + ExFreePool(sem); +} + +void +sys_sem_signal(sys_sem_t sem) +{ + KeSetEvent(sem, IO_NO_INCREMENT, FALSE); +} + +u32_t +sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) +{ + LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime; + UINT64 TimeDiff; + NTSTATUS Status; + PVOID WaitObjects[] = {sem, &TerminationEvent}; + + LargeTimeout.QuadPart = Int32x32To64(timeout, -10000); + + KeQuerySystemTime(&PreWaitTime); + + Status = KeWaitForMultipleObjects(2, + WaitObjects, + WaitAny, + Executive, + KernelMode, + FALSE, + timeout != 0 ? &LargeTimeout : NULL, + NULL); + if (Status == STATUS_WAIT_0) + { + KeQuerySystemTime(&PostWaitTime); + TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart; + TimeDiff /= 10000; + return TimeDiff; + } + else if (Status == STATUS_WAIT_1) + { + /* DON'T remove ourselves from the thread list! */ + PsTerminateSystemThread(STATUS_SUCCESS); + + /* We should never get here! */ + ASSERT(FALSE); + + return 0; + } + else + return SYS_ARCH_TIMEOUT; +} + +sys_mbox_t +sys_mbox_new(int size) +{ + sys_mbox_t mbox = ExAllocatePool(NonPagedPool, sizeof(struct _sys_mbox_t)); + + if (!mbox) + return SYS_MBOX_NULL; + + KeInitializeSpinLock(&mbox->Lock); + + InitializeListHead(&mbox->ListHead); + + KeInitializeEvent(&mbox->Event, NotificationEvent, FALSE); + + return mbox; +} + +void +sys_mbox_free(sys_mbox_t mbox) +{ + ASSERT(IsListEmpty(&mbox->ListHead)); + + ExFreePool(mbox); +} + +void +sys_mbox_post(sys_mbox_t mbox, void *msg) +{ + PLWIP_MESSAGE_CONTAINER Container; + KIRQL OldIrql; + + Container = ExAllocatePool(NonPagedPool, sizeof(*Container)); + ASSERT(Container); + + Container->Message = msg; + + KeAcquireSpinLock(&mbox->Lock, &OldIrql); + InsertTailList(&mbox->ListHead, + &Container->ListEntry); + + KeSetEvent(&mbox->Event, IO_NO_INCREMENT, FALSE); + KeReleaseSpinLock(&mbox->Lock, OldIrql); +} + +u32_t +sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) +{ + LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime; + UINT64 TimeDiff; + NTSTATUS Status; + PVOID Message; + PLWIP_MESSAGE_CONTAINER Container; + PLIST_ENTRY Entry; + KIRQL OldIrql; + PVOID WaitObjects[] = {&mbox->Event, &TerminationEvent}; + + LargeTimeout.QuadPart = Int32x32To64(timeout, -10000); + + KeQuerySystemTime(&PreWaitTime); + + Status = KeWaitForMultipleObjects(2, + WaitObjects, + WaitAny, + Executive, + KernelMode, + FALSE, + timeout != 0 ? &LargeTimeout : NULL, + NULL); + if (Status == STATUS_WAIT_0) + { + KeAcquireSpinLock(&mbox->Lock, &OldIrql); + Entry = RemoveHeadList(&mbox->ListHead); + ASSERT(Entry); + if (IsListEmpty(&mbox->ListHead)) + KeClearEvent(&mbox->Event); + Container = CONTAINING_RECORD(Entry, LWIP_MESSAGE_CONTAINER, ListEntry); + KeReleaseSpinLock(&mbox->Lock, OldIrql); + + KeQuerySystemTime(&PostWaitTime); + TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart; + TimeDiff /= 10000; + + Message = Container->Message; + ExFreePool(Container); + + if (msg) + *msg = Message; + + return TimeDiff; + } + else if (Status == STATUS_WAIT_1) + { + /* DON'T remove ourselves from the thread list! */ + PsTerminateSystemThread(STATUS_SUCCESS); + + /* We should never get here! */ + ASSERT(FALSE); + + return 0; + } + else + return SYS_ARCH_TIMEOUT; +} + +u32_t +sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) +{ + if (sys_arch_mbox_fetch(mbox, msg, 1) != SYS_ARCH_TIMEOUT) + return 0; + else + return SYS_MBOX_EMPTY; +} + +err_t +sys_mbox_trypost(sys_mbox_t mbox, void *msg) +{ + sys_mbox_post(mbox, msg); + + return ERR_OK; +} + +struct sys_timeouts *sys_arch_timeouts(void) +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + thread_t Container; + + KeAcquireSpinLock(&ThreadListLock, &OldIrql); + CurrentEntry = ThreadListHead.Flink; + while (CurrentEntry != &ThreadListHead) + { + Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry); + + if (Container->ThreadId == KeGetCurrentThread()) + { + KeReleaseSpinLock(&ThreadListLock, OldIrql); + return &Container->Timeouts; + } + + CurrentEntry = CurrentEntry->Flink; + } + KeReleaseSpinLock(&ThreadListLock, OldIrql); + + Container = ExAllocatePool(NonPagedPool, sizeof(*Container)); + if (!Container) + return SYS_ARCH_NULL; + + Container->Name[0] = ANSI_NULL; + Container->ThreadFunction = NULL; + Container->ThreadContext = NULL; + Container->Timeouts.next = NULL; + Container->ThreadId = KeGetCurrentThread(); + + ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock); + + return &Container->Timeouts; +} + +VOID +NTAPI +LwipThreadMain(PVOID Context) +{ + thread_t Container = Context; + KIRQL OldIrql; + + Container->ThreadId = KeGetCurrentThread(); + + ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock); + + Container->ThreadFunction(Container->ThreadContext); + + KeAcquireSpinLock(&ThreadListLock, &OldIrql); + RemoveEntryList(&Container->ListEntry); + KeReleaseSpinLock(&ThreadListLock, OldIrql); + + ExFreePool(Container); + + PsTerminateSystemThread(STATUS_SUCCESS); +} + +sys_thread_t +sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) +{ + thread_t Container; + NTSTATUS Status; + + Container = ExAllocatePool(NonPagedPool, strlen(name) + sizeof(*Container)); + if (!Container) + return 0; + + strcpy(Container->Name, name); + Container->ThreadFunction = thread; + Container->ThreadContext = arg; + Container->Timeouts.next = NULL; + + Status = PsCreateSystemThread(&Container->Handle, + THREAD_ALL_ACCESS, + NULL, + NULL, + NULL, + LwipThreadMain, + Container); + + if (!NT_SUCCESS(Status)) + { + ExFreePool(Container); + return 0; + } + + return 0; +} + +void +sys_init(void) +{ + KeInitializeSpinLock(&ThreadListLock); + + InitializeListHead(&ThreadListHead); + + KeQuerySystemTime(&StartTime); + + KeInitializeEvent(&TerminationEvent, NotificationEvent, FALSE); +} + +void +sys_shutdown(void) +{ + PLIST_ENTRY CurrentEntry; + thread_t Container; + + /* Set the termination event */ + KeSetEvent(&TerminationEvent, IO_NO_INCREMENT, FALSE); + + /* Loop through the thread list and wait for each to die */ + while ((CurrentEntry = ExInterlockedRemoveHeadList(&ThreadListHead, &ThreadListLock))) + { + Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry); + + if (Container->ThreadFunction) + { + KeWaitForSingleObject(Container->Handle, + Executive, + KernelMode, + FALSE, + NULL); + + ZwClose(Container->Handle); + } + + CurrentEntry = CurrentEntry->Flink; + } +}