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 SignalledConnections
;
19 LIST_ENTRY SleepingThreadsList
;
20 FAST_MUTEX SleepingThreadsLock
;
21 RECURSIVE_MUTEX TCPLock
;
24 static VOID
HandleSignalledConnection( PCONNECTION_ENDPOINT Connection
,
26 NTSTATUS Status
= STATUS_SUCCESS
;
27 PTCP_COMPLETION_ROUTINE Complete
;
33 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
34 Connection
, Connection
->SocketContext
));
36 /* Things that can happen when we try the initial connection */
37 if( NewState
& SEL_CONNECT
) {
38 while( !IsListEmpty( &Connection
->ConnectRequest
) ) {
39 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
40 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
42 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
43 Complete
= Bucket
->Request
.RequestNotifyObject
;
44 TI_DbgPrint(DEBUG_TCP
,
45 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
47 if( (NewState
& (SEL_CONNECT
| SEL_FIN
)) ==
48 (SEL_CONNECT
| SEL_FIN
) )
49 Status
= STATUS_CONNECTION_REFUSED
;
51 Status
= STATUS_SUCCESS
;
53 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
55 /* Frees the bucket allocated in TCPConnect */
60 if( NewState
& SEL_ACCEPT
) {
61 /* Handle readable on a listening socket --
62 * TODO: Implement filtering
65 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
67 IsListEmpty(&Connection
->ListenRequest
) ?
68 "empty" : "nonempty"));
70 while( !IsListEmpty( &Connection
->ListenRequest
) ) {
71 PIO_STACK_LOCATION IrpSp
;
73 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
74 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
75 Complete
= Bucket
->Request
.RequestNotifyObject
;
77 Irp
= Bucket
->Request
.RequestContext
;
78 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
80 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
81 Status
= TCPServiceListeningSocket
82 ( Connection
->AddressFile
->Listener
,
83 Bucket
->AssociatedEndpoint
,
84 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
86 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
88 if( Status
== STATUS_PENDING
) {
89 InsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
);
92 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
98 /* Things that happen after we're connected */
99 if( NewState
& SEL_READ
) {
100 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
101 IsListEmpty(&Connection
->ReceiveRequest
) ?
102 "empty" : "nonempty"));
104 while( !IsListEmpty( &Connection
->ReceiveRequest
) ) {
105 OSK_UINT RecvLen
= 0, Received
= 0;
106 OSK_PCHAR RecvBuffer
= 0;
108 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
109 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
110 Complete
= Bucket
->Request
.RequestNotifyObject
;
112 Irp
= Bucket
->Request
.RequestContext
;
113 Mdl
= Irp
->MdlAddress
;
115 TI_DbgPrint(DEBUG_TCP
,
116 ("Getting the user buffer from %x\n", Mdl
));
118 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
120 TI_DbgPrint(DEBUG_TCP
,
121 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
123 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
126 ("Connection->SocketContext: %x\n",
127 Connection
->SocketContext
));
128 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
130 Status
= TCPTranslateError
131 ( OskitTCPRecv( Connection
->SocketContext
,
137 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
139 if( Status
== STATUS_SUCCESS
) {
140 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
143 Complete( Bucket
->Request
.RequestContext
,
144 STATUS_SUCCESS
, Received
);
145 exFreePool( Bucket
);
146 } else if( Status
== STATUS_PENDING
) {
148 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
151 TI_DbgPrint(DEBUG_TCP
,
152 ("Completing Receive request: %x %x\n",
153 Bucket
->Request
, Status
));
154 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
155 exFreePool( Bucket
);
159 if( NewState
& SEL_WRITE
) {
160 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
161 IsListEmpty(&Connection
->SendRequest
) ?
162 "empty" : "nonempty"));
164 while( !IsListEmpty( &Connection
->SendRequest
) ) {
165 OSK_UINT SendLen
= 0, Sent
= 0;
166 OSK_PCHAR SendBuffer
= 0;
168 Entry
= RemoveHeadList( &Connection
->SendRequest
);
169 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
170 Complete
= Bucket
->Request
.RequestNotifyObject
;
172 Irp
= Bucket
->Request
.RequestContext
;
173 Mdl
= Irp
->MdlAddress
;
175 TI_DbgPrint(DEBUG_TCP
,
176 ("Getting the user buffer from %x\n", Mdl
));
178 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
180 TI_DbgPrint(DEBUG_TCP
,
181 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
183 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
186 ("Connection->SocketContext: %x\n",
187 Connection
->SocketContext
));
189 Status
= TCPTranslateError
190 ( OskitTCPSend( Connection
->SocketContext
,
196 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
198 if( Status
== STATUS_SUCCESS
) {
199 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
202 Complete( Bucket
->Request
.RequestContext
,
203 STATUS_SUCCESS
, Sent
);
204 exFreePool( Bucket
);
205 } else if( Status
== STATUS_PENDING
) {
207 ( &Connection
->SendRequest
, &Bucket
->Entry
);
210 TI_DbgPrint(DEBUG_TCP
,
211 ("Completing Send request: %x %x\n",
212 Bucket
->Request
, Status
));
213 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
214 exFreePool( Bucket
);
219 if( NewState
& SEL_FIN
) {
220 PLIST_ENTRY ListsToErase
[4];
221 NTSTATUS IrpStatus
[4];
224 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
226 ListsToErase
[0] = &Connection
->ReceiveRequest
;
227 IrpStatus
[0] = STATUS_SUCCESS
;
228 ListsToErase
[1] = &Connection
->ListenRequest
;
229 IrpStatus
[1] = STATUS_UNSUCCESSFUL
;
230 ListsToErase
[2] = &Connection
->ConnectRequest
;
231 IrpStatus
[2] = STATUS_UNSUCCESSFUL
;
235 for( i
= 0; ListsToErase
[i
]; i
++ ) {
236 while( !IsListEmpty( ListsToErase
[i
] ) ) {
237 Entry
= RemoveHeadList( ListsToErase
[i
] );
238 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
239 Complete
= Bucket
->Request
.RequestNotifyObject
;
240 Complete( Bucket
->Request
.RequestContext
, IrpStatus
[i
], 0 );
241 exFreePool( Bucket
);
246 Connection
->Signalled
= FALSE
;
249 VOID
DrainSignals() {
250 PCONNECTION_ENDPOINT Connection
;
251 PLIST_ENTRY ListEntry
;
253 while( !IsListEmpty( &SignalledConnections
) ) {
254 ListEntry
= RemoveHeadList( &SignalledConnections
);
255 Connection
= CONTAINING_RECORD( ListEntry
, CONNECTION_ENDPOINT
,
257 HandleSignalledConnection( Connection
, Connection
->SignalState
);
261 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
262 PCONNECTION_ENDPOINT Connection
=
263 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
267 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
269 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
271 /* Initialize spin lock that protects the connection endpoint file object */
272 TcpipInitializeSpinLock(&Connection
->Lock
);
273 InitializeListHead(&Connection
->ConnectRequest
);
274 InitializeListHead(&Connection
->ListenRequest
);
275 InitializeListHead(&Connection
->ReceiveRequest
);
276 InitializeListHead(&Connection
->SendRequest
);
278 /* Save client context pointer */
279 Connection
->ClientContext
= ClientContext
;
284 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
285 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
286 exFreePool( Connection
);
289 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
290 UINT Family
, UINT Type
, UINT Proto
) {
293 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
295 Connection
, Family
, Type
, Proto
));
297 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
298 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
299 &Connection
->SocketContext
,
304 ASSERT_KM_POINTER(Connection
->SocketContext
);
306 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
307 Connection
->SocketContext
));
309 TcpipRecursiveMutexLeave( &TCPLock
);
314 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
316 * FUNCTION: Receives and queues TCP data
318 * IPPacket = Pointer to an IP packet that was received
320 * This is the low level interface for receiving TCP data
323 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
325 IPPacket
->HeaderSize
));
327 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
329 OskitTCPReceiveDatagram( IPPacket
->Header
,
331 IPPacket
->HeaderSize
);
335 TcpipRecursiveMutexLeave( &TCPLock
);
339 int TCPSocketState( void *ClientData
,
341 void *WhichConnection
,
344 int TCPPacketSend( void *ClientData
,
348 POSK_IFADDR
TCPFindInterface( void *ClientData
,
351 OSK_SOCKADDR
*ReqAddr
);
353 NTSTATUS
TCPMemStartup( void );
354 void *TCPMalloc( void *ClientData
,
355 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
356 void TCPFree( void *ClientData
,
357 void *data
, OSK_PCHAR file
, OSK_UINT line
);
358 void TCPMemShutdown( void );
360 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
363 void TCPWakeup( void *ClientData
, void *token
);
365 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
366 NULL
, /* Client Data */
367 TCPSocketState
, /* SocketState */
368 TCPPacketSend
, /* PacketSend */
369 TCPFindInterface
, /* FindInterface */
370 TCPMalloc
, /* Malloc */
372 TCPSleep
, /* Sleep */
373 TCPWakeup
/* Wakeup */
376 static KEVENT TimerLoopEvent
;
377 static HANDLE TimerThreadHandle
;
380 * We are running 2 timers here, one with a 200ms interval (fast) and the other
381 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
382 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
383 * "slow" events at 500 and 1000.
386 TimerThread(PVOID Context
)
388 LARGE_INTEGER Timeout
;
390 unsigned Current
, NextFast
, NextSlow
, Next
;
397 if (Next
== NextFast
) {
400 if (Next
== NextSlow
) {
403 Next
= min(NextFast
, NextSlow
);
404 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
405 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
407 if (Status
!= STATUS_TIMEOUT
) {
408 PsTerminateSystemThread(Status
);
411 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
412 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
413 if (Next
== NextSlow
) {
416 TcpipRecursiveMutexLeave( &TCPLock
);
431 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
432 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
437 NTSTATUS
TCPStartup(VOID
)
439 * FUNCTION: Initializes the TCP subsystem
441 * Status of operation
446 TcpipRecursiveMutexInit( &TCPLock
);
447 ExInitializeFastMutex( &SleepingThreadsLock
);
448 InitializeListHead( &SleepingThreadsList
);
449 InitializeListHead( &SignalledConnections
);
450 Status
= TCPMemStartup();
451 if ( ! NT_SUCCESS(Status
) ) {
455 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
456 if( !NT_SUCCESS(Status
) ) {
461 RegisterOskitTCPEventHandlers( &EventHandlers
);
464 /* Register this protocol with IP layer */
465 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
467 ExInitializeNPagedLookasideList(
468 &TCPSegmentList
, /* Lookaside list */
469 NULL
, /* Allocate routine */
470 NULL
, /* Free routine */
472 sizeof(TCP_SEGMENT
), /* Size of each entry */
473 TAG('T','C','P','S'), /* Tag */
478 TCPInitialized
= TRUE
;
480 return STATUS_SUCCESS
;
484 NTSTATUS
TCPShutdown(VOID
)
486 * FUNCTION: Shuts down the TCP subsystem
488 * Status of operation
491 LARGE_INTEGER WaitForThread
;
494 return STATUS_SUCCESS
;
496 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
497 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
498 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
500 /* Deregister this protocol with IP layer */
501 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
503 ExDeleteNPagedLookasideList(&TCPSegmentList
);
505 TCPInitialized
= FALSE
;
509 PortsShutdown( &TCPPorts
);
513 return STATUS_SUCCESS
;
516 NTSTATUS
TCPTranslateError( int OskitError
) {
517 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
519 switch( OskitError
) {
520 case 0: Status
= STATUS_SUCCESS
; break;
521 case OSK_EADDRNOTAVAIL
:
522 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
523 case OSK_ECONNREFUSED
:
524 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
525 case OSK_EINPROGRESS
:
526 case OSK_EAGAIN
: Status
= STATUS_PENDING
; break;
527 default: Status
= STATUS_INVALID_CONNECTION
; break;
530 if (Status
!= STATUS_SUCCESS
)
531 DbgPrint("%d -> %x\n", OskitError
, Status
);
533 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
538 ( PCONNECTION_ENDPOINT Connection
,
539 PTDI_CONNECTION_INFORMATION ConnInfo
,
540 PTDI_CONNECTION_INFORMATION ReturnInfo
,
541 PTCP_COMPLETION_ROUTINE Complete
,
544 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
545 IP_ADDRESS RemoteAddress
;
548 PNEIGHBOR_CACHE_ENTRY NCE
;
550 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
552 Status
= AddrBuildAddress
553 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
557 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
559 return STATUS_NETWORK_UNREACHABLE
;
562 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
564 if (Connection
->State
& SEL_FIN
)
566 TcpipRecursiveMutexLeave( &TCPLock
);
567 return STATUS_REMOTE_DISCONNECT
;
570 /* Freed in TCPSocketState */
571 TI_DbgPrint(DEBUG_TCP
,
572 ("Connecting to address %x:%x\n",
573 RemoteAddress
.Address
.IPv4Address
,
576 if (!NT_SUCCESS(Status
)) {
577 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
578 TcpipRecursiveMutexLeave( &TCPLock
);
582 AddressToConnect
.sin_family
= AF_INET
;
583 AddressToBind
= AddressToConnect
;
584 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
586 Status
= TCPTranslateError
587 ( OskitTCPBind( Connection
->SocketContext
,
590 sizeof(AddressToBind
) ) );
592 if (NT_SUCCESS(Status
)) {
593 memcpy( &AddressToConnect
.sin_addr
,
594 &RemoteAddress
.Address
.IPv4Address
,
595 sizeof(AddressToConnect
.sin_addr
) );
596 AddressToConnect
.sin_port
= RemotePort
;
598 Status
= TCPTranslateError
599 ( OskitTCPConnect( Connection
->SocketContext
,
602 sizeof(AddressToConnect
) ) );
604 if (Status
== STATUS_PENDING
)
606 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
607 if( !Bucket
) return STATUS_NO_MEMORY
;
609 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
610 Bucket
->Request
.RequestContext
= Context
;
612 InsertHeadList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
616 TcpipRecursiveMutexLeave( &TCPLock
);
621 NTSTATUS TCPDisconnect
622 ( PCONNECTION_ENDPOINT Connection
,
624 PTDI_CONNECTION_INFORMATION ConnInfo
,
625 PTDI_CONNECTION_INFORMATION ReturnInfo
,
626 PTCP_COMPLETION_ROUTINE Complete
,
630 TI_DbgPrint(DEBUG_TCP
,("started\n"));
632 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
634 switch( Flags
& (TDI_DISCONNECT_ABORT
| TDI_DISCONNECT_RELEASE
) ) {
636 case TDI_DISCONNECT_ABORT
:
640 case TDI_DISCONNECT_ABORT
| TDI_DISCONNECT_RELEASE
:
644 case TDI_DISCONNECT_RELEASE
:
649 Status
= TCPTranslateError
650 ( OskitTCPShutdown( Connection
->SocketContext
, Flags
) );
652 TcpipRecursiveMutexLeave( &TCPLock
);
654 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
660 ( PCONNECTION_ENDPOINT Connection
) {
663 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
665 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
667 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
669 /* Make our code remove all pending IRPs */
670 Connection
->State
|= SEL_FIN
;
673 TcpipRecursiveMutexLeave( &TCPLock
);
675 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
680 NTSTATUS TCPReceiveData
681 ( PCONNECTION_ENDPOINT Connection
,
684 PULONG BytesReceived
,
686 PTCP_COMPLETION_ROUTINE Complete
,
688 OSK_PCHAR DataBuffer
;
689 UINT DataLen
, Received
= 0;
693 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
694 ReceiveLength
, Connection
->SocketContext
));
696 ASSERT_KM_POINTER(Connection
->SocketContext
);
698 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
701 if (Connection
->State
& SEL_FIN
)
703 TcpipRecursiveMutexLeave( &TCPLock
);
705 return STATUS_REMOTE_DISCONNECT
;
708 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
710 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
712 Status
= TCPTranslateError
714 ( Connection
->SocketContext
,
720 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
722 /* Keep this request around ... there was no data yet */
723 if( Status
== STATUS_PENDING
) {
724 /* Freed in TCPSocketState */
725 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
727 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
728 TcpipRecursiveMutexLeave( &TCPLock
);
729 return STATUS_NO_MEMORY
;
732 Bucket
->Request
.RequestNotifyObject
= Complete
;
733 Bucket
->Request
.RequestContext
= Context
;
736 InsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
737 Status
= STATUS_PENDING
;
738 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
740 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
741 *BytesReceived
= Received
;
744 TcpipRecursiveMutexLeave( &TCPLock
);
746 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
752 ( PCONNECTION_ENDPOINT Connection
,
757 PTCP_COMPLETION_ROUTINE Complete
,
763 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
764 SendLength
, Connection
->SocketContext
));
766 ASSERT_KM_POINTER(Connection
->SocketContext
);
768 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
770 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
771 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
772 Connection
->SocketContext
));
775 if (Connection
->State
& SEL_FIN
)
777 TcpipRecursiveMutexLeave( &TCPLock
);
779 return STATUS_REMOTE_DISCONNECT
;
782 Status
= TCPTranslateError
783 ( OskitTCPSend( Connection
->SocketContext
,
784 (OSK_PCHAR
)BufferData
, SendLength
,
787 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
789 /* Keep this request around ... there was no data yet */
790 if( Status
== STATUS_PENDING
) {
791 /* Freed in TCPSocketState */
792 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
794 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
795 TcpipRecursiveMutexLeave( &TCPLock
);
796 return STATUS_NO_MEMORY
;
799 Bucket
->Request
.RequestNotifyObject
= Complete
;
800 Bucket
->Request
.RequestContext
= Context
;
803 InsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
);
804 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
806 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
810 TcpipRecursiveMutexLeave( &TCPLock
);
812 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
817 VOID
TCPTimeout(VOID
) {
818 /* Now handled by TimerThread */
821 UINT
TCPAllocatePort( UINT HintPort
) {
823 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
826 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
829 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
832 VOID
TCPFreePort( UINT Port
) {
833 DeallocatePort( &TCPPorts
, Port
);
836 NTSTATUS TCPGetSockAddress
837 ( PCONNECTION_ENDPOINT Connection
,
838 PTRANSPORT_ADDRESS Address
,
839 BOOLEAN GetRemote
) {
840 OSK_UINT LocalAddress
, RemoteAddress
;
841 OSK_UI16 LocalPort
, RemotePort
;
842 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
844 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
847 ( Connection
->SocketContext
,
848 &LocalAddress
, &LocalPort
,
849 &RemoteAddress
, &RemotePort
);
851 AddressIP
->TAAddressCount
= 1;
852 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
853 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
854 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
855 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
857 TcpipRecursiveMutexLeave( &TCPLock
);
859 return STATUS_SUCCESS
;
862 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
864 PLIST_ENTRY ListHead
[4];
869 ListHead
[0] = &Endpoint
->SendRequest
;
870 ListHead
[1] = &Endpoint
->ReceiveRequest
;
871 ListHead
[2] = &Endpoint
->ConnectRequest
;
872 ListHead
[3] = &Endpoint
->ListenRequest
;
874 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
876 for( i
= 0; i
< 4; i
++ )
878 for( Entry
= ListHead
[i
]->Flink
;
879 Entry
!= ListHead
[i
];
880 Entry
= Entry
->Flink
)
882 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
883 if( Bucket
->Request
.RequestContext
== Irp
)
885 RemoveEntryList( &Bucket
->Entry
);
886 exFreePool( Bucket
);
892 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);