- Removed prefix.c and the prefix list. Adapter and route netmasks are now
[reactos.git] / reactos / drivers / lib / ip / transport / tcp / tcp.c
1 /*
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)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
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;
19
20 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
21 PCONNECTION_ENDPOINT Connection =
22 ExAllocatePool(NonPagedPool, sizeof(CONNECTION_ENDPOINT));
23 if (!Connection)
24 return Connection;
25
26 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
27
28 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
29
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);
35
36 /* Save client context pointer */
37 Connection->ClientContext = ClientContext;
38
39 /* Initialize received segments queue */
40 InitializeListHead(&Connection->ReceivedSegments);
41
42 return Connection;
43 }
44
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 );
49 }
50
51 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
52 UINT Family, UINT Type, UINT Proto ) {
53 NTSTATUS Status;
54
55 TI_DbgPrint(MID_TRACE,("Called: Connection %x, Family %d, Type %d, "
56 "Proto %d\n",
57 Connection, Family, Type, Proto));
58
59 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
60 Status = TCPTranslateError( OskitTCPSocket( Connection,
61 &Connection->SocketContext,
62 Family,
63 Type,
64 Proto ) );
65
66 ASSERT_KM_POINTER(Connection->SocketContext);
67
68 TI_DbgPrint(MID_TRACE,("Connection->SocketContext %x\n",
69 Connection->SocketContext));
70
71 TcpipRecursiveMutexLeave( &TCPLock );
72
73 return Status;
74 }
75
76 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
77 /*
78 * FUNCTION: Receives and queues TCP data
79 * ARGUMENTS:
80 * IPPacket = Pointer to an IP packet that was received
81 * NOTES:
82 * This is the low level interface for receiving TCP data
83 */
84 {
85 TI_DbgPrint(MID_TRACE,("Sending packet %d (%d) to oskit\n",
86 IPPacket->TotalSize,
87 IPPacket->HeaderSize));
88
89 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
90
91 OskitTCPReceiveDatagram( IPPacket->Header,
92 IPPacket->TotalSize,
93 IPPacket->HeaderSize );
94
95 TcpipRecursiveMutexLeave( &TCPLock );
96 }
97
98 /* event.c */
99 int TCPSocketState( void *ClientData,
100 void *WhichSocket,
101 void *WhichConnection,
102 OSK_UINT NewState );
103
104 int TCPPacketSend( void *ClientData,
105 OSK_PCHAR Data,
106 OSK_UINT Len );
107
108 POSK_IFADDR TCPFindInterface( void *ClientData,
109 OSK_UINT AddrType,
110 OSK_UINT FindType,
111 OSK_SOCKADDR *ReqAddr );
112
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 );
117
118 int TCPSleep( void *ClientData, void *token, int priority, char *msg,
119 int tmio );
120
121 void TCPWakeup( void *ClientData, void *token );
122
123 OSKITTCP_EVENT_HANDLERS EventHandlers = {
124 NULL, /* Client Data */
125 TCPSocketState, /* SocketState */
126 TCPPacketSend, /* PacketSend */
127 TCPFindInterface, /* FindInterface */
128 TCPMalloc, /* Malloc */
129 TCPFree, /* Free */
130 TCPSleep, /* Sleep */
131 TCPWakeup /* Wakeup */
132 };
133
134 NTSTATUS TCPStartup(VOID)
135 /*
136 * FUNCTION: Initializes the TCP subsystem
137 * RETURNS:
138 * Status of operation
139 */
140 {
141 TcpipRecursiveMutexInit( &TCPLock );
142 ExInitializeFastMutex( &SleepingThreadsLock );
143 InitializeListHead( &SleepingThreadsList );
144
145 RegisterOskitTCPEventHandlers( &EventHandlers );
146 InitOskitTCP();
147
148 /* Register this protocol with IP layer */
149 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
150
151 ExInitializeNPagedLookasideList(
152 &TCPSegmentList, /* Lookaside list */
153 NULL, /* Allocate routine */
154 NULL, /* Free routine */
155 0, /* Flags */
156 sizeof(TCP_SEGMENT), /* Size of each entry */
157 TAG('T','C','P','S'), /* Tag */
158 0); /* Depth */
159
160 TCPInitialized = TRUE;
161
162 return STATUS_SUCCESS;
163 }
164
165
166 NTSTATUS TCPShutdown(VOID)
167 /*
168 * FUNCTION: Shuts down the TCP subsystem
169 * RETURNS:
170 * Status of operation
171 */
172 {
173 if (!TCPInitialized)
174 return STATUS_SUCCESS;
175
176 /* Deregister this protocol with IP layer */
177 IPRegisterProtocol(IPPROTO_TCP, NULL);
178
179 ExDeleteNPagedLookasideList(&TCPSegmentList);
180
181 TCPInitialized = FALSE;
182
183 DeinitOskitTCP();
184
185 return STATUS_SUCCESS;
186 }
187
188 NTSTATUS TCPTranslateError( int OskitError ) {
189 NTSTATUS Status = STATUS_UNSUCCESSFUL;
190
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;
200 }
201
202 TI_DbgPrint(MID_TRACE,("Error %d -> %x\n", OskitError, Status));
203 return Status;
204 }
205
206 #if 0
207 NTSTATUS TCPBind
208 ( PCONNECTION_ENDPOINT Connection,
209 PTDI_CONNECTION_INFORMATION ConnInfo ) {
210 NTSTATUS Status;
211 SOCKADDR_IN AddressToConnect;
212 PIP_ADDRESS LocalAddress;
213 USHORT LocalPort;
214
215 TI_DbgPrint(MID_TRACE,("Called\n"));
216
217 Status = AddrBuildAddress
218 ((PTA_ADDRESS)ConnInfo->LocalAddress,
219 &LocalAddress,
220 &LocalPort);
221
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;
227
228 Status = OskitTCPBind( Connection->SocketContext,
229 Connection,
230 &AddressToBind,
231 sizeof(AddressToBind));
232
233 TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));
234
235 return Status;
236 }
237 #endif
238
239 NTSTATUS TCPConnect
240 ( PCONNECTION_ENDPOINT Connection,
241 PTDI_CONNECTION_INFORMATION ConnInfo,
242 PTDI_CONNECTION_INFORMATION ReturnInfo,
243 PTCP_COMPLETION_ROUTINE Complete,
244 PVOID Context ) {
245 NTSTATUS Status;
246 SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
247 PIP_ADDRESS RemoteAddress;
248 USHORT RemotePort;
249 PTDI_BUCKET Bucket;
250
251 DbgPrint("TCPConnect: Called\n");
252
253 Bucket = ExAllocatePool( NonPagedPool, sizeof(*Bucket) );
254 if( !Bucket ) return STATUS_NO_MEMORY;
255
256 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
257
258 /* Freed in TCPSocketState */
259 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
260 Bucket->Request.RequestContext = Context;
261
262 InsertHeadList( &Connection->ConnectRequest, &Bucket->Entry );
263
264 Status = AddrBuildAddress
265 ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
266 &RemoteAddress,
267 &RemotePort);
268
269 DbgPrint("Connecting to address %x:%x\n",
270 RemoteAddress->Address.IPv4Address,
271 RemotePort);
272
273 if (!NT_SUCCESS(Status)) {
274 TI_DbgPrint(MID_TRACE, ("Could not AddrBuildAddress in TCPConnect\n"));
275 return Status;
276 }
277
278 AddressToConnect.sin_family = AF_INET;
279 AddressToBind = AddressToConnect;
280
281 OskitTCPBind( Connection->SocketContext,
282 Connection,
283 &AddressToBind,
284 sizeof(AddressToBind) );
285
286 memcpy( &AddressToConnect.sin_addr,
287 &RemoteAddress->Address.IPv4Address,
288 sizeof(AddressToConnect.sin_addr) );
289 AddressToConnect.sin_port = RemotePort;
290
291 Status = OskitTCPConnect(Connection->SocketContext,
292 Connection,
293 &AddressToConnect,
294 sizeof(AddressToConnect));
295
296 TcpipRecursiveMutexLeave( &TCPLock );
297
298 if( Status == OSK_EINPROGRESS || Status == STATUS_SUCCESS )
299 return STATUS_PENDING;
300 else
301 return Status;
302 }
303
304 NTSTATUS TCPClose
305 ( PCONNECTION_ENDPOINT Connection ) {
306 NTSTATUS Status;
307
308 TI_DbgPrint(MID_TRACE,("TCPClose started\n"));
309
310 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
311
312 Status = TCPTranslateError( OskitTCPClose( Connection->SocketContext ) );
313
314 TcpipRecursiveMutexLeave( &TCPLock );
315
316 TI_DbgPrint(MID_TRACE,("TCPClose finished %x\n", Status));
317
318 return Status;
319 }
320
321 NTSTATUS TCPListen
322 ( PCONNECTION_ENDPOINT Connection,
323 UINT Backlog,
324 PTCP_COMPLETION_ROUTINE Complete,
325 PVOID Context) {
326 NTSTATUS Status;
327
328 TI_DbgPrint(MID_TRACE,("TCPListen started\n"));
329
330 TI_DbgPrint(MID_TRACE,("Connection->SocketContext %x\n",
331 Connection->SocketContext));
332
333 ASSERT(Connection);
334 ASSERT_KM_POINTER(Connection->SocketContext);
335
336 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
337
338 Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext,
339 Backlog ) );
340
341 TcpipRecursiveMutexLeave( &TCPLock );
342
343 TI_DbgPrint(MID_TRACE,("TCPListen finished %x\n", Status));
344
345 return Status;
346 }
347
348 NTSTATUS TCPAccept
349 ( PTDI_REQUEST Request,
350 VOID **NewSocketContext ) {
351 NTSTATUS Status;
352
353 TI_DbgPrint(MID_TRACE,("TCPAccept started\n"));
354 Status = STATUS_UNSUCCESSFUL;
355 TI_DbgPrint(MID_TRACE,("TCPAccept finished %x\n", Status));
356 return Status;
357 }
358
359 VOID TCPCancelReceiveRequest( PVOID Context ) {
360 PLIST_ENTRY ListEntry;
361 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Context;
362
363 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
364 for( ListEntry = Connection->ReceiveRequest.Flink;
365 ListEntry != &Connection->ReceiveRequest;
366 ListEntry = ListEntry->Flink ) {
367
368 }
369 TcpipRecursiveMutexLeave( &TCPLock );
370 }
371
372 NTSTATUS TCPReceiveData
373 ( PCONNECTION_ENDPOINT Connection,
374 PNDIS_BUFFER Buffer,
375 ULONG ReceiveLength,
376 PULONG BytesReceived,
377 ULONG ReceiveFlags,
378 PTCP_COMPLETION_ROUTINE Complete,
379 PVOID Context ) {
380 PCHAR DataBuffer;
381 UINT DataLen, Received = 0;
382 NTSTATUS Status;
383 PTDI_BUCKET Bucket;
384
385 TI_DbgPrint(MID_TRACE,("Called for %d bytes\n", ReceiveLength));
386
387 ASSERT_KM_POINTER(Connection->SocketContext);
388
389 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
390
391 NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
392
393 TI_DbgPrint(MID_TRACE,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
394
395 Status = TCPTranslateError
396 ( OskitTCPRecv
397 ( Connection->SocketContext,
398 DataBuffer,
399 DataLen,
400 &Received,
401 ReceiveFlags ) );
402
403 TI_DbgPrint(MID_TRACE,("OskitTCPReceive: %x, %d\n", Status, Received));
404
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) );
410 if( !Bucket ) {
411 TI_DbgPrint(MID_TRACE,("Failed to allocate bucket\n"));
412 TcpipRecursiveMutexLeave( &TCPLock );
413 return STATUS_NO_MEMORY;
414 }
415
416 Bucket->Request.RequestNotifyObject = Complete;
417 Bucket->Request.RequestContext = Context;
418 *BytesReceived = 0;
419
420 InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
421 Status = STATUS_PENDING;
422 TI_DbgPrint(MID_TRACE,("Queued read irp\n"));
423 } else {
424 TI_DbgPrint(MID_TRACE,("Got status %x, bytes %d\n", Status, Received));
425 *BytesReceived = Received;
426 }
427
428 TcpipRecursiveMutexLeave( &TCPLock );
429
430 TI_DbgPrint(MID_TRACE,("Status %x\n", Status));
431
432 return Status;
433 }
434
435 NTSTATUS TCPSendData
436 ( PCONNECTION_ENDPOINT Connection,
437 PCHAR BufferData,
438 ULONG PacketSize,
439 PULONG DataUsed,
440 ULONG Flags) {
441 NTSTATUS Status;
442
443 ASSERT_KM_POINTER(Connection->SocketContext);
444
445 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
446
447 TI_DbgPrint(MID_TRACE,("Connection = %x\n", Connection));
448 TI_DbgPrint(MID_TRACE,("Connection->SocketContext = %x\n",
449 Connection->SocketContext));
450
451 Status = OskitTCPSend( Connection->SocketContext,
452 BufferData, PacketSize, (PUINT)DataUsed, 0 );
453
454 TcpipRecursiveMutexLeave( &TCPLock );
455
456 return Status;
457 }
458
459 VOID TCPTimeout(VOID) {
460 static int Times = 0;
461 if( (Times++ % 5) == 0 ) {
462 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
463 TimerOskitTCP();
464 TcpipRecursiveMutexLeave( &TCPLock );
465 }
466 }
467
468 /* EOF */