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 LIST_ENTRY SleepingThreadsList
;
21 FAST_MUTEX SleepingThreadsLock
;
22 RECURSIVE_MUTEX TCPLock
;
25 static VOID
HandleSignalledConnection( PCONNECTION_ENDPOINT Connection
) {
26 NTSTATUS Status
= STATUS_SUCCESS
;
27 PTCP_COMPLETION_ROUTINE Complete
;
33 ASSERT_LOCKED(&TCPLock
);
35 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
36 Connection
, Connection
->SocketContext
));
38 if( Connection
->SignalState
& SEL_FIN
) {
39 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
41 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
42 &Connection
->Lock
)) != NULL
)
44 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
45 Complete
= Bucket
->Request
.RequestNotifyObject
;
47 /* We have to notify oskittcp of the abortion */
50 TDI_DISCONNECT_RELEASE
| TDI_DISCONNECT_ABORT
,
53 Bucket
->Request
.RequestNotifyObject
,
54 (PIRP
)Bucket
->Request
.RequestContext
);
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 /* We have to notify oskittcp of the abortion */
70 TDI_DISCONNECT_RELEASE
,
73 Bucket
->Request
.RequestNotifyObject
,
74 (PIRP
)Bucket
->Request
.RequestContext
);
76 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
81 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
82 &Connection
->Lock
)) != NULL
)
84 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
85 Complete
= Bucket
->Request
.RequestNotifyObject
;
87 /* We have to notify oskittcp of the abortion */
88 TCPAbortListenForSocket(Connection
->AddressFile
->Listener
,
91 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
94 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
95 &Connection
->Lock
)) != NULL
)
97 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
98 Complete
= Bucket
->Request
.RequestNotifyObject
;
100 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
103 Connection
->SignalState
= 0;
106 /* Things that can happen when we try the initial connection */
107 if( Connection
->SignalState
& SEL_CONNECT
) {
108 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
109 &Connection
->Lock
)) != NULL
) {
111 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
113 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
114 Complete
= Bucket
->Request
.RequestNotifyObject
;
115 TI_DbgPrint(DEBUG_TCP
,
116 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
118 Complete( Bucket
->Request
.RequestContext
, STATUS_SUCCESS
, 0 );
120 /* Frees the bucket allocated in TCPConnect */
121 exFreePool( Bucket
);
125 if( Connection
->SignalState
& SEL_ACCEPT
) {
126 /* Handle readable on a listening socket --
127 * TODO: Implement filtering
130 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
132 IsListEmpty(&Connection
->ListenRequest
) ?
133 "empty" : "nonempty"));
135 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
136 &Connection
->Lock
)) != NULL
) {
137 PIO_STACK_LOCATION IrpSp
;
139 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
140 Complete
= Bucket
->Request
.RequestNotifyObject
;
142 Irp
= Bucket
->Request
.RequestContext
;
143 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
145 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
146 Status
= TCPServiceListeningSocket
147 ( Connection
->AddressFile
->Listener
,
148 Bucket
->AssociatedEndpoint
,
149 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
151 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
153 if( Status
== STATUS_PENDING
) {
154 ExInterlockedInsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
, &Connection
->Lock
);
157 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
158 exFreePool( Bucket
);
163 /* Things that happen after we're connected */
164 if( Connection
->SignalState
& SEL_READ
) {
165 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
166 IsListEmpty(&Connection
->ReceiveRequest
) ?
167 "empty" : "nonempty"));
169 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
170 &Connection
->Lock
)) != NULL
) {
171 OSK_UINT RecvLen
= 0, Received
= 0;
172 PVOID RecvBuffer
= 0;
174 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
175 Complete
= Bucket
->Request
.RequestNotifyObject
;
177 Irp
= Bucket
->Request
.RequestContext
;
178 Mdl
= Irp
->MdlAddress
;
180 TI_DbgPrint(DEBUG_TCP
,
181 ("Getting the user buffer from %x\n", Mdl
));
183 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
185 TI_DbgPrint(DEBUG_TCP
,
186 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
188 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
191 ("Connection->SocketContext: %x\n",
192 Connection
->SocketContext
));
193 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
195 Status
= TCPTranslateError
196 ( OskitTCPRecv( Connection
->SocketContext
,
202 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
204 if( Status
== STATUS_SUCCESS
) {
205 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
208 Complete( Bucket
->Request
.RequestContext
,
209 STATUS_SUCCESS
, Received
);
210 exFreePool( Bucket
);
211 } else if( Status
== STATUS_PENDING
) {
212 ExInterlockedInsertHeadList
213 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
216 TI_DbgPrint(DEBUG_TCP
,
217 ("Completing Receive request: %x %x\n",
218 Bucket
->Request
, Status
));
219 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
220 exFreePool( Bucket
);
224 if( Connection
->SignalState
& SEL_WRITE
) {
225 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
226 IsListEmpty(&Connection
->SendRequest
) ?
227 "empty" : "nonempty"));
229 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
230 &Connection
->Lock
)) != NULL
) {
231 OSK_UINT SendLen
= 0, Sent
= 0;
232 PVOID SendBuffer
= 0;
234 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
235 Complete
= Bucket
->Request
.RequestNotifyObject
;
237 Irp
= Bucket
->Request
.RequestContext
;
238 Mdl
= Irp
->MdlAddress
;
240 TI_DbgPrint(DEBUG_TCP
,
241 ("Getting the user buffer from %x\n", Mdl
));
243 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
245 TI_DbgPrint(DEBUG_TCP
,
246 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
248 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
251 ("Connection->SocketContext: %x\n",
252 Connection
->SocketContext
));
254 Status
= TCPTranslateError
255 ( OskitTCPSend( Connection
->SocketContext
,
261 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
263 if( Status
== STATUS_SUCCESS
) {
264 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
267 Complete( Bucket
->Request
.RequestContext
,
268 STATUS_SUCCESS
, Sent
);
269 exFreePool( Bucket
);
270 } else if( Status
== STATUS_PENDING
) {
271 ExInterlockedInsertHeadList
272 ( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
275 TI_DbgPrint(DEBUG_TCP
,
276 ("Completing Send request: %x %x\n",
277 Bucket
->Request
, Status
));
278 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
279 exFreePool( Bucket
);
284 Connection
->SignalState
= 0;
285 Connection
->Signalled
= FALSE
;
288 VOID
DrainSignals() {
289 PCONNECTION_ENDPOINT Connection
;
290 PLIST_ENTRY ListEntry
;
292 while( (ListEntry
= ExInterlockedRemoveHeadList(&SignalledConnectionsList
,
293 &SignalledConnectionsLock
)) != NULL
) {
294 Connection
= CONTAINING_RECORD( ListEntry
, CONNECTION_ENDPOINT
,
296 HandleSignalledConnection( Connection
);
300 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
301 PCONNECTION_ENDPOINT Connection
=
302 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
306 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
308 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
310 /* Initialize spin lock that protects the connection endpoint file object */
311 TcpipInitializeSpinLock(&Connection
->Lock
);
312 InitializeListHead(&Connection
->ConnectRequest
);
313 InitializeListHead(&Connection
->ListenRequest
);
314 InitializeListHead(&Connection
->ReceiveRequest
);
315 InitializeListHead(&Connection
->SendRequest
);
317 /* Save client context pointer */
318 Connection
->ClientContext
= ClientContext
;
323 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
324 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
325 exFreePool( Connection
);
328 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
329 UINT Family
, UINT Type
, UINT Proto
) {
332 ASSERT_LOCKED(&TCPLock
);
334 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
336 Connection
, Family
, Type
, Proto
));
338 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
339 &Connection
->SocketContext
,
344 ASSERT_KM_POINTER(Connection
->SocketContext
);
346 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
347 Connection
->SocketContext
));
352 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
354 * FUNCTION: Receives and queues TCP data
356 * IPPacket = Pointer to an IP packet that was received
358 * This is the low level interface for receiving TCP data
361 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
363 IPPacket
->HeaderSize
));
365 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
367 OskitTCPReceiveDatagram( IPPacket
->Header
,
369 IPPacket
->HeaderSize
);
373 TcpipRecursiveMutexLeave( &TCPLock
);
377 int TCPSocketState( void *ClientData
,
379 void *WhichConnection
,
382 int TCPPacketSend( void *ClientData
,
386 POSK_IFADDR
TCPFindInterface( void *ClientData
,
389 OSK_SOCKADDR
*ReqAddr
);
391 NTSTATUS
TCPMemStartup( void );
392 void *TCPMalloc( void *ClientData
,
393 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
394 void TCPFree( void *ClientData
,
395 void *data
, OSK_PCHAR file
, OSK_UINT line
);
396 void TCPMemShutdown( void );
398 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
401 void TCPWakeup( void *ClientData
, void *token
);
403 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
404 NULL
, /* Client Data */
405 TCPSocketState
, /* SocketState */
406 TCPPacketSend
, /* PacketSend */
407 TCPFindInterface
, /* FindInterface */
408 TCPMalloc
, /* Malloc */
410 TCPSleep
, /* Sleep */
411 TCPWakeup
/* Wakeup */
414 static KEVENT TimerLoopEvent
;
415 static HANDLE TimerThreadHandle
;
418 * We are running 2 timers here, one with a 200ms interval (fast) and the other
419 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
420 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
421 * "slow" events at 500 and 1000.
424 TimerThread(PVOID Context
)
426 LARGE_INTEGER Timeout
;
428 unsigned Current
, NextFast
, NextSlow
, Next
;
435 if (Next
== NextFast
) {
438 if (Next
== NextSlow
) {
441 Next
= min(NextFast
, NextSlow
);
442 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
443 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
445 if (Status
!= STATUS_TIMEOUT
) {
446 PsTerminateSystemThread(Status
);
449 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
450 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
451 if (Next
== NextSlow
) {
454 TcpipRecursiveMutexLeave( &TCPLock
);
469 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
470 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
475 NTSTATUS
TCPStartup(VOID
)
477 * FUNCTION: Initializes the TCP subsystem
479 * Status of operation
484 TcpipRecursiveMutexInit( &TCPLock
);
485 ExInitializeFastMutex( &SleepingThreadsLock
);
486 KeInitializeSpinLock( &SignalledConnectionsLock
);
487 InitializeListHead( &SleepingThreadsList
);
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
, TRUE
);
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
;
550 PortsShutdown( &TCPPorts
);
554 return STATUS_SUCCESS
;
557 NTSTATUS
TCPTranslateError( int OskitError
) {
560 switch( OskitError
) {
561 case 0: Status
= STATUS_SUCCESS
; break;
562 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
563 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
564 case OSK_ECONNREFUSED
:
565 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
566 case OSK_EWOULDBLOCK
:
567 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
568 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
570 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
571 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
572 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
573 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
574 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
575 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
577 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
578 Status
= STATUS_INVALID_CONNECTION
;
582 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
587 ( PCONNECTION_ENDPOINT Connection
,
588 PTDI_CONNECTION_INFORMATION ConnInfo
,
589 PTDI_CONNECTION_INFORMATION ReturnInfo
,
590 PTCP_COMPLETION_ROUTINE Complete
,
593 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
594 IP_ADDRESS RemoteAddress
;
597 PNEIGHBOR_CACHE_ENTRY NCE
;
599 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
601 ASSERT_LOCKED(&TCPLock
);
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 if (Connection
->State
& SEL_FIN
)
620 return STATUS_REMOTE_DISCONNECT
;
623 /* Freed in TCPSocketState */
624 TI_DbgPrint(DEBUG_TCP
,
625 ("Connecting to address %x:%x\n",
626 RemoteAddress
.Address
.IPv4Address
,
629 AddressToConnect
.sin_family
= AF_INET
;
630 AddressToBind
= AddressToConnect
;
631 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
633 Status
= TCPTranslateError
634 ( OskitTCPBind( Connection
->SocketContext
,
636 sizeof(AddressToBind
) ) );
638 if (NT_SUCCESS(Status
)) {
639 memcpy( &AddressToConnect
.sin_addr
,
640 &RemoteAddress
.Address
.IPv4Address
,
641 sizeof(AddressToConnect
.sin_addr
) );
642 AddressToConnect
.sin_port
= RemotePort
;
644 Status
= TCPTranslateError
645 ( OskitTCPConnect( Connection
->SocketContext
,
648 sizeof(AddressToConnect
) ) );
650 if (Status
== STATUS_PENDING
)
652 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
653 if( !Bucket
) return STATUS_NO_MEMORY
;
655 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
656 Bucket
->Request
.RequestContext
= Context
;
658 IoMarkIrpPending((PIRP
)Context
);
660 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
, &Connection
->Lock
);
667 NTSTATUS TCPDisconnect
668 ( PCONNECTION_ENDPOINT Connection
,
670 PTDI_CONNECTION_INFORMATION ConnInfo
,
671 PTDI_CONNECTION_INFORMATION ReturnInfo
,
672 PTCP_COMPLETION_ROUTINE Complete
,
676 ASSERT_LOCKED(&TCPLock
);
678 TI_DbgPrint(DEBUG_TCP
,("started\n"));
680 switch( Flags
& (TDI_DISCONNECT_ABORT
| TDI_DISCONNECT_RELEASE
) ) {
682 case TDI_DISCONNECT_ABORT
:
686 case TDI_DISCONNECT_ABORT
| TDI_DISCONNECT_RELEASE
:
690 case TDI_DISCONNECT_RELEASE
:
695 Status
= TCPTranslateError
696 ( OskitTCPShutdown( Connection
->SocketContext
, Flags
) );
698 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
704 ( PCONNECTION_ENDPOINT Connection
) {
707 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
709 ASSERT_LOCKED(&TCPLock
);
711 /* Make our code remove all pending IRPs */
712 Connection
->State
|= SEL_FIN
;
715 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
716 if (Status
== STATUS_SUCCESS
)
717 Connection
->SocketContext
= NULL
;
719 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
724 NTSTATUS TCPReceiveData
725 ( PCONNECTION_ENDPOINT Connection
,
728 PULONG BytesReceived
,
730 PTCP_COMPLETION_ROUTINE Complete
,
733 UINT DataLen
, Received
= 0;
737 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
738 ReceiveLength
, Connection
->SocketContext
));
740 ASSERT_LOCKED(&TCPLock
);
742 ASSERT_KM_POINTER(Connection
->SocketContext
);
745 if (Connection
->State
& SEL_FIN
)
748 return STATUS_REMOTE_DISCONNECT
;
751 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
753 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
755 Status
= TCPTranslateError
757 ( Connection
->SocketContext
,
763 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
765 /* Keep this request around ... there was no data yet */
766 if( Status
== STATUS_PENDING
) {
767 /* Freed in TCPSocketState */
768 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
770 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
771 return STATUS_NO_MEMORY
;
774 Bucket
->Request
.RequestNotifyObject
= Complete
;
775 Bucket
->Request
.RequestContext
= Context
;
778 IoMarkIrpPending((PIRP
)Context
);
780 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
781 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
783 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
784 *BytesReceived
= Received
;
787 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
793 ( PCONNECTION_ENDPOINT Connection
,
798 PTCP_COMPLETION_ROUTINE Complete
,
804 ASSERT_LOCKED(&TCPLock
);
806 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
807 SendLength
, Connection
->SocketContext
));
809 ASSERT_KM_POINTER(Connection
->SocketContext
);
811 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
812 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
813 Connection
->SocketContext
));
816 if (Connection
->State
& SEL_FIN
)
819 return STATUS_REMOTE_DISCONNECT
;
822 Status
= TCPTranslateError
823 ( OskitTCPSend( Connection
->SocketContext
,
824 (OSK_PCHAR
)BufferData
, SendLength
,
827 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
829 /* Keep this request around ... there was no data yet */
830 if( Status
== STATUS_PENDING
) {
831 /* Freed in TCPSocketState */
832 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
834 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
835 return STATUS_NO_MEMORY
;
838 Bucket
->Request
.RequestNotifyObject
= Complete
;
839 Bucket
->Request
.RequestContext
= Context
;
842 IoMarkIrpPending((PIRP
)Context
);
844 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
845 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
847 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
851 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
856 VOID
TCPTimeout(VOID
) {
857 /* Now handled by TimerThread */
860 UINT
TCPAllocatePort( UINT HintPort
) {
862 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
865 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
868 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
871 VOID
TCPFreePort( UINT Port
) {
872 DeallocatePort( &TCPPorts
, Port
);
875 NTSTATUS TCPGetSockAddress
876 ( PCONNECTION_ENDPOINT Connection
,
877 PTRANSPORT_ADDRESS Address
,
878 BOOLEAN GetRemote
) {
879 OSK_UINT LocalAddress
, RemoteAddress
;
880 OSK_UI16 LocalPort
, RemotePort
;
881 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
884 ASSERT_LOCKED(&TCPLock
);
886 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
887 &LocalAddress
, &LocalPort
,
888 &RemoteAddress
, &RemotePort
));
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
);