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)
9 * CSH 01/08-2000 Created
10 * arty 12/21/2004 Added accept
15 LONG TCP_IPIdentification
= 0;
16 static BOOLEAN TCPInitialized
= FALSE
;
17 static NPAGED_LOOKASIDE_LIST TCPSegmentList
;
20 static VOID
DrainSignals() {
21 PCONNECTION_ENDPOINT Connection
;
22 PLIST_ENTRY CurrentEntry
, NextEntry
;
24 NTSTATUS Status
= STATUS_SUCCESS
;
25 PTCP_COMPLETION_ROUTINE Complete
;
31 KeAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
32 CurrentEntry
= ConnectionEndpointListHead
.Flink
;
33 while (CurrentEntry
!= &ConnectionEndpointListHead
)
35 NextEntry
= CurrentEntry
->Flink
;
36 KeReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
38 Connection
= CONTAINING_RECORD( CurrentEntry
, CONNECTION_ENDPOINT
,
41 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
43 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
44 Connection
, Connection
->SocketContext
));
46 if( !Connection
->SocketContext
|| Connection
->SignalState
& SEL_FIN
) {
47 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
48 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
50 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
51 &Connection
->Lock
)) != NULL
)
53 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
54 Complete
= Bucket
->Request
.RequestNotifyObject
;
56 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
61 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
62 &Connection
->Lock
)) != NULL
)
64 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
65 Complete
= Bucket
->Request
.RequestNotifyObject
;
67 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
72 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
73 &Connection
->Lock
)) != NULL
)
75 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
76 Complete
= Bucket
->Request
.RequestNotifyObject
;
78 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
83 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
84 &Connection
->Lock
)) != NULL
)
86 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
87 Complete
= Bucket
->Request
.RequestNotifyObject
;
89 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
94 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
97 /* Things that can happen when we try the initial connection */
98 if( Connection
->SignalState
& SEL_CONNECT
) {
99 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
100 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
101 &Connection
->Lock
)) != NULL
) {
103 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
105 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
106 Complete
= Bucket
->Request
.RequestNotifyObject
;
107 TI_DbgPrint(DEBUG_TCP
,
108 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
110 Complete( Bucket
->Request
.RequestContext
, STATUS_SUCCESS
, 0 );
112 /* Frees the bucket allocated in TCPConnect */
113 exFreePool( Bucket
);
115 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
118 if( Connection
->SignalState
& SEL_ACCEPT
) {
119 /* Handle readable on a listening socket --
120 * TODO: Implement filtering
123 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
125 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
127 IsListEmpty(&Connection
->ListenRequest
) ?
128 "empty" : "nonempty"));
130 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
131 &Connection
->Lock
)) != NULL
) {
132 PIO_STACK_LOCATION IrpSp
;
134 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
135 Complete
= Bucket
->Request
.RequestNotifyObject
;
137 Irp
= Bucket
->Request
.RequestContext
;
138 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
140 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
142 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
144 Status
= TCPServiceListeningSocket
145 ( Connection
->AddressFile
->Listener
,
146 Bucket
->AssociatedEndpoint
,
147 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
149 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
151 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
153 if( Status
== STATUS_PENDING
) {
154 ExInterlockedInsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
,
158 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
159 exFreePool( Bucket
);
163 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
166 /* Things that happen after we're connected */
167 if( Connection
->SignalState
& SEL_READ
&&
168 Connection
->SignalState
& SEL_CONNECT
) {
169 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
170 IsListEmpty(&Connection
->ReceiveRequest
) ?
171 "empty" : "nonempty"));
173 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
175 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
176 &Connection
->Lock
)) != NULL
) {
177 OSK_UINT RecvLen
= 0, Received
= 0;
178 PVOID RecvBuffer
= 0;
180 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
181 Complete
= Bucket
->Request
.RequestNotifyObject
;
183 Irp
= Bucket
->Request
.RequestContext
;
184 Mdl
= Irp
->MdlAddress
;
186 TI_DbgPrint(DEBUG_TCP
,
187 ("Getting the user buffer from %x\n", Mdl
));
189 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
191 TI_DbgPrint(DEBUG_TCP
,
192 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
194 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
197 ("Connection->SocketContext: %x\n",
198 Connection
->SocketContext
));
199 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
201 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
203 Status
= TCPTranslateError
204 ( OskitTCPRecv( Connection
->SocketContext
,
210 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
212 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
214 if( Status
== STATUS_SUCCESS
) {
215 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
217 Complete( Bucket
->Request
.RequestContext
,
218 STATUS_SUCCESS
, Received
);
219 exFreePool( Bucket
);
220 } else if( Status
== STATUS_PENDING
) {
221 ExInterlockedInsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
,
225 TI_DbgPrint(DEBUG_TCP
,
226 ("Completing Receive request: %x %x\n",
227 Bucket
->Request
, Status
));
228 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
229 exFreePool( Bucket
);
233 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
235 if( Connection
->SignalState
& SEL_WRITE
&&
236 Connection
->SignalState
& SEL_CONNECT
) {
237 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
238 IsListEmpty(&Connection
->SendRequest
) ?
239 "empty" : "nonempty"));
241 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
243 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
244 &Connection
->Lock
)) != NULL
) {
245 OSK_UINT SendLen
= 0, Sent
= 0;
246 PVOID SendBuffer
= 0;
248 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
249 Complete
= Bucket
->Request
.RequestNotifyObject
;
251 Irp
= Bucket
->Request
.RequestContext
;
252 Mdl
= Irp
->MdlAddress
;
254 TI_DbgPrint(DEBUG_TCP
,
255 ("Getting the user buffer from %x\n", Mdl
));
257 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
259 TI_DbgPrint(DEBUG_TCP
,
260 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
262 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
265 ("Connection->SocketContext: %x\n",
266 Connection
->SocketContext
));
268 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
270 Status
= TCPTranslateError
271 ( OskitTCPSend( Connection
->SocketContext
,
277 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
279 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
281 if( Status
== STATUS_SUCCESS
) {
282 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
284 Complete( Bucket
->Request
.RequestContext
,
285 STATUS_SUCCESS
, Sent
);
286 exFreePool( Bucket
);
287 } else if( Status
== STATUS_PENDING
) {
288 ExInterlockedInsertHeadList( &Connection
->SendRequest
, &Bucket
->Entry
,
292 TI_DbgPrint(DEBUG_TCP
,
293 ("Completing Send request: %x %x\n",
294 Bucket
->Request
, Status
));
295 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
296 exFreePool( Bucket
);
299 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
302 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
304 if (!Connection
->SocketContext
)
306 TCPFreeConnectionEndpoint(Connection
);
309 CurrentEntry
= NextEntry
;
311 KeAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
314 KeReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
317 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
318 PCONNECTION_ENDPOINT Connection
=
319 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
323 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
325 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
327 /* Initialize spin lock that protects the connection endpoint file object */
328 KeInitializeSpinLock(&Connection
->Lock
);
329 InitializeListHead(&Connection
->ConnectRequest
);
330 InitializeListHead(&Connection
->ListenRequest
);
331 InitializeListHead(&Connection
->ReceiveRequest
);
332 InitializeListHead(&Connection
->SendRequest
);
334 /* Save client context pointer */
335 Connection
->ClientContext
= ClientContext
;
337 /* Add connection endpoint to global list */
338 ExInterlockedInsertTailList(&ConnectionEndpointListHead
,
339 &Connection
->ListEntry
,
340 &ConnectionEndpointListLock
);
345 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
348 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
350 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
351 RemoveEntryList(&Connection
->ListEntry
);
352 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
354 exFreePool( Connection
);
357 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
358 UINT Family
, UINT Type
, UINT Proto
) {
362 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
364 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
366 Connection
, Family
, Type
, Proto
));
368 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
369 &Connection
->SocketContext
,
374 ASSERT_KM_POINTER(Connection
->SocketContext
);
376 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
377 Connection
->SocketContext
));
379 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
384 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
386 * FUNCTION: Receives and queues TCP data
388 * IPPacket = Pointer to an IP packet that was received
390 * This is the low level interface for receiving TCP data
393 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
395 IPPacket
->HeaderSize
));
397 OskitTCPReceiveDatagram( IPPacket
->Header
,
399 IPPacket
->HeaderSize
);
403 int TCPSocketState( void *ClientData
,
405 void *WhichConnection
,
408 int TCPPacketSend( void *ClientData
,
412 POSK_IFADDR
TCPFindInterface( void *ClientData
,
415 OSK_SOCKADDR
*ReqAddr
);
417 NTSTATUS
TCPMemStartup( void );
418 void *TCPMalloc( void *ClientData
,
419 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
420 void TCPFree( void *ClientData
,
421 void *data
, OSK_PCHAR file
, OSK_UINT line
);
422 void TCPMemShutdown( void );
424 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
425 NULL
, /* Client Data */
426 TCPSocketState
, /* SocketState */
427 TCPPacketSend
, /* PacketSend */
428 TCPFindInterface
, /* FindInterface */
429 TCPMalloc
, /* Malloc */
435 static KEVENT TimerLoopEvent
;
436 static HANDLE TimerThreadHandle
;
439 * We are running 2 timers here, one with a 200ms interval (fast) and the other
440 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
441 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
442 * "slow" events at 500 and 1000.
445 TimerThread(PVOID Context
)
447 LARGE_INTEGER Timeout
;
449 unsigned Current
, NextFast
, NextSlow
, Next
;
456 if (Next
== NextFast
) {
459 if (Next
== NextSlow
) {
462 Next
= min(NextFast
, NextSlow
);
463 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
464 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
466 if (Status
!= STATUS_TIMEOUT
) {
467 PsTerminateSystemThread(Status
);
470 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
471 if (Next
== NextSlow
) {
488 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
489 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
494 NTSTATUS
TCPStartup(VOID
)
496 * FUNCTION: Initializes the TCP subsystem
498 * Status of operation
503 Status
= TCPMemStartup();
504 if ( ! NT_SUCCESS(Status
) ) {
508 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
509 if( !NT_SUCCESS(Status
) ) {
514 RegisterOskitTCPEventHandlers( &EventHandlers
);
517 /* Register this protocol with IP layer */
518 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
520 ExInitializeNPagedLookasideList(
521 &TCPSegmentList
, /* Lookaside list */
522 NULL
, /* Allocate routine */
523 NULL
, /* Free routine */
525 sizeof(TCP_SEGMENT
), /* Size of each entry */
531 TCPInitialized
= TRUE
;
533 return STATUS_SUCCESS
;
537 NTSTATUS
TCPShutdown(VOID
)
539 * FUNCTION: Shuts down the TCP subsystem
541 * Status of operation
544 LARGE_INTEGER WaitForThread
;
547 return STATUS_SUCCESS
;
549 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
550 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
551 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
553 /* Deregister this protocol with IP layer */
554 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
556 ExDeleteNPagedLookasideList(&TCPSegmentList
);
558 TCPInitialized
= FALSE
;
562 PortsShutdown( &TCPPorts
);
566 return STATUS_SUCCESS
;
569 NTSTATUS
TCPTranslateError( int OskitError
) {
572 switch( OskitError
) {
573 case 0: Status
= STATUS_SUCCESS
; break;
574 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
575 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
576 case OSK_ECONNREFUSED
:
577 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
578 case OSK_EWOULDBLOCK
:
579 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
580 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
582 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
583 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
584 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
585 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
586 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
587 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
589 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
590 Status
= STATUS_INVALID_CONNECTION
;
594 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
599 ( PCONNECTION_ENDPOINT Connection
,
600 PTDI_CONNECTION_INFORMATION ConnInfo
,
601 PTDI_CONNECTION_INFORMATION ReturnInfo
,
602 PTCP_COMPLETION_ROUTINE Complete
,
605 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
606 IP_ADDRESS RemoteAddress
;
609 PNEIGHBOR_CACHE_ENTRY NCE
;
612 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
614 Status
= AddrBuildAddress
615 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
619 if (!NT_SUCCESS(Status
)) {
620 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
624 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
626 return STATUS_NETWORK_UNREACHABLE
;
629 /* Freed in TCPSocketState */
630 TI_DbgPrint(DEBUG_TCP
,
631 ("Connecting to address %x:%x\n",
632 RemoteAddress
.Address
.IPv4Address
,
635 AddressToConnect
.sin_family
= AF_INET
;
636 AddressToBind
= AddressToConnect
;
637 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
639 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
641 Status
= TCPTranslateError
642 ( OskitTCPBind( Connection
->SocketContext
,
644 sizeof(AddressToBind
) ) );
646 if (NT_SUCCESS(Status
)) {
647 memcpy( &AddressToConnect
.sin_addr
,
648 &RemoteAddress
.Address
.IPv4Address
,
649 sizeof(AddressToConnect
.sin_addr
) );
650 AddressToConnect
.sin_port
= RemotePort
;
652 Status
= TCPTranslateError
653 ( OskitTCPConnect( Connection
->SocketContext
,
655 sizeof(AddressToConnect
) ) );
657 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
659 if (Status
== STATUS_PENDING
)
661 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
664 return STATUS_NO_MEMORY
;
667 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
668 Bucket
->Request
.RequestContext
= Context
;
670 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
,
674 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
680 NTSTATUS TCPDisconnect
681 ( PCONNECTION_ENDPOINT Connection
,
683 PTDI_CONNECTION_INFORMATION ConnInfo
,
684 PTDI_CONNECTION_INFORMATION ReturnInfo
,
685 PTCP_COMPLETION_ROUTINE Complete
,
687 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
690 TI_DbgPrint(DEBUG_TCP
,("started\n"));
692 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
694 if (Flags
& TDI_DISCONNECT_RELEASE
)
695 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
697 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
698 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
700 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
702 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
708 ( PCONNECTION_ENDPOINT Connection
) {
713 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
715 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
716 Socket
= Connection
->SocketContext
;
717 Connection
->SocketContext
= NULL
;
718 Status
= TCPTranslateError( OskitTCPClose( Socket
) );
719 if (!NT_SUCCESS(Status
))
721 Connection
->SocketContext
= Socket
;
723 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
725 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
730 NTSTATUS TCPReceiveData
731 ( PCONNECTION_ENDPOINT Connection
,
734 PULONG BytesReceived
,
736 PTCP_COMPLETION_ROUTINE Complete
,
739 UINT DataLen
, Received
= 0;
744 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
745 ReceiveLength
, Connection
->SocketContext
));
747 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
749 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
751 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
753 ASSERT_KM_POINTER(Connection
->SocketContext
);
755 Status
= TCPTranslateError
757 ( Connection
->SocketContext
,
763 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
765 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
767 /* Keep this request around ... there was no data yet */
768 if( Status
== STATUS_PENDING
) {
769 /* Freed in TCPSocketState */
770 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
772 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
773 return STATUS_NO_MEMORY
;
776 Bucket
->Request
.RequestNotifyObject
= Complete
;
777 Bucket
->Request
.RequestContext
= Context
;
780 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
,
782 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
784 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
785 *BytesReceived
= Received
;
788 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
794 ( PCONNECTION_ENDPOINT Connection
,
799 PTCP_COMPLETION_ROUTINE Complete
,
806 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
808 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
809 SendLength
, Connection
->SocketContext
));
811 ASSERT_KM_POINTER(Connection
->SocketContext
);
813 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
814 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
815 Connection
->SocketContext
));
817 Status
= TCPTranslateError
818 ( OskitTCPSend( Connection
->SocketContext
,
819 (OSK_PCHAR
)BufferData
, SendLength
,
822 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
824 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
826 /* Keep this request around ... there was no data yet */
827 if( Status
== STATUS_PENDING
) {
828 /* Freed in TCPSocketState */
829 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
831 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
832 return STATUS_NO_MEMORY
;
835 Bucket
->Request
.RequestNotifyObject
= Complete
;
836 Bucket
->Request
.RequestContext
= Context
;
839 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
,
841 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
843 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
847 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
852 VOID
TCPTimeout(VOID
) {
853 /* Now handled by TimerThread */
856 UINT
TCPAllocatePort( UINT HintPort
) {
858 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
861 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
864 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
867 VOID
TCPFreePort( UINT Port
) {
868 DeallocatePort( &TCPPorts
, Port
);
871 NTSTATUS TCPGetSockAddress
872 ( PCONNECTION_ENDPOINT Connection
,
873 PTRANSPORT_ADDRESS Address
,
874 BOOLEAN GetRemote
) {
875 OSK_UINT LocalAddress
, RemoteAddress
;
876 OSK_UI16 LocalPort
, RemotePort
;
877 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
881 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
883 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
884 &LocalAddress
, &LocalPort
,
885 &RemoteAddress
, &RemotePort
));
887 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
889 if (!NT_SUCCESS(Status
))
892 AddressIP
->TAAddressCount
= 1;
893 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
894 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
895 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
896 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
901 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
903 PLIST_ENTRY ListHead
[4];
908 ListHead
[0] = &Endpoint
->SendRequest
;
909 ListHead
[1] = &Endpoint
->ReceiveRequest
;
910 ListHead
[2] = &Endpoint
->ConnectRequest
;
911 ListHead
[3] = &Endpoint
->ListenRequest
;
913 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
915 for( i
= 0; i
< 4; i
++ )
917 for( Entry
= ListHead
[i
]->Flink
;
918 Entry
!= ListHead
[i
];
919 Entry
= Entry
->Flink
)
921 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
922 if( Bucket
->Request
.RequestContext
== Irp
)
924 RemoveEntryList( &Bucket
->Entry
);
925 exFreePool( Bucket
);
931 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);