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 KeInitializeSpinLock(&Connection
->Lock
);
32 InitializeListHead(&Connection
->ConnectRequest
);
33 InitializeListHead(&Connection
->ListenRequest
);
34 InitializeListHead(&Connection
->ReceiveRequest
);
36 /* Reference the object */
37 Connection
->RefCount
= 1;
39 /* Save client context pointer */
40 Connection
->ClientContext
= ClientContext
;
42 /* Initialize received segments queue */
43 InitializeListHead(&Connection
->ReceivedSegments
);
48 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
49 /* XXX Cancel all pending requests */
50 ExFreePool( Connection
);
53 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
54 UINT Family
, UINT Type
, UINT Proto
) {
57 RecursiveMutexEnter( &TCPLock
, TRUE
);
58 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
59 &Connection
->SocketContext
,
63 RecursiveMutexLeave( &TCPLock
);
68 VOID
TCPReceive(PNET_TABLE_ENTRY NTE
, PIP_PACKET IPPacket
)
70 * FUNCTION: Receives and queues TCP data
72 * NTE = Pointer to net table entry which the packet was received on
73 * IPPacket = Pointer to an IP packet that was received
75 * This is the low level interface for receiving TCP data
78 TI_DbgPrint(MID_TRACE
,("Sending packet %d (%d) to oskit\n",
80 IPPacket
->HeaderSize
));
82 RecursiveMutexEnter( &TCPLock
, TRUE
);
84 OskitTCPReceiveDatagram( IPPacket
->Header
,
86 IPPacket
->HeaderSize
);
88 RecursiveMutexLeave( &TCPLock
);
92 int TCPSocketState( void *ClientData
,
94 void *WhichConnection
,
97 int TCPPacketSend( void *ClientData
,
101 POSK_IFADDR
TCPFindInterface( void *ClientData
,
104 OSK_SOCKADDR
*ReqAddr
);
106 void *TCPMalloc( void *ClientData
,
107 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
108 void TCPFree( void *ClientData
,
109 void *data
, OSK_PCHAR file
, OSK_UINT line
);
111 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
114 void TCPWakeup( void *ClientData
, void *token
);
116 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
117 NULL
, /* Client Data */
118 TCPSocketState
, /* SocketState */
119 TCPPacketSend
, /* PacketSend */
120 TCPFindInterface
, /* FindInterface */
121 TCPMalloc
, /* Malloc */
123 TCPSleep
, /* Sleep */
124 TCPWakeup
/* Wakeup */
127 NTSTATUS
TCPStartup(VOID
)
129 * FUNCTION: Initializes the TCP subsystem
131 * Status of operation
134 RecursiveMutexInit( &TCPLock
);
135 ExInitializeFastMutex( &SleepingThreadsLock
);
136 InitializeListHead( &SleepingThreadsList
);
138 RegisterOskitTCPEventHandlers( &EventHandlers
);
141 /* Register this protocol with IP layer */
142 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
144 ExInitializeNPagedLookasideList(
145 &TCPSegmentList
, /* Lookaside list */
146 NULL
, /* Allocate routine */
147 NULL
, /* Free routine */
149 sizeof(TCP_SEGMENT
), /* Size of each entry */
150 TAG('T','C','P','S'), /* Tag */
153 TCPInitialized
= TRUE
;
155 return STATUS_SUCCESS
;
159 NTSTATUS
TCPShutdown(VOID
)
161 * FUNCTION: Shuts down the TCP subsystem
163 * Status of operation
167 return STATUS_SUCCESS
;
169 /* Deregister this protocol with IP layer */
170 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
172 ExDeleteNPagedLookasideList(&TCPSegmentList
);
174 TCPInitialized
= FALSE
;
178 return STATUS_SUCCESS
;
181 NTSTATUS
TCPTranslateError( int OskitError
) {
182 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
184 switch( OskitError
) {
185 case 0: Status
= STATUS_SUCCESS
; break;
186 case OSK_EADDRNOTAVAIL
:
187 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
188 case OSK_ECONNREFUSED
:
189 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
190 case OSK_EINPROGRESS
:
191 case OSK_EAGAIN
: Status
= STATUS_PENDING
; break;
192 default: Status
= STATUS_INVALID_CONNECTION
; break;
195 TI_DbgPrint(MID_TRACE
,("Error %d -> %x\n", OskitError
, Status
));
201 ( PCONNECTION_ENDPOINT Connection
,
202 PTDI_CONNECTION_INFORMATION ConnInfo
) {
204 SOCKADDR_IN AddressToConnect
;
205 PIP_ADDRESS LocalAddress
;
208 TI_DbgPrint(MID_TRACE
,("Called\n"));
210 Status
= AddrBuildAddress
211 ((PTA_ADDRESS
)ConnInfo
->LocalAddress
,
215 AddressToBind
.sin_family
= AF_INET
;
216 memcpy( &AddressToBind
.sin_addr
,
217 &LocalAddress
->Address
.IPv4Address
,
218 sizeof(AddressToBind
.sin_addr
) );
219 AddressToBind
.sin_port
= LocalPort
;
221 Status
= OskitTCPBind( Connection
->SocketContext
,
224 sizeof(AddressToBind
));
226 TI_DbgPrint(MID_TRACE
,("Leaving %x\n", Status
));
233 ( PCONNECTION_ENDPOINT Connection
,
234 PTDI_CONNECTION_INFORMATION ConnInfo
,
235 PTDI_CONNECTION_INFORMATION ReturnInfo
,
236 PTCP_COMPLETION_ROUTINE Complete
,
239 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
240 PIP_ADDRESS RemoteAddress
;
244 DbgPrint("TCPConnect: Called\n");
246 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
247 if( !Bucket
) return STATUS_NO_MEMORY
;
249 RecursiveMutexEnter( &TCPLock
, TRUE
);
251 /* Freed in TCPSocketState */
252 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
253 Bucket
->Request
.RequestContext
= Context
;
255 InsertHeadList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
257 Status
= AddrBuildAddress
258 ((PTA_ADDRESS
)ConnInfo
->RemoteAddress
,
262 DbgPrint("Connecting to address %x:%x\n",
263 RemoteAddress
->Address
.IPv4Address
,
266 if (!NT_SUCCESS(Status
)) {
267 TI_DbgPrint(MID_TRACE
, ("Could not AddrBuildAddress in TCPConnect\n"));
271 AddressToConnect
.sin_family
= AF_INET
;
272 AddressToBind
= AddressToConnect
;
274 OskitTCPBind( Connection
->SocketContext
,
277 sizeof(AddressToBind
) );
279 memcpy( &AddressToConnect
.sin_addr
,
280 &RemoteAddress
->Address
.IPv4Address
,
281 sizeof(AddressToConnect
.sin_addr
) );
282 AddressToConnect
.sin_port
= RemotePort
;
284 Status
= OskitTCPConnect(Connection
->SocketContext
,
287 sizeof(AddressToConnect
));
289 RecursiveMutexLeave( &TCPLock
);
291 if( Status
== OSK_EINPROGRESS
|| Status
== STATUS_SUCCESS
)
292 return STATUS_PENDING
;
298 ( PCONNECTION_ENDPOINT Connection
) {
301 TI_DbgPrint(MID_TRACE
,("TCPClose started\n"));
303 RecursiveMutexEnter( &TCPLock
, TRUE
);
305 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
307 RecursiveMutexLeave( &TCPLock
);
309 TI_DbgPrint(MID_TRACE
,("TCPClose finished %x\n", Status
));
315 ( PCONNECTION_ENDPOINT Connection
,
317 PTCP_COMPLETION_ROUTINE Complete
,
321 RecursiveMutexEnter( &TCPLock
, TRUE
);
323 Status
= TCPTranslateError( OskitTCPListen( Connection
->SocketContext
,
326 RecursiveMutexLeave( &TCPLock
);
332 ( PTDI_REQUEST Request
,
333 VOID
**NewSocketContext
) {
334 return STATUS_UNSUCCESSFUL
;
337 NTSTATUS TCPReceiveData
338 ( PCONNECTION_ENDPOINT Connection
,
342 PULONG BytesReceived
,
343 PTCP_COMPLETION_ROUTINE Complete
,
346 UINT DataLen
, Received
= 0;
350 TI_DbgPrint(MID_TRACE
,("Called for %d bytes\n", ReceiveLength
));
352 RecursiveMutexEnter( &TCPLock
, TRUE
);
354 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
356 TI_DbgPrint(MID_TRACE
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
358 Status
= TCPTranslateError
360 ( Connection
->SocketContext
,
366 TI_DbgPrint(MID_TRACE
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
368 /* Keep this request around ... there was no data yet */
369 if( Status
== STATUS_PENDING
||
370 (Status
== STATUS_SUCCESS
&& Received
== 0) ) {
371 /* Freed in TCPSocketState */
372 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
374 TI_DbgPrint(MID_TRACE
,("Failed to allocate bucket\n"));
375 return STATUS_NO_MEMORY
;
378 Bucket
->Request
.RequestNotifyObject
= Complete
;
379 Bucket
->Request
.RequestContext
= Context
;
381 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
382 Status
= STATUS_PENDING
;
383 TI_DbgPrint(MID_TRACE
,("Queued read irp\n"));
385 TI_DbgPrint(MID_TRACE
,("Got status %x, bytes %d\n", Status
, Received
));
386 *BytesReceived
= Received
;
389 RecursiveMutexLeave( &TCPLock
);
391 TI_DbgPrint(MID_TRACE
,("Status %x\n", Status
));
397 ( PCONNECTION_ENDPOINT Connection
,
406 RecursiveMutexEnter( &TCPLock
, TRUE
);
408 NdisQueryBuffer( Buffer
, &BufferData
, &PacketSize
);
410 TI_DbgPrint(MID_TRACE
,("Connection = %x\n", Connection
));
411 TI_DbgPrint(MID_TRACE
,("Connection->SocketContext = %x\n",
412 Connection
->SocketContext
));
414 OskitDumpBuffer( BufferData
, PacketSize
);
416 Status
= OskitTCPSend( Connection
->SocketContext
,
417 BufferData
, PacketSize
, (PUINT
)DataUsed
, 0 );
419 RecursiveMutexLeave( &TCPLock
);
424 VOID
TCPTimeout(VOID
) {
425 static int Times
= 0;
426 if( (Times
++ % 5) == 0 ) {
427 RecursiveMutexEnter( &TCPLock
, TRUE
);
429 RecursiveMutexLeave( &TCPLock
);