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
;
18 LIST_ENTRY SignalledConnectionsList
;
19 KSPIN_LOCK SignalledConnectionsLock
;
20 RECURSIVE_MUTEX TCPLock
;
23 ULONG
HandleSignalledConnection( PCONNECTION_ENDPOINT Connection
) {
24 NTSTATUS Status
= STATUS_SUCCESS
;
25 PTCP_COMPLETION_ROUTINE Complete
;
31 ASSERT_LOCKED(&TCPLock
);
33 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
34 Connection
, Connection
->SocketContext
));
36 if( Connection
->SignalState
& SEL_FIN
) {
37 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
39 Connection
->SignalState
&= ~SEL_READ
;
40 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
41 &Connection
->Lock
)) != NULL
)
43 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
44 Complete
= Bucket
->Request
.RequestNotifyObject
;
46 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
51 Connection
->SignalState
&= ~SEL_WRITE
;
52 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
53 &Connection
->Lock
)) != NULL
)
55 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
56 Complete
= Bucket
->Request
.RequestNotifyObject
;
58 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
63 Connection
->SignalState
&= ~SEL_ACCEPT
;
64 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
65 &Connection
->Lock
)) != NULL
)
67 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
68 Complete
= Bucket
->Request
.RequestNotifyObject
;
70 /* We have to notify oskittcp of the abortion */
71 TCPAbortListenForSocket(Connection
->AddressFile
->Listener
,
74 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
79 Connection
->SignalState
&= ~SEL_CONNECT
;
80 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
81 &Connection
->Lock
)) != NULL
)
83 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
84 Complete
= Bucket
->Request
.RequestNotifyObject
;
86 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
92 /* Things that can happen when we try the initial connection */
93 if( Connection
->SignalState
& SEL_CONNECT
) {
94 Connection
->SignalState
&= ~SEL_CONNECT
;
95 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
96 &Connection
->Lock
)) != NULL
) {
98 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
100 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
101 Complete
= Bucket
->Request
.RequestNotifyObject
;
102 TI_DbgPrint(DEBUG_TCP
,
103 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
105 Complete( Bucket
->Request
.RequestContext
, STATUS_SUCCESS
, 0 );
107 /* Frees the bucket allocated in TCPConnect */
108 exFreePool( Bucket
);
112 if( Connection
->SignalState
& SEL_ACCEPT
) {
113 /* Handle readable on a listening socket --
114 * TODO: Implement filtering
117 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
119 IsListEmpty(&Connection
->ListenRequest
) ?
120 "empty" : "nonempty"));
122 Connection
->SignalState
&= ~SEL_ACCEPT
;
123 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
124 &Connection
->Lock
)) != NULL
) {
125 PIO_STACK_LOCATION IrpSp
;
127 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
128 Complete
= Bucket
->Request
.RequestNotifyObject
;
130 Irp
= Bucket
->Request
.RequestContext
;
131 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
133 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
134 Status
= TCPServiceListeningSocket
135 ( Connection
->AddressFile
->Listener
,
136 Bucket
->AssociatedEndpoint
,
137 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
139 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
141 if( Status
== STATUS_PENDING
) {
142 Connection
->SignalState
|= SEL_ACCEPT
;
143 ExInterlockedInsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
, &Connection
->Lock
);
146 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
147 exFreePool( Bucket
);
152 /* Things that happen after we're connected */
153 if( Connection
->SignalState
& SEL_READ
) {
154 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
155 IsListEmpty(&Connection
->ReceiveRequest
) ?
156 "empty" : "nonempty"));
158 Connection
->SignalState
&= ~SEL_READ
;
159 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
160 &Connection
->Lock
)) != NULL
) {
161 OSK_UINT RecvLen
= 0, Received
= 0;
162 PVOID RecvBuffer
= 0;
164 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
165 Complete
= Bucket
->Request
.RequestNotifyObject
;
167 Irp
= Bucket
->Request
.RequestContext
;
168 Mdl
= Irp
->MdlAddress
;
170 TI_DbgPrint(DEBUG_TCP
,
171 ("Getting the user buffer from %x\n", Mdl
));
173 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
175 TI_DbgPrint(DEBUG_TCP
,
176 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
178 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
181 ("Connection->SocketContext: %x\n",
182 Connection
->SocketContext
));
183 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
185 Status
= TCPTranslateError
186 ( OskitTCPRecv( Connection
->SocketContext
,
192 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
194 if( Status
== STATUS_SUCCESS
) {
195 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
198 Complete( Bucket
->Request
.RequestContext
,
199 STATUS_SUCCESS
, Received
);
200 exFreePool( Bucket
);
201 } else if( Status
== STATUS_PENDING
) {
202 ExInterlockedInsertHeadList
203 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
204 Connection
->SignalState
|= SEL_READ
;
207 TI_DbgPrint(DEBUG_TCP
,
208 ("Completing Receive request: %x %x\n",
209 Bucket
->Request
, Status
));
210 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
211 exFreePool( Bucket
);
215 if( Connection
->SignalState
& SEL_WRITE
) {
216 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
217 IsListEmpty(&Connection
->SendRequest
) ?
218 "empty" : "nonempty"));
220 Connection
->SignalState
&= ~SEL_WRITE
;
221 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
222 &Connection
->Lock
)) != NULL
) {
223 OSK_UINT SendLen
= 0, Sent
= 0;
224 PVOID SendBuffer
= 0;
226 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
227 Complete
= Bucket
->Request
.RequestNotifyObject
;
229 Irp
= Bucket
->Request
.RequestContext
;
230 Mdl
= Irp
->MdlAddress
;
232 TI_DbgPrint(DEBUG_TCP
,
233 ("Getting the user buffer from %x\n", Mdl
));
235 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
237 TI_DbgPrint(DEBUG_TCP
,
238 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
240 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
243 ("Connection->SocketContext: %x\n",
244 Connection
->SocketContext
));
246 Status
= TCPTranslateError
247 ( OskitTCPSend( Connection
->SocketContext
,
253 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
255 if( Status
== STATUS_SUCCESS
) {
256 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
259 Complete( Bucket
->Request
.RequestContext
,
260 STATUS_SUCCESS
, Sent
);
261 exFreePool( Bucket
);
262 } else if( Status
== STATUS_PENDING
) {
263 ExInterlockedInsertHeadList
264 ( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
265 Connection
->SignalState
|= SEL_WRITE
;
268 TI_DbgPrint(DEBUG_TCP
,
269 ("Completing Send request: %x %x\n",
270 Bucket
->Request
, Status
));
271 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
272 exFreePool( Bucket
);
277 return Connection
->SignalState
;
280 static VOID
DrainSignals() {
281 PCONNECTION_ENDPOINT Connection
;
282 PLIST_ENTRY CurrentEntry
, NextEntry
;
286 KeAcquireSpinLock(&SignalledConnectionsLock
, &OldIrql
);
287 CurrentEntry
= SignalledConnectionsList
.Flink
;
288 while (CurrentEntry
!= &SignalledConnectionsList
)
290 NextEntry
= CurrentEntry
->Flink
;
291 Connection
= CONTAINING_RECORD( CurrentEntry
, CONNECTION_ENDPOINT
,
294 KeReleaseSpinLock(&SignalledConnectionsLock
, OldIrql
);
295 NewState
= HandleSignalledConnection(Connection
);
296 KeAcquireSpinLock(&SignalledConnectionsLock
, &OldIrql
);
298 if (NewState
== SEL_FIN
|| NewState
== 0)
300 RemoveEntryList(CurrentEntry
);
303 CurrentEntry
= NextEntry
;
305 KeReleaseSpinLock(&SignalledConnectionsLock
, OldIrql
);
308 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
309 PCONNECTION_ENDPOINT Connection
=
310 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
314 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
316 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
318 /* Initialize spin lock that protects the connection endpoint file object */
319 TcpipInitializeSpinLock(&Connection
->Lock
);
320 InitializeListHead(&Connection
->ConnectRequest
);
321 InitializeListHead(&Connection
->ListenRequest
);
322 InitializeListHead(&Connection
->ReceiveRequest
);
323 InitializeListHead(&Connection
->SendRequest
);
325 /* Save client context pointer */
326 Connection
->ClientContext
= ClientContext
;
331 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
332 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
333 exFreePool( Connection
);
336 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
337 UINT Family
, UINT Type
, UINT Proto
) {
340 ASSERT_LOCKED(&TCPLock
);
342 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
344 Connection
, Family
, Type
, Proto
));
346 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
347 &Connection
->SocketContext
,
352 ASSERT_KM_POINTER(Connection
->SocketContext
);
354 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
355 Connection
->SocketContext
));
360 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
362 * FUNCTION: Receives and queues TCP data
364 * IPPacket = Pointer to an IP packet that was received
366 * This is the low level interface for receiving TCP data
369 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
371 IPPacket
->HeaderSize
));
373 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
375 OskitTCPReceiveDatagram( IPPacket
->Header
,
377 IPPacket
->HeaderSize
);
379 TcpipRecursiveMutexLeave( &TCPLock
);
383 int TCPSocketState( void *ClientData
,
385 void *WhichConnection
,
388 int TCPPacketSend( void *ClientData
,
392 POSK_IFADDR
TCPFindInterface( void *ClientData
,
395 OSK_SOCKADDR
*ReqAddr
);
397 NTSTATUS
TCPMemStartup( void );
398 void *TCPMalloc( void *ClientData
,
399 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
400 void TCPFree( void *ClientData
,
401 void *data
, OSK_PCHAR file
, OSK_UINT line
);
402 void TCPMemShutdown( void );
404 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
405 NULL
, /* Client Data */
406 TCPSocketState
, /* SocketState */
407 TCPPacketSend
, /* PacketSend */
408 TCPFindInterface
, /* FindInterface */
409 TCPMalloc
, /* Malloc */
415 static KEVENT TimerLoopEvent
;
416 static HANDLE TimerThreadHandle
;
419 * We are running 2 timers here, one with a 200ms interval (fast) and the other
420 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
421 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
422 * "slow" events at 500 and 1000.
425 TimerThread(PVOID Context
)
427 LARGE_INTEGER Timeout
;
429 unsigned Current
, NextFast
, NextSlow
, Next
;
436 if (Next
== NextFast
) {
439 if (Next
== NextSlow
) {
442 Next
= min(NextFast
, NextSlow
);
443 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
444 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
446 if (Status
!= STATUS_TIMEOUT
) {
447 PsTerminateSystemThread(Status
);
450 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
451 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
452 if (Next
== NextSlow
) {
455 TcpipRecursiveMutexLeave( &TCPLock
);
470 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
471 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
476 NTSTATUS
TCPStartup(VOID
)
478 * FUNCTION: Initializes the TCP subsystem
480 * Status of operation
485 TcpipRecursiveMutexInit( &TCPLock
);
486 KeInitializeSpinLock( &SignalledConnectionsLock
);
487 InitializeListHead( &SignalledConnectionsList
);
488 Status
= TCPMemStartup();
489 if ( ! NT_SUCCESS(Status
) ) {
493 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
494 if( !NT_SUCCESS(Status
) ) {
499 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
500 RegisterOskitTCPEventHandlers( &EventHandlers
);
502 TcpipRecursiveMutexLeave(&TCPLock
);
504 /* Register this protocol with IP layer */
505 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
507 ExInitializeNPagedLookasideList(
508 &TCPSegmentList
, /* Lookaside list */
509 NULL
, /* Allocate routine */
510 NULL
, /* Free routine */
512 sizeof(TCP_SEGMENT
), /* Size of each entry */
518 TCPInitialized
= TRUE
;
520 return STATUS_SUCCESS
;
524 NTSTATUS
TCPShutdown(VOID
)
526 * FUNCTION: Shuts down the TCP subsystem
528 * Status of operation
531 LARGE_INTEGER WaitForThread
;
534 return STATUS_SUCCESS
;
536 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
537 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
538 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
540 /* Deregister this protocol with IP layer */
541 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
543 ExDeleteNPagedLookasideList(&TCPSegmentList
);
545 TCPInitialized
= FALSE
;
549 PortsShutdown( &TCPPorts
);
553 return STATUS_SUCCESS
;
556 NTSTATUS
TCPTranslateError( int OskitError
) {
559 switch( OskitError
) {
560 case 0: Status
= STATUS_SUCCESS
; break;
561 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
562 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
563 case OSK_ECONNREFUSED
:
564 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
565 case OSK_EWOULDBLOCK
:
566 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
567 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
569 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
570 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
571 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
572 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
573 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
574 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
576 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
577 Status
= STATUS_INVALID_CONNECTION
;
581 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
586 ( PCONNECTION_ENDPOINT Connection
,
587 PTDI_CONNECTION_INFORMATION ConnInfo
,
588 PTDI_CONNECTION_INFORMATION ReturnInfo
,
589 PTCP_COMPLETION_ROUTINE Complete
,
592 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
593 IP_ADDRESS RemoteAddress
;
596 PNEIGHBOR_CACHE_ENTRY NCE
;
598 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
600 ASSERT_LOCKED(&TCPLock
);
602 Status
= AddrBuildAddress
603 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
607 if (!NT_SUCCESS(Status
)) {
608 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
612 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
614 return STATUS_NETWORK_UNREACHABLE
;
617 /* Freed in TCPSocketState */
618 TI_DbgPrint(DEBUG_TCP
,
619 ("Connecting to address %x:%x\n",
620 RemoteAddress
.Address
.IPv4Address
,
623 AddressToConnect
.sin_family
= AF_INET
;
624 AddressToBind
= AddressToConnect
;
625 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
627 Status
= TCPTranslateError
628 ( OskitTCPBind( Connection
->SocketContext
,
630 sizeof(AddressToBind
) ) );
632 if (NT_SUCCESS(Status
)) {
633 memcpy( &AddressToConnect
.sin_addr
,
634 &RemoteAddress
.Address
.IPv4Address
,
635 sizeof(AddressToConnect
.sin_addr
) );
636 AddressToConnect
.sin_port
= RemotePort
;
638 Status
= TCPTranslateError
639 ( OskitTCPConnect( Connection
->SocketContext
,
642 sizeof(AddressToConnect
) ) );
644 if (Status
== STATUS_PENDING
)
646 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
647 if( !Bucket
) return STATUS_NO_MEMORY
;
649 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
650 Bucket
->Request
.RequestContext
= Context
;
652 IoMarkIrpPending((PIRP
)Context
);
654 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
, &Connection
->Lock
);
661 NTSTATUS TCPDisconnect
662 ( PCONNECTION_ENDPOINT Connection
,
664 PTDI_CONNECTION_INFORMATION ConnInfo
,
665 PTDI_CONNECTION_INFORMATION ReturnInfo
,
666 PTCP_COMPLETION_ROUTINE Complete
,
668 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
670 ASSERT_LOCKED(&TCPLock
);
672 TI_DbgPrint(DEBUG_TCP
,("started\n"));
674 if (Flags
& TDI_DISCONNECT_RELEASE
)
675 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
677 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
678 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
680 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
686 ( PCONNECTION_ENDPOINT Connection
) {
689 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
691 ASSERT_LOCKED(&TCPLock
);
693 /* Make our code remove all pending IRPs */
694 Connection
->SignalState
|= SEL_FIN
;
695 HandleSignalledConnection(Connection
);
697 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
698 if (Status
== STATUS_SUCCESS
)
699 Connection
->SocketContext
= NULL
;
701 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
706 NTSTATUS TCPReceiveData
707 ( PCONNECTION_ENDPOINT Connection
,
710 PULONG BytesReceived
,
712 PTCP_COMPLETION_ROUTINE Complete
,
715 UINT DataLen
, Received
= 0;
719 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
720 ReceiveLength
, Connection
->SocketContext
));
722 ASSERT_LOCKED(&TCPLock
);
724 ASSERT_KM_POINTER(Connection
->SocketContext
);
726 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
728 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
730 Status
= TCPTranslateError
732 ( Connection
->SocketContext
,
738 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
740 /* Keep this request around ... there was no data yet */
741 if( Status
== STATUS_PENDING
) {
742 /* Freed in TCPSocketState */
743 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
745 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
746 return STATUS_NO_MEMORY
;
749 Bucket
->Request
.RequestNotifyObject
= Complete
;
750 Bucket
->Request
.RequestContext
= Context
;
753 IoMarkIrpPending((PIRP
)Context
);
755 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
756 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
758 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
759 *BytesReceived
= Received
;
762 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
768 ( PCONNECTION_ENDPOINT Connection
,
773 PTCP_COMPLETION_ROUTINE Complete
,
779 ASSERT_LOCKED(&TCPLock
);
781 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
782 SendLength
, Connection
->SocketContext
));
784 ASSERT_KM_POINTER(Connection
->SocketContext
);
786 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
787 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
788 Connection
->SocketContext
));
791 Status
= TCPTranslateError
792 ( OskitTCPSend( Connection
->SocketContext
,
793 (OSK_PCHAR
)BufferData
, SendLength
,
796 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
798 /* Keep this request around ... there was no data yet */
799 if( Status
== STATUS_PENDING
) {
800 /* Freed in TCPSocketState */
801 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
803 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
804 return STATUS_NO_MEMORY
;
807 Bucket
->Request
.RequestNotifyObject
= Complete
;
808 Bucket
->Request
.RequestContext
= Context
;
811 IoMarkIrpPending((PIRP
)Context
);
813 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
814 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
816 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
820 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
825 VOID
TCPTimeout(VOID
) {
826 /* Now handled by TimerThread */
829 UINT
TCPAllocatePort( UINT HintPort
) {
831 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
834 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
837 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
840 VOID
TCPFreePort( UINT Port
) {
841 DeallocatePort( &TCPPorts
, Port
);
844 NTSTATUS TCPGetSockAddress
845 ( PCONNECTION_ENDPOINT Connection
,
846 PTRANSPORT_ADDRESS Address
,
847 BOOLEAN GetRemote
) {
848 OSK_UINT LocalAddress
, RemoteAddress
;
849 OSK_UI16 LocalPort
, RemotePort
;
850 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
853 ASSERT_LOCKED(&TCPLock
);
855 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
856 &LocalAddress
, &LocalPort
,
857 &RemoteAddress
, &RemotePort
));
858 if (!NT_SUCCESS(Status
))
861 AddressIP
->TAAddressCount
= 1;
862 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
863 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
864 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
865 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
870 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
872 PLIST_ENTRY ListHead
[4];
877 ListHead
[0] = &Endpoint
->SendRequest
;
878 ListHead
[1] = &Endpoint
->ReceiveRequest
;
879 ListHead
[2] = &Endpoint
->ConnectRequest
;
880 ListHead
[3] = &Endpoint
->ListenRequest
;
882 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
884 for( i
= 0; i
< 4; i
++ )
886 for( Entry
= ListHead
[i
]->Flink
;
887 Entry
!= ListHead
[i
];
888 Entry
= Entry
->Flink
)
890 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
891 if( Bucket
->Request
.RequestContext
== Irp
)
893 RemoveEntryList( &Bucket
->Entry
);
894 exFreePool( Bucket
);
900 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);