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 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
32 Connection
, Connection
->SocketContext
));
34 if( Connection
->SignalState
& SEL_FIN
) {
35 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
37 Connection
->SignalState
&= ~SEL_READ
;
38 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
39 &Connection
->Lock
)) != NULL
)
41 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
42 Complete
= Bucket
->Request
.RequestNotifyObject
;
44 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
49 Connection
->SignalState
&= ~SEL_WRITE
;
50 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
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 Connection
->SignalState
&= ~SEL_ACCEPT
;
62 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
63 &Connection
->Lock
)) != NULL
)
65 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
66 Complete
= Bucket
->Request
.RequestNotifyObject
;
68 /* We have to notify oskittcp of the abortion */
69 TCPAbortListenForSocket(Connection
->AddressFile
->Listener
,
72 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
77 Connection
->SignalState
&= ~SEL_CONNECT
;
78 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
79 &Connection
->Lock
)) != NULL
)
81 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
82 Complete
= Bucket
->Request
.RequestNotifyObject
;
84 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
90 /* Things that can happen when we try the initial connection */
91 if( Connection
->SignalState
& SEL_CONNECT
) {
92 Connection
->SignalState
&= ~SEL_CONNECT
;
93 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
94 &Connection
->Lock
)) != NULL
) {
96 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
98 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
99 Complete
= Bucket
->Request
.RequestNotifyObject
;
100 TI_DbgPrint(DEBUG_TCP
,
101 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
103 Complete( Bucket
->Request
.RequestContext
, STATUS_SUCCESS
, 0 );
105 /* Frees the bucket allocated in TCPConnect */
106 exFreePool( Bucket
);
110 if( Connection
->SignalState
& SEL_ACCEPT
) {
111 /* Handle readable on a listening socket --
112 * TODO: Implement filtering
115 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
117 IsListEmpty(&Connection
->ListenRequest
) ?
118 "empty" : "nonempty"));
120 Connection
->SignalState
&= ~SEL_ACCEPT
;
121 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
122 &Connection
->Lock
)) != NULL
) {
123 PIO_STACK_LOCATION IrpSp
;
125 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
126 Complete
= Bucket
->Request
.RequestNotifyObject
;
128 Irp
= Bucket
->Request
.RequestContext
;
129 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
131 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
132 Status
= TCPServiceListeningSocket
133 ( Connection
->AddressFile
->Listener
,
134 Bucket
->AssociatedEndpoint
,
135 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
137 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
139 if( Status
== STATUS_PENDING
) {
140 Connection
->SignalState
|= SEL_ACCEPT
;
141 ExInterlockedInsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
, &Connection
->Lock
);
144 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
145 exFreePool( Bucket
);
150 /* Things that happen after we're connected */
151 if( Connection
->SignalState
& SEL_READ
) {
152 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
153 IsListEmpty(&Connection
->ReceiveRequest
) ?
154 "empty" : "nonempty"));
156 Connection
->SignalState
&= ~SEL_READ
;
157 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
158 &Connection
->Lock
)) != NULL
) {
159 OSK_UINT RecvLen
= 0, Received
= 0;
160 PVOID RecvBuffer
= 0;
162 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
163 Complete
= Bucket
->Request
.RequestNotifyObject
;
165 Irp
= Bucket
->Request
.RequestContext
;
166 Mdl
= Irp
->MdlAddress
;
168 TI_DbgPrint(DEBUG_TCP
,
169 ("Getting the user buffer from %x\n", Mdl
));
171 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
173 TI_DbgPrint(DEBUG_TCP
,
174 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
176 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
179 ("Connection->SocketContext: %x\n",
180 Connection
->SocketContext
));
181 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
183 Status
= TCPTranslateError
184 ( OskitTCPRecv( Connection
->SocketContext
,
190 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
192 if( Status
== STATUS_SUCCESS
) {
193 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
196 Complete( Bucket
->Request
.RequestContext
,
197 STATUS_SUCCESS
, Received
);
198 exFreePool( Bucket
);
199 } else if( Status
== STATUS_PENDING
) {
200 ExInterlockedInsertHeadList
201 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
202 Connection
->SignalState
|= SEL_READ
;
205 TI_DbgPrint(DEBUG_TCP
,
206 ("Completing Receive request: %x %x\n",
207 Bucket
->Request
, Status
));
208 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
209 exFreePool( Bucket
);
213 if( Connection
->SignalState
& SEL_WRITE
) {
214 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
215 IsListEmpty(&Connection
->SendRequest
) ?
216 "empty" : "nonempty"));
218 Connection
->SignalState
&= ~SEL_WRITE
;
219 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
220 &Connection
->Lock
)) != NULL
) {
221 OSK_UINT SendLen
= 0, Sent
= 0;
222 PVOID SendBuffer
= 0;
224 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
225 Complete
= Bucket
->Request
.RequestNotifyObject
;
227 Irp
= Bucket
->Request
.RequestContext
;
228 Mdl
= Irp
->MdlAddress
;
230 TI_DbgPrint(DEBUG_TCP
,
231 ("Getting the user buffer from %x\n", Mdl
));
233 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
235 TI_DbgPrint(DEBUG_TCP
,
236 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
238 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
241 ("Connection->SocketContext: %x\n",
242 Connection
->SocketContext
));
244 Status
= TCPTranslateError
245 ( OskitTCPSend( Connection
->SocketContext
,
251 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
253 if( Status
== STATUS_SUCCESS
) {
254 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
257 Complete( Bucket
->Request
.RequestContext
,
258 STATUS_SUCCESS
, Sent
);
259 exFreePool( Bucket
);
260 } else if( Status
== STATUS_PENDING
) {
261 ExInterlockedInsertHeadList
262 ( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
263 Connection
->SignalState
|= SEL_WRITE
;
266 TI_DbgPrint(DEBUG_TCP
,
267 ("Completing Send request: %x %x\n",
268 Bucket
->Request
, Status
));
269 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
270 exFreePool( Bucket
);
275 return Connection
->SignalState
;
278 static VOID
DrainSignals() {
279 PCONNECTION_ENDPOINT Connection
;
280 PLIST_ENTRY CurrentEntry
, NextEntry
;
284 KeAcquireSpinLock(&SignalledConnectionsLock
, &OldIrql
);
285 CurrentEntry
= SignalledConnectionsList
.Flink
;
286 while (CurrentEntry
!= &SignalledConnectionsList
)
288 NextEntry
= CurrentEntry
->Flink
;
289 Connection
= CONTAINING_RECORD( CurrentEntry
, CONNECTION_ENDPOINT
,
292 KeReleaseSpinLock(&SignalledConnectionsLock
, OldIrql
);
293 NewState
= HandleSignalledConnection(Connection
);
294 KeAcquireSpinLock(&SignalledConnectionsLock
, &OldIrql
);
296 if (NewState
== SEL_FIN
|| NewState
== 0)
298 RemoveEntryList(CurrentEntry
);
301 CurrentEntry
= NextEntry
;
303 KeReleaseSpinLock(&SignalledConnectionsLock
, OldIrql
);
306 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
307 PCONNECTION_ENDPOINT Connection
=
308 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
312 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
314 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
316 /* Initialize spin lock that protects the connection endpoint file object */
317 TcpipInitializeSpinLock(&Connection
->Lock
);
318 InitializeListHead(&Connection
->ConnectRequest
);
319 InitializeListHead(&Connection
->ListenRequest
);
320 InitializeListHead(&Connection
->ReceiveRequest
);
321 InitializeListHead(&Connection
->SendRequest
);
323 /* Save client context pointer */
324 Connection
->ClientContext
= ClientContext
;
329 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
330 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
331 exFreePool( Connection
);
334 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
335 UINT Family
, UINT Type
, UINT Proto
) {
338 TcpipRecursiveMutexEnter(&TCPLock
);
340 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
342 Connection
, Family
, Type
, Proto
));
344 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
345 &Connection
->SocketContext
,
350 ASSERT_KM_POINTER(Connection
->SocketContext
);
352 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
353 Connection
->SocketContext
));
355 TcpipRecursiveMutexLeave(&TCPLock
);
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
);
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
);
451 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
452 TcpipRecursiveMutexLeave( &TCPLock
);
454 if (Next
== NextSlow
) {
471 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
472 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
477 NTSTATUS
TCPStartup(VOID
)
479 * FUNCTION: Initializes the TCP subsystem
481 * Status of operation
486 TcpipRecursiveMutexInit( &TCPLock
);
487 KeInitializeSpinLock( &SignalledConnectionsLock
);
488 InitializeListHead( &SignalledConnectionsList
);
489 Status
= TCPMemStartup();
490 if ( ! NT_SUCCESS(Status
) ) {
494 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
495 if( !NT_SUCCESS(Status
) ) {
500 TcpipRecursiveMutexEnter(&TCPLock
);
501 RegisterOskitTCPEventHandlers( &EventHandlers
);
503 TcpipRecursiveMutexLeave(&TCPLock
);
505 /* Register this protocol with IP layer */
506 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
508 ExInitializeNPagedLookasideList(
509 &TCPSegmentList
, /* Lookaside list */
510 NULL
, /* Allocate routine */
511 NULL
, /* Free routine */
513 sizeof(TCP_SEGMENT
), /* Size of each entry */
519 TCPInitialized
= TRUE
;
521 return STATUS_SUCCESS
;
525 NTSTATUS
TCPShutdown(VOID
)
527 * FUNCTION: Shuts down the TCP subsystem
529 * Status of operation
532 LARGE_INTEGER WaitForThread
;
535 return STATUS_SUCCESS
;
537 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
538 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
539 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
541 /* Deregister this protocol with IP layer */
542 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
544 ExDeleteNPagedLookasideList(&TCPSegmentList
);
546 TCPInitialized
= FALSE
;
548 TcpipRecursiveMutexEnter(&TCPLock
);
550 TcpipRecursiveMutexLeave(&TCPLock
);
552 PortsShutdown( &TCPPorts
);
556 return STATUS_SUCCESS
;
559 NTSTATUS
TCPTranslateError( int OskitError
) {
562 switch( OskitError
) {
563 case 0: Status
= STATUS_SUCCESS
; break;
564 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
565 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
566 case OSK_ECONNREFUSED
:
567 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
568 case OSK_EWOULDBLOCK
:
569 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
570 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
572 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
573 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
574 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
575 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
576 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
577 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
579 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
580 Status
= STATUS_INVALID_CONNECTION
;
584 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
589 ( PCONNECTION_ENDPOINT Connection
,
590 PTDI_CONNECTION_INFORMATION ConnInfo
,
591 PTDI_CONNECTION_INFORMATION ReturnInfo
,
592 PTCP_COMPLETION_ROUTINE Complete
,
595 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
596 IP_ADDRESS RemoteAddress
;
599 PNEIGHBOR_CACHE_ENTRY NCE
;
601 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
603 Status
= AddrBuildAddress
604 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
608 if (!NT_SUCCESS(Status
)) {
609 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
613 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
615 return STATUS_NETWORK_UNREACHABLE
;
618 /* Freed in TCPSocketState */
619 TI_DbgPrint(DEBUG_TCP
,
620 ("Connecting to address %x:%x\n",
621 RemoteAddress
.Address
.IPv4Address
,
624 AddressToConnect
.sin_family
= AF_INET
;
625 AddressToBind
= AddressToConnect
;
626 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
628 TcpipRecursiveMutexEnter(&TCPLock
);
630 Status
= TCPTranslateError
631 ( OskitTCPBind( Connection
->SocketContext
,
633 sizeof(AddressToBind
) ) );
635 if (NT_SUCCESS(Status
)) {
636 memcpy( &AddressToConnect
.sin_addr
,
637 &RemoteAddress
.Address
.IPv4Address
,
638 sizeof(AddressToConnect
.sin_addr
) );
639 AddressToConnect
.sin_port
= RemotePort
;
641 Status
= TCPTranslateError
642 ( OskitTCPConnect( Connection
->SocketContext
,
645 sizeof(AddressToConnect
) ) );
647 if (Status
== STATUS_PENDING
)
649 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
650 if( !Bucket
) return STATUS_NO_MEMORY
;
652 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
653 Bucket
->Request
.RequestContext
= Context
;
655 IoMarkIrpPending((PIRP
)Context
);
657 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
, &Connection
->Lock
);
661 TcpipRecursiveMutexLeave(&TCPLock
);
666 NTSTATUS TCPDisconnect
667 ( PCONNECTION_ENDPOINT Connection
,
669 PTDI_CONNECTION_INFORMATION ConnInfo
,
670 PTDI_CONNECTION_INFORMATION ReturnInfo
,
671 PTCP_COMPLETION_ROUTINE Complete
,
673 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
675 ASSERT_LOCKED(&TCPLock
);
677 TI_DbgPrint(DEBUG_TCP
,("started\n"));
679 TcpipRecursiveMutexEnter(&TCPLock
);
681 if (Flags
& TDI_DISCONNECT_RELEASE
)
682 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
684 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
685 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
687 TcpipRecursiveMutexLeave(&TCPLock
);
689 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
695 ( PCONNECTION_ENDPOINT Connection
) {
698 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
700 /* Make our code remove all pending IRPs */
701 Connection
->SignalState
|= SEL_FIN
;
702 HandleSignalledConnection(Connection
);
704 TcpipRecursiveMutexEnter(&TCPLock
);
706 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
707 if (Status
== STATUS_SUCCESS
)
708 Connection
->SocketContext
= NULL
;
710 TcpipRecursiveMutexLeave(&TCPLock
);
712 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
717 NTSTATUS TCPReceiveData
718 ( PCONNECTION_ENDPOINT Connection
,
721 PULONG BytesReceived
,
723 PTCP_COMPLETION_ROUTINE Complete
,
726 UINT DataLen
, Received
= 0;
730 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
731 ReceiveLength
, Connection
->SocketContext
));
733 ASSERT_KM_POINTER(Connection
->SocketContext
);
735 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
737 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
739 TcpipRecursiveMutexEnter(&TCPLock
);
741 Status
= TCPTranslateError
743 ( Connection
->SocketContext
,
749 TcpipRecursiveMutexLeave(&TCPLock
);
751 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
753 /* Keep this request around ... there was no data yet */
754 if( Status
== STATUS_PENDING
) {
755 /* Freed in TCPSocketState */
756 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
758 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
759 return STATUS_NO_MEMORY
;
762 Bucket
->Request
.RequestNotifyObject
= Complete
;
763 Bucket
->Request
.RequestContext
= Context
;
766 IoMarkIrpPending((PIRP
)Context
);
768 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
769 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
771 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
772 *BytesReceived
= Received
;
775 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
781 ( PCONNECTION_ENDPOINT Connection
,
786 PTCP_COMPLETION_ROUTINE Complete
,
792 ASSERT_LOCKED(&TCPLock
);
794 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
795 SendLength
, Connection
->SocketContext
));
797 ASSERT_KM_POINTER(Connection
->SocketContext
);
799 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
800 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
801 Connection
->SocketContext
));
803 TcpipRecursiveMutexEnter(&TCPLock
);
805 Status
= TCPTranslateError
806 ( OskitTCPSend( Connection
->SocketContext
,
807 (OSK_PCHAR
)BufferData
, SendLength
,
810 TcpipRecursiveMutexLeave(&TCPLock
);
812 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
814 /* Keep this request around ... there was no data yet */
815 if( Status
== STATUS_PENDING
) {
816 /* Freed in TCPSocketState */
817 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
819 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
820 return STATUS_NO_MEMORY
;
823 Bucket
->Request
.RequestNotifyObject
= Complete
;
824 Bucket
->Request
.RequestContext
= Context
;
827 IoMarkIrpPending((PIRP
)Context
);
829 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
830 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
832 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
836 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
841 VOID
TCPTimeout(VOID
) {
842 /* Now handled by TimerThread */
845 UINT
TCPAllocatePort( UINT HintPort
) {
847 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
850 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
853 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
856 VOID
TCPFreePort( UINT Port
) {
857 DeallocatePort( &TCPPorts
, Port
);
860 NTSTATUS TCPGetSockAddress
861 ( PCONNECTION_ENDPOINT Connection
,
862 PTRANSPORT_ADDRESS Address
,
863 BOOLEAN GetRemote
) {
864 OSK_UINT LocalAddress
, RemoteAddress
;
865 OSK_UI16 LocalPort
, RemotePort
;
866 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
869 TcpipRecursiveMutexEnter(&TCPLock
);
871 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
872 &LocalAddress
, &LocalPort
,
873 &RemoteAddress
, &RemotePort
));
875 TcpipRecursiveMutexLeave(&TCPLock
);
877 if (!NT_SUCCESS(Status
))
880 AddressIP
->TAAddressCount
= 1;
881 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
882 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
883 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
884 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
889 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
891 PLIST_ENTRY ListHead
[4];
896 ListHead
[0] = &Endpoint
->SendRequest
;
897 ListHead
[1] = &Endpoint
->ReceiveRequest
;
898 ListHead
[2] = &Endpoint
->ConnectRequest
;
899 ListHead
[3] = &Endpoint
->ListenRequest
;
901 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
903 for( i
= 0; i
< 4; i
++ )
905 for( Entry
= ListHead
[i
]->Flink
;
906 Entry
!= ListHead
[i
];
907 Entry
= Entry
->Flink
)
909 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
910 if( Bucket
->Request
.RequestContext
== Irp
)
912 RemoveEntryList( &Bucket
->Entry
);
913 exFreePool( Bucket
);
919 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);