2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/tcp.c
5 * PURPOSE: Transmission Control Protocol
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
13 LONG TCP_IPIdentification
= 0;
14 static BOOLEAN TCPInitialized
= FALSE
;
15 static NPAGED_LOOKASIDE_LIST TCPSegmentList
;
16 LIST_ENTRY SleepingThreadsList
;
17 FAST_MUTEX SleepingThreadsLock
;
18 RECURSIVE_MUTEX TCPLock
;
20 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
21 PCONNECTION_ENDPOINT Connection
=
22 ExAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
26 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
28 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
30 /* Initialize spin lock that protects the connection endpoint file object */
31 TcpipInitializeSpinLock(&Connection
->Lock
);
32 InitializeListHead(&Connection
->ConnectRequest
);
33 InitializeListHead(&Connection
->ListenRequest
);
34 InitializeListHead(&Connection
->ReceiveRequest
);
36 /* Save client context pointer */
37 Connection
->ClientContext
= ClientContext
;
39 /* Initialize received segments queue */
40 InitializeListHead(&Connection
->ReceivedSegments
);
45 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
46 TI_DbgPrint(MAX_TRACE
,("FIXME: Cancel all pending requests\n"));
47 /* XXX Cancel all pending requests */
48 ExFreePool( Connection
);
51 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
52 UINT Family
, UINT Type
, UINT Proto
) {
55 TI_DbgPrint(MID_TRACE
,("Called: Connection %x, Family %d, Type %d, "
57 Connection
, Family
, Type
, Proto
));
59 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
60 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
61 &Connection
->SocketContext
,
66 ASSERT_KM_POINTER(Connection
->SocketContext
);
68 TI_DbgPrint(MID_TRACE
,("Connection->SocketContext %x\n",
69 Connection
->SocketContext
));
71 TcpipRecursiveMutexLeave( &TCPLock
);
76 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
78 * FUNCTION: Receives and queues TCP data
80 * IPPacket = Pointer to an IP packet that was received
82 * This is the low level interface for receiving TCP data
85 TI_DbgPrint(MID_TRACE
,("Sending packet %d (%d) to oskit\n",
87 IPPacket
->HeaderSize
));
89 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
91 OskitTCPReceiveDatagram( IPPacket
->Header
,
93 IPPacket
->HeaderSize
);
95 TcpipRecursiveMutexLeave( &TCPLock
);
99 int TCPSocketState( void *ClientData
,
101 void *WhichConnection
,
104 int TCPPacketSend( void *ClientData
,
108 POSK_IFADDR
TCPFindInterface( void *ClientData
,
111 OSK_SOCKADDR
*ReqAddr
);
113 void *TCPMalloc( void *ClientData
,
114 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
115 void TCPFree( void *ClientData
,
116 void *data
, OSK_PCHAR file
, OSK_UINT line
);
118 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
121 void TCPWakeup( void *ClientData
, void *token
);
123 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
124 NULL
, /* Client Data */
125 TCPSocketState
, /* SocketState */
126 TCPPacketSend
, /* PacketSend */
127 TCPFindInterface
, /* FindInterface */
128 TCPMalloc
, /* Malloc */
130 TCPSleep
, /* Sleep */
131 TCPWakeup
/* Wakeup */
134 NTSTATUS
TCPStartup(VOID
)
136 * FUNCTION: Initializes the TCP subsystem
138 * Status of operation
141 TcpipRecursiveMutexInit( &TCPLock
);
142 ExInitializeFastMutex( &SleepingThreadsLock
);
143 InitializeListHead( &SleepingThreadsList
);
145 RegisterOskitTCPEventHandlers( &EventHandlers
);
148 /* Register this protocol with IP layer */
149 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
151 ExInitializeNPagedLookasideList(
152 &TCPSegmentList
, /* Lookaside list */
153 NULL
, /* Allocate routine */
154 NULL
, /* Free routine */
156 sizeof(TCP_SEGMENT
), /* Size of each entry */
157 TAG('T','C','P','S'), /* Tag */
160 TCPInitialized
= TRUE
;
162 return STATUS_SUCCESS
;
166 NTSTATUS
TCPShutdown(VOID
)
168 * FUNCTION: Shuts down the TCP subsystem
170 * Status of operation
174 return STATUS_SUCCESS
;
176 /* Deregister this protocol with IP layer */
177 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
179 ExDeleteNPagedLookasideList(&TCPSegmentList
);
181 TCPInitialized
= FALSE
;
185 return STATUS_SUCCESS
;
188 NTSTATUS
TCPTranslateError( int OskitError
) {
189 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
191 switch( OskitError
) {
192 case 0: Status
= STATUS_SUCCESS
; break;
193 case OSK_EADDRNOTAVAIL
:
194 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
195 case OSK_ECONNREFUSED
:
196 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
197 case OSK_EINPROGRESS
:
198 case OSK_EAGAIN
: Status
= STATUS_PENDING
; break;
199 default: Status
= STATUS_INVALID_CONNECTION
; break;
202 TI_DbgPrint(MID_TRACE
,("Error %d -> %x\n", OskitError
, Status
));
208 ( PCONNECTION_ENDPOINT Connection
,
209 PTDI_CONNECTION_INFORMATION ConnInfo
) {
211 SOCKADDR_IN AddressToConnect
;
212 PIP_ADDRESS LocalAddress
;
215 TI_DbgPrint(MID_TRACE
,("Called\n"));
217 Status
= AddrBuildAddress
218 ((PTA_ADDRESS
)ConnInfo
->LocalAddress
,
222 AddressToBind
.sin_family
= AF_INET
;
223 memcpy( &AddressToBind
.sin_addr
,
224 &LocalAddress
->Address
.IPv4Address
,
225 sizeof(AddressToBind
.sin_addr
) );
226 AddressToBind
.sin_port
= LocalPort
;
228 Status
= OskitTCPBind( Connection
->SocketContext
,
231 sizeof(AddressToBind
));
233 TI_DbgPrint(MID_TRACE
,("Leaving %x\n", Status
));
240 ( PCONNECTION_ENDPOINT Connection
,
241 PTDI_CONNECTION_INFORMATION ConnInfo
,
242 PTDI_CONNECTION_INFORMATION ReturnInfo
,
243 PTCP_COMPLETION_ROUTINE Complete
,
246 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
247 PIP_ADDRESS RemoteAddress
;
251 DbgPrint("TCPConnect: Called\n");
253 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
254 if( !Bucket
) return STATUS_NO_MEMORY
;
256 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
258 /* Freed in TCPSocketState */
259 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
260 Bucket
->Request
.RequestContext
= Context
;
262 InsertHeadList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
264 Status
= AddrBuildAddress
265 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
269 DbgPrint("Connecting to address %x:%x\n",
270 RemoteAddress
->Address
.IPv4Address
,
273 if (!NT_SUCCESS(Status
)) {
274 TI_DbgPrint(MID_TRACE
, ("Could not AddrBuildAddress in TCPConnect\n"));
278 AddressToConnect
.sin_family
= AF_INET
;
279 AddressToBind
= AddressToConnect
;
281 OskitTCPBind( Connection
->SocketContext
,
284 sizeof(AddressToBind
) );
286 memcpy( &AddressToConnect
.sin_addr
,
287 &RemoteAddress
->Address
.IPv4Address
,
288 sizeof(AddressToConnect
.sin_addr
) );
289 AddressToConnect
.sin_port
= RemotePort
;
291 Status
= OskitTCPConnect(Connection
->SocketContext
,
294 sizeof(AddressToConnect
));
296 TcpipRecursiveMutexLeave( &TCPLock
);
298 if( Status
== OSK_EINPROGRESS
|| Status
== STATUS_SUCCESS
)
299 return STATUS_PENDING
;
305 ( PCONNECTION_ENDPOINT Connection
) {
308 TI_DbgPrint(MID_TRACE
,("TCPClose started\n"));
310 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
312 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
314 TcpipRecursiveMutexLeave( &TCPLock
);
316 TI_DbgPrint(MID_TRACE
,("TCPClose finished %x\n", Status
));
322 ( PCONNECTION_ENDPOINT Connection
,
324 PTCP_COMPLETION_ROUTINE Complete
,
328 TI_DbgPrint(MID_TRACE
,("TCPListen started\n"));
330 TI_DbgPrint(MID_TRACE
,("Connection->SocketContext %x\n",
331 Connection
->SocketContext
));
334 ASSERT_KM_POINTER(Connection
->SocketContext
);
336 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
338 Status
= TCPTranslateError( OskitTCPListen( Connection
->SocketContext
,
341 TcpipRecursiveMutexLeave( &TCPLock
);
343 TI_DbgPrint(MID_TRACE
,("TCPListen finished %x\n", Status
));
349 ( PTDI_REQUEST Request
,
350 VOID
**NewSocketContext
) {
353 TI_DbgPrint(MID_TRACE
,("TCPAccept started\n"));
354 Status
= STATUS_UNSUCCESSFUL
;
355 TI_DbgPrint(MID_TRACE
,("TCPAccept finished %x\n", Status
));
359 VOID
TCPCancelReceiveRequest( PVOID Context
) {
360 PLIST_ENTRY ListEntry
;
361 PCONNECTION_ENDPOINT Connection
= (PCONNECTION_ENDPOINT
)Context
;
363 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
364 for( ListEntry
= Connection
->ReceiveRequest
.Flink
;
365 ListEntry
!= &Connection
->ReceiveRequest
;
366 ListEntry
= ListEntry
->Flink
) {
369 TcpipRecursiveMutexLeave( &TCPLock
);
372 NTSTATUS TCPReceiveData
373 ( PCONNECTION_ENDPOINT Connection
,
376 PULONG BytesReceived
,
378 PTCP_COMPLETION_ROUTINE Complete
,
381 UINT DataLen
, Received
= 0;
385 TI_DbgPrint(MID_TRACE
,("Called for %d bytes\n", ReceiveLength
));
387 ASSERT_KM_POINTER(Connection
->SocketContext
);
389 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
391 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
393 TI_DbgPrint(MID_TRACE
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
395 Status
= TCPTranslateError
397 ( Connection
->SocketContext
,
403 TI_DbgPrint(MID_TRACE
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
405 /* Keep this request around ... there was no data yet */
406 if( Status
== STATUS_PENDING
||
407 (Status
== STATUS_SUCCESS
&& Received
== 0) ) {
408 /* Freed in TCPSocketState */
409 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
411 TI_DbgPrint(MID_TRACE
,("Failed to allocate bucket\n"));
412 TcpipRecursiveMutexLeave( &TCPLock
);
413 return STATUS_NO_MEMORY
;
416 Bucket
->Request
.RequestNotifyObject
= Complete
;
417 Bucket
->Request
.RequestContext
= Context
;
420 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
421 Status
= STATUS_PENDING
;
422 TI_DbgPrint(MID_TRACE
,("Queued read irp\n"));
424 TI_DbgPrint(MID_TRACE
,("Got status %x, bytes %d\n", Status
, Received
));
425 *BytesReceived
= Received
;
428 TcpipRecursiveMutexLeave( &TCPLock
);
430 TI_DbgPrint(MID_TRACE
,("Status %x\n", Status
));
436 ( PCONNECTION_ENDPOINT Connection
,
443 ASSERT_KM_POINTER(Connection
->SocketContext
);
445 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
447 TI_DbgPrint(MID_TRACE
,("Connection = %x\n", Connection
));
448 TI_DbgPrint(MID_TRACE
,("Connection->SocketContext = %x\n",
449 Connection
->SocketContext
));
451 Status
= OskitTCPSend( Connection
->SocketContext
,
452 BufferData
, PacketSize
, (PUINT
)DataUsed
, 0 );
454 TcpipRecursiveMutexLeave( &TCPLock
);
459 VOID
TCPTimeout(VOID
) {
460 static int Times
= 0;
461 if( (Times
++ % 5) == 0 ) {
462 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
464 TcpipRecursiveMutexLeave( &TCPLock
);