[IP]
[reactos.git] / reactos / lib / drivers / 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 * Art Yerkes (arty@users.sf.net)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * arty 12/21/2004 Added accept
11 */
12
13 #include "precomp.h"
14
15 LONG TCP_IPIdentification = 0;
16 static BOOLEAN TCPInitialized = FALSE;
17 static NPAGED_LOOKASIDE_LIST TCPSegmentList;
18 PORT_SET TCPPorts;
19 CLIENT_DATA ClientInfo;
20
21 VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
22 {
23 PTDI_BUCKET Bucket;
24 PLIST_ENTRY Entry;
25 NTSTATUS Status;
26 PIRP Irp;
27 PMDL Mdl;
28 KIRQL OldIrql;
29 PTCP_COMPLETION_ROUTINE Complete;
30
31 if (ClientInfo.Unlocked)
32 LockObjectAtDpcLevel(Connection);
33
34 TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
35 Connection, Connection->SocketContext));
36
37 /* Things that can happen when we try the initial connection */
38 if( Connection->SignalState & (SEL_CONNECT | SEL_FIN) ) {
39 while (!IsListEmpty(&Connection->ConnectRequest)) {
40 Entry = RemoveHeadList( &Connection->ConnectRequest );
41
42 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
43
44 Bucket->Status = (Connection->SignalState & SEL_CONNECT) ? STATUS_SUCCESS : STATUS_CANCELLED;
45 Bucket->Information = 0;
46
47 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
48 }
49 }
50
51 if( Connection->SignalState & (SEL_ACCEPT | SEL_FIN) ) {
52 /* Handle readable on a listening socket --
53 * TODO: Implement filtering
54 */
55 TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
56 Connection,
57 IsListEmpty(&Connection->ListenRequest) ?
58 "empty" : "nonempty"));
59
60 while (!IsListEmpty(&Connection->ListenRequest)) {
61 PIO_STACK_LOCATION IrpSp;
62
63 Entry = RemoveHeadList( &Connection->ListenRequest );
64
65 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
66
67 Irp = Bucket->Request.RequestContext;
68 IrpSp = IoGetCurrentIrpStackLocation( Irp );
69
70 TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
71
72 Status = TCPServiceListeningSocket
73 ( Connection->AddressFile->Listener,
74 Bucket->AssociatedEndpoint,
75 (PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
76
77 TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
78
79 if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
80 InsertHeadList( &Connection->ListenRequest, &Bucket->Entry );
81 break;
82 } else {
83 Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
84 Bucket->Information = 0;
85 DereferenceObject(Bucket->AssociatedEndpoint);
86
87 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
88 }
89 }
90 }
91
92 /* Things that happen after we're connected */
93 if( Connection->SignalState & (SEL_READ | SEL_FIN) ) {
94 TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
95 IsListEmpty(&Connection->ReceiveRequest) ?
96 "empty" : "nonempty"));
97
98 while (!IsListEmpty(&Connection->ReceiveRequest)) {
99 OSK_UINT RecvLen = 0, Received = 0;
100 PVOID RecvBuffer = 0;
101
102 Entry = RemoveHeadList( &Connection->ReceiveRequest );
103
104 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
105
106 Irp = Bucket->Request.RequestContext;
107 Mdl = Irp->MdlAddress;
108
109 TI_DbgPrint(DEBUG_TCP,
110 ("Getting the user buffer from %x\n", Mdl));
111
112 NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
113
114 TI_DbgPrint(DEBUG_TCP,
115 ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
116
117 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
118 TI_DbgPrint
119 (DEBUG_TCP,
120 ("Connection->SocketContext: %x\n",
121 Connection->SocketContext));
122 TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
123
124 Status = TCPTranslateError
125 ( OskitTCPRecv( Connection->SocketContext,
126 RecvBuffer,
127 RecvLen,
128 &Received,
129 0 ) );
130
131 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
132
133 if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
134 InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
135 break;
136 } else {
137 TI_DbgPrint(DEBUG_TCP,
138 ("Completing Receive request: %x %x\n",
139 Bucket->Request, Status));
140
141 Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
142 Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Received : 0;
143
144 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
145 }
146 }
147 }
148 if( Connection->SignalState & (SEL_WRITE | SEL_FIN) ) {
149 TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
150 IsListEmpty(&Connection->SendRequest) ?
151 "empty" : "nonempty"));
152
153 while (!IsListEmpty(&Connection->SendRequest)) {
154 OSK_UINT SendLen = 0, Sent = 0;
155 PVOID SendBuffer = 0;
156
157 Entry = RemoveHeadList( &Connection->SendRequest );
158
159 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
160
161 Irp = Bucket->Request.RequestContext;
162 Mdl = Irp->MdlAddress;
163
164 TI_DbgPrint(DEBUG_TCP,
165 ("Getting the user buffer from %x\n", Mdl));
166
167 NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
168
169 TI_DbgPrint(DEBUG_TCP,
170 ("Writing %d bytes to %x\n", SendLen, SendBuffer));
171
172 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
173 TI_DbgPrint
174 (DEBUG_TCP,
175 ("Connection->SocketContext: %x\n",
176 Connection->SocketContext));
177
178 Status = TCPTranslateError
179 ( OskitTCPSend( Connection->SocketContext,
180 SendBuffer,
181 SendLen,
182 &Sent,
183 0 ) );
184
185 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
186
187 if( Status == STATUS_PENDING && !(Connection->SignalState & SEL_FIN) ) {
188 InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
189 break;
190 } else {
191 TI_DbgPrint(DEBUG_TCP,
192 ("Completing Send request: %x %x\n",
193 Bucket->Request, Status));
194
195 Bucket->Status = (Status == STATUS_PENDING) ? STATUS_CANCELLED : Status;
196 Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? Sent : 0;
197
198 InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
199 }
200 }
201 }
202
203 ReferenceObject(Connection);
204 if (ClientInfo.Unlocked)
205 {
206 UnlockObjectFromDpcLevel(Connection);
207 KeReleaseSpinLock(&ClientInfo.Lock, ClientInfo.OldIrql);
208 }
209 else
210 {
211 UnlockObject(Connection, Connection->OldIrql);
212 }
213
214 while ((Entry = ExInterlockedRemoveHeadList(&Connection->CompletionQueue,
215 &Connection->Lock)))
216 {
217 Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
218 Complete = Bucket->Request.RequestNotifyObject;
219
220 Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
221
222 ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
223 }
224
225 if (!ClientInfo.Unlocked)
226 {
227 LockObject(Connection, &OldIrql);
228 }
229 else
230 {
231 KeAcquireSpinLock(&ClientInfo.Lock, &ClientInfo.OldIrql);
232 }
233 DereferenceObject(Connection);
234
235 /* If the socket is dead, remove the reference we added for oskit */
236 if (Connection->SignalState & SEL_FIN)
237 DereferenceObject(Connection);
238 }
239
240 VOID ConnectionFree(PVOID Object) {
241 PCONNECTION_ENDPOINT Connection = Object;
242 KIRQL OldIrql;
243
244 TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
245
246 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
247 RemoveEntryList(&Connection->ListEntry);
248 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
249
250 ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
251 }
252
253 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
254 PCONNECTION_ENDPOINT Connection =
255 ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT),
256 CONN_ENDPT_TAG);
257 if (!Connection)
258 return Connection;
259
260 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
261
262 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
263
264 /* Initialize spin lock that protects the connection endpoint file object */
265 KeInitializeSpinLock(&Connection->Lock);
266 InitializeListHead(&Connection->ConnectRequest);
267 InitializeListHead(&Connection->ListenRequest);
268 InitializeListHead(&Connection->ReceiveRequest);
269 InitializeListHead(&Connection->SendRequest);
270 InitializeListHead(&Connection->CompletionQueue);
271
272 /* Save client context pointer */
273 Connection->ClientContext = ClientContext;
274
275 /* Add an extra reference for oskit */
276 Connection->RefCount = 2;
277 Connection->Free = ConnectionFree;
278
279 /* Add connection endpoint to global list */
280 ExInterlockedInsertTailList(&ConnectionEndpointListHead,
281 &Connection->ListEntry,
282 &ConnectionEndpointListLock);
283
284 return Connection;
285 }
286
287 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
288 UINT Family, UINT Type, UINT Proto ) {
289 NTSTATUS Status;
290 KIRQL OldIrql;
291
292 LockObject(Connection, &OldIrql);
293
294 TI_DbgPrint(DEBUG_TCP,("Called: Connection %x, Family %d, Type %d, "
295 "Proto %d\n",
296 Connection, Family, Type, Proto));
297
298 Status = TCPTranslateError( OskitTCPSocket( Connection,
299 &Connection->SocketContext,
300 Family,
301 Type,
302 Proto ) );
303
304 ASSERT_KM_POINTER(Connection->SocketContext);
305
306 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
307 Connection->SocketContext));
308
309 UnlockObject(Connection, OldIrql);
310
311 return Status;
312 }
313
314 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
315 /*
316 * FUNCTION: Receives and queues TCP data
317 * ARGUMENTS:
318 * IPPacket = Pointer to an IP packet that was received
319 * NOTES:
320 * This is the low level interface for receiving TCP data
321 */
322 {
323 KIRQL OldIrql;
324
325 TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
326 IPPacket->TotalSize,
327 IPPacket->HeaderSize));
328
329 KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql);
330 ClientInfo.Unlocked = TRUE;
331 ClientInfo.OldIrql = OldIrql;
332
333 OskitTCPReceiveDatagram( IPPacket->Header,
334 IPPacket->TotalSize,
335 IPPacket->HeaderSize );
336
337 ClientInfo.Unlocked = FALSE;
338 KeReleaseSpinLock(&ClientInfo.Lock, OldIrql);
339 }
340
341 /* event.c */
342 int TCPSocketState( void *ClientData,
343 void *WhichSocket,
344 void *WhichConnection,
345 OSK_UINT NewState );
346
347 int TCPPacketSend( void *ClientData,
348 OSK_PCHAR Data,
349 OSK_UINT Len );
350
351 POSK_IFADDR TCPFindInterface( void *ClientData,
352 OSK_UINT AddrType,
353 OSK_UINT FindType,
354 OSK_SOCKADDR *ReqAddr );
355
356 NTSTATUS TCPMemStartup( void );
357 void *TCPMalloc( void *ClientData,
358 OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
359 void TCPFree( void *ClientData,
360 void *data, OSK_PCHAR file, OSK_UINT line );
361 void TCPMemShutdown( void );
362
363 OSKITTCP_EVENT_HANDLERS EventHandlers = {
364 NULL, /* Client Data */
365 TCPSocketState, /* SocketState */
366 TCPPacketSend, /* PacketSend */
367 TCPFindInterface, /* FindInterface */
368 TCPMalloc, /* Malloc */
369 TCPFree, /* Free */
370 NULL, /* Sleep */
371 NULL, /* Wakeup */
372 };
373
374 static KEVENT TimerLoopEvent;
375 static HANDLE TimerThreadHandle;
376
377 /*
378 * We are running 2 timers here, one with a 200ms interval (fast) and the other
379 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
380 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
381 * "slow" events at 500 and 1000.
382 */
383 static VOID NTAPI
384 TimerThread(PVOID Context)
385 {
386 LARGE_INTEGER Timeout;
387 NTSTATUS Status;
388 unsigned Current, NextFast, NextSlow, Next;
389
390 Current = 0;
391 Next = 0;
392 NextFast = 0;
393 NextSlow = 0;
394 while ( 1 ) {
395 if (Next == NextFast) {
396 NextFast += 2;
397 }
398 if (Next == NextSlow) {
399 NextSlow += 5;
400 }
401 Next = min(NextFast, NextSlow);
402 Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */
403 Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode,
404 FALSE, &Timeout);
405 if (Status != STATUS_TIMEOUT) {
406 PsTerminateSystemThread(Status);
407 }
408
409 TimerOskitTCP( Next == NextFast, Next == NextSlow );
410
411 Current = Next;
412 if (10 <= Current) {
413 Current = 0;
414 Next = 0;
415 NextFast = 0;
416 NextSlow = 0;
417 }
418 }
419 }
420
421 static VOID
422 StartTimer(VOID)
423 {
424 KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
425 PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
426 TimerThread, NULL);
427 }
428
429 NTSTATUS TCPStartup(VOID)
430 /*
431 * FUNCTION: Initializes the TCP subsystem
432 * RETURNS:
433 * Status of operation
434 */
435 {
436 NTSTATUS Status;
437
438 Status = TCPMemStartup();
439 if ( ! NT_SUCCESS(Status) ) {
440 return Status;
441 }
442
443 Status = PortsStartup( &TCPPorts, 1, 0xfffe );
444 if( !NT_SUCCESS(Status) ) {
445 TCPMemShutdown();
446 return Status;
447 }
448
449 KeInitializeSpinLock(&ClientInfo.Lock);
450 ClientInfo.Unlocked = FALSE;
451
452 RegisterOskitTCPEventHandlers( &EventHandlers );
453 InitOskitTCP();
454
455 /* Register this protocol with IP layer */
456 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
457
458 ExInitializeNPagedLookasideList(
459 &TCPSegmentList, /* Lookaside list */
460 NULL, /* Allocate routine */
461 NULL, /* Free routine */
462 0, /* Flags */
463 sizeof(TCP_SEGMENT), /* Size of each entry */
464 'SPCT', /* Tag */
465 0); /* Depth */
466
467 StartTimer();
468
469 TCPInitialized = TRUE;
470
471 return STATUS_SUCCESS;
472 }
473
474
475 NTSTATUS TCPShutdown(VOID)
476 /*
477 * FUNCTION: Shuts down the TCP subsystem
478 * RETURNS:
479 * Status of operation
480 */
481 {
482 LARGE_INTEGER WaitForThread;
483
484 if (!TCPInitialized)
485 return STATUS_SUCCESS;
486
487 WaitForThread.QuadPart = -2500000; /* 250 ms */
488 KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
489 ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
490
491 /* Deregister this protocol with IP layer */
492 IPRegisterProtocol(IPPROTO_TCP, NULL);
493
494 ExDeleteNPagedLookasideList(&TCPSegmentList);
495
496 TCPInitialized = FALSE;
497
498 DeinitOskitTCP();
499
500 PortsShutdown( &TCPPorts );
501
502 TCPMemShutdown();
503
504 return STATUS_SUCCESS;
505 }
506
507 NTSTATUS TCPTranslateError( int OskitError ) {
508 NTSTATUS Status;
509
510 switch( OskitError ) {
511 case 0: Status = STATUS_SUCCESS; break;
512 case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
513 case OSK_EADDRINUSE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break;
514 case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
515 case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break;
516 case OSK_ECONNRESET: Status = STATUS_REMOTE_DISCONNECT; break;
517 case OSK_ECONNABORTED: Status = STATUS_LOCAL_DISCONNECT; break;
518 case OSK_EWOULDBLOCK:
519 case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
520 case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break;
521 case OSK_ENOMEM:
522 case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break;
523 case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break;
524 case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break;
525 case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break;
526 case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break;
527 case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break;
528 default:
529 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
530 Status = STATUS_INVALID_CONNECTION;
531 break;
532 }
533
534 TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
535 return Status;
536 }
537
538 NTSTATUS TCPConnect
539 ( PCONNECTION_ENDPOINT Connection,
540 PTDI_CONNECTION_INFORMATION ConnInfo,
541 PTDI_CONNECTION_INFORMATION ReturnInfo,
542 PTCP_COMPLETION_ROUTINE Complete,
543 PVOID Context ) {
544 NTSTATUS Status;
545 SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
546 IP_ADDRESS RemoteAddress;
547 USHORT RemotePort;
548 PTDI_BUCKET Bucket;
549 PNEIGHBOR_CACHE_ENTRY NCE;
550 KIRQL OldIrql;
551
552 TI_DbgPrint(DEBUG_TCP,("TCPConnect: Called\n"));
553
554 Status = AddrBuildAddress
555 ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
556 &RemoteAddress,
557 &RemotePort);
558
559 if (!NT_SUCCESS(Status)) {
560 TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
561 return Status;
562 }
563
564 /* Freed in TCPSocketState */
565 TI_DbgPrint(DEBUG_TCP,
566 ("Connecting to address %x:%x\n",
567 RemoteAddress.Address.IPv4Address,
568 RemotePort));
569
570 AddressToConnect.sin_family = AF_INET;
571 AddressToBind = AddressToConnect;
572
573 LockObject(Connection, &OldIrql);
574
575 if (!Connection->AddressFile)
576 {
577 UnlockObject(Connection, OldIrql);
578 return STATUS_INVALID_PARAMETER;
579 }
580
581 if (AddrIsUnspecified(&Connection->AddressFile->Address))
582 {
583 if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
584 {
585 UnlockObject(Connection, OldIrql);
586 return STATUS_NETWORK_UNREACHABLE;
587 }
588
589 AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
590 }
591 else
592 {
593 AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address;
594 }
595
596 Status = TCPTranslateError
597 ( OskitTCPBind( Connection->SocketContext,
598 &AddressToBind,
599 sizeof(AddressToBind) ) );
600
601 if (NT_SUCCESS(Status)) {
602 memcpy( &AddressToConnect.sin_addr,
603 &RemoteAddress.Address.IPv4Address,
604 sizeof(AddressToConnect.sin_addr) );
605 AddressToConnect.sin_port = RemotePort;
606
607 Status = TCPTranslateError
608 ( OskitTCPConnect( Connection->SocketContext,
609 &AddressToConnect,
610 sizeof(AddressToConnect) ) );
611
612 if (Status == STATUS_PENDING)
613 {
614 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
615 if( !Bucket )
616 {
617 UnlockObject(Connection, OldIrql);
618 return STATUS_NO_MEMORY;
619 }
620
621 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
622 Bucket->Request.RequestContext = Context;
623
624 InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
625 }
626 }
627
628 UnlockObject(Connection, OldIrql);
629
630 return Status;
631 }
632
633 NTSTATUS TCPDisconnect
634 ( PCONNECTION_ENDPOINT Connection,
635 UINT Flags,
636 PTDI_CONNECTION_INFORMATION ConnInfo,
637 PTDI_CONNECTION_INFORMATION ReturnInfo,
638 PTCP_COMPLETION_ROUTINE Complete,
639 PVOID Context ) {
640 NTSTATUS Status = STATUS_INVALID_PARAMETER;
641 KIRQL OldIrql;
642
643 TI_DbgPrint(DEBUG_TCP,("started\n"));
644
645 LockObject(Connection, &OldIrql);
646
647 if (Flags & TDI_DISCONNECT_RELEASE)
648 Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
649
650 if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
651 Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
652
653 UnlockObject(Connection, OldIrql);
654
655 TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
656
657 return Status;
658 }
659
660 NTSTATUS TCPClose
661 ( PCONNECTION_ENDPOINT Connection )
662 {
663 KIRQL OldIrql;
664 NTSTATUS Status;
665 PVOID Socket;
666
667 /* We don't rely on SocketContext == NULL for socket
668 * closure anymore but we still need it to determine
669 * if we caused the closure
670 */
671 LockObject(Connection, &OldIrql);
672 Socket = Connection->SocketContext;
673 Connection->SocketContext = NULL;
674
675 /* Don't try to close again if the other side closed us already */
676 if (!(Connection->SignalState & SEL_FIN))
677 {
678 /* We need to close here otherwise oskit will never indicate
679 * SEL_FIN and we will never fully close the connection */
680 Status = TCPTranslateError( OskitTCPClose( Socket ) );
681
682 if (!NT_SUCCESS(Status))
683 {
684 Connection->SocketContext = Socket;
685 UnlockObject(Connection, OldIrql);
686 return Status;
687 }
688 }
689 else
690 {
691 /* We are already closed by the other end so return success */
692 Status = STATUS_SUCCESS;
693 }
694
695 if (Connection->AddressFile)
696 DereferenceObject(Connection->AddressFile);
697
698 UnlockObject(Connection, OldIrql);
699
700 DereferenceObject(Connection);
701
702 return Status;
703 }
704
705 NTSTATUS TCPReceiveData
706 ( PCONNECTION_ENDPOINT Connection,
707 PNDIS_BUFFER Buffer,
708 ULONG ReceiveLength,
709 PULONG BytesReceived,
710 ULONG ReceiveFlags,
711 PTCP_COMPLETION_ROUTINE Complete,
712 PVOID Context ) {
713 PVOID DataBuffer;
714 UINT DataLen, Received = 0;
715 NTSTATUS Status;
716 PTDI_BUCKET Bucket;
717 KIRQL OldIrql;
718
719 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
720 ReceiveLength, Connection->SocketContext));
721
722 NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
723
724 TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
725
726 LockObject(Connection, &OldIrql);
727
728 Status = TCPTranslateError
729 ( OskitTCPRecv
730 ( Connection->SocketContext,
731 DataBuffer,
732 DataLen,
733 &Received,
734 ReceiveFlags ) );
735
736 TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
737
738 /* Keep this request around ... there was no data yet */
739 if( Status == STATUS_PENDING ) {
740 /* Freed in TCPSocketState */
741 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
742 if( !Bucket ) {
743 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
744 UnlockObject(Connection, OldIrql);
745 return STATUS_NO_MEMORY;
746 }
747
748 Bucket->Request.RequestNotifyObject = Complete;
749 Bucket->Request.RequestContext = Context;
750 *BytesReceived = 0;
751
752 InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
753 TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
754 } else {
755 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
756 *BytesReceived = Received;
757 }
758
759 UnlockObject(Connection, OldIrql);
760
761 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
762
763 return Status;
764 }
765
766 NTSTATUS TCPSendData
767 ( PCONNECTION_ENDPOINT Connection,
768 PCHAR BufferData,
769 ULONG SendLength,
770 PULONG BytesSent,
771 ULONG Flags,
772 PTCP_COMPLETION_ROUTINE Complete,
773 PVOID Context ) {
774 UINT Sent = 0;
775 NTSTATUS Status;
776 PTDI_BUCKET Bucket;
777 KIRQL OldIrql;
778
779 LockObject(Connection, &OldIrql);
780
781 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
782 SendLength, Connection->SocketContext));
783
784 TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection));
785 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
786 Connection->SocketContext));
787
788 Status = TCPTranslateError
789 ( OskitTCPSend( Connection->SocketContext,
790 (OSK_PCHAR)BufferData, SendLength,
791 &Sent, 0 ) );
792
793 TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
794
795 /* Keep this request around ... there was no data yet */
796 if( Status == STATUS_PENDING ) {
797 /* Freed in TCPSocketState */
798 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
799 if( !Bucket ) {
800 UnlockObject(Connection, OldIrql);
801 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
802 return STATUS_NO_MEMORY;
803 }
804
805 Bucket->Request.RequestNotifyObject = Complete;
806 Bucket->Request.RequestContext = Context;
807 *BytesSent = 0;
808
809 InsertTailList( &Connection->SendRequest, &Bucket->Entry );
810 TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
811 } else {
812 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
813 *BytesSent = Sent;
814 }
815
816 UnlockObject(Connection, OldIrql);
817
818 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
819
820 return Status;
821 }
822
823 UINT TCPAllocatePort( UINT HintPort ) {
824 if( HintPort ) {
825 if( AllocatePort( &TCPPorts, HintPort ) ) return HintPort;
826 else {
827 TI_DbgPrint
828 (MID_TRACE,("We got a hint port but couldn't allocate it\n"));
829 return (UINT)-1;
830 }
831 } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
832 }
833
834 VOID TCPFreePort( UINT Port ) {
835 DeallocatePort( &TCPPorts, Port );
836 }
837
838 NTSTATUS TCPGetSockAddress
839 ( PCONNECTION_ENDPOINT Connection,
840 PTRANSPORT_ADDRESS Address,
841 BOOLEAN GetRemote ) {
842 OSK_UINT LocalAddress, RemoteAddress;
843 OSK_UI16 LocalPort, RemotePort;
844 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
845 NTSTATUS Status;
846 KIRQL OldIrql;
847
848 LockObject(Connection, &OldIrql);
849
850 Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext,
851 &LocalAddress, &LocalPort,
852 &RemoteAddress, &RemotePort));
853
854 UnlockObject(Connection, OldIrql);
855
856 if (!NT_SUCCESS(Status))
857 return Status;
858
859 AddressIP->TAAddressCount = 1;
860 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
861 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
862 AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort;
863 AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress;
864
865 return Status;
866 }
867
868 BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
869 PLIST_ENTRY Entry;
870 PLIST_ENTRY ListHead[4];
871 KIRQL OldIrql;
872 PTDI_BUCKET Bucket;
873 UINT i = 0;
874 BOOLEAN Found = FALSE;
875
876 ListHead[0] = &Endpoint->SendRequest;
877 ListHead[1] = &Endpoint->ReceiveRequest;
878 ListHead[2] = &Endpoint->ConnectRequest;
879 ListHead[3] = &Endpoint->ListenRequest;
880
881 LockObject(Endpoint, &OldIrql);
882
883 for( i = 0; i < 4; i++ )
884 {
885 for( Entry = ListHead[i]->Flink;
886 Entry != ListHead[i];
887 Entry = Entry->Flink )
888 {
889 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
890 if( Bucket->Request.RequestContext == Irp )
891 {
892 RemoveEntryList( &Bucket->Entry );
893 ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
894 Found = TRUE;
895 break;
896 }
897 }
898 }
899
900 UnlockObject(Endpoint, OldIrql);
901
902 return Found;
903 }
904
905 /* EOF */