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
;
19 CLIENT_DATA ClientInfo
;
22 CompleteBucketWorker(PVOID Context
)
24 PTDI_BUCKET Bucket
= Context
;
25 PCONNECTION_ENDPOINT Connection
;
26 PTCP_COMPLETION_ROUTINE Complete
;
30 Connection
= Bucket
->AssociatedEndpoint
;
31 Complete
= Bucket
->Request
.RequestNotifyObject
;
33 Complete(Bucket
->Request
.RequestContext
, Bucket
->Status
, Bucket
->Information
);
35 ExFreePoolWithTag(Bucket
, TDI_BUCKET_TAG
);
37 DereferenceObject(Connection
);
41 CompleteBucket(PCONNECTION_ENDPOINT Connection
, PTDI_BUCKET Bucket
)
43 Bucket
->AssociatedEndpoint
= Connection
;
44 ReferenceObject(Connection
);
45 ChewCreate(CompleteBucketWorker
, Bucket
);
48 VOID
HandleSignalledConnection(PCONNECTION_ENDPOINT Connection
)
56 if (ClientInfo
.Unlocked
)
57 LockObjectAtDpcLevel(Connection
);
59 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
60 Connection
, Connection
->SocketContext
));
62 /* Things that can happen when we try the initial connection */
63 if( Connection
->SignalState
& (SEL_CONNECT
| SEL_FIN
) ) {
64 while (!IsListEmpty(&Connection
->ConnectRequest
)) {
65 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
67 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
69 Bucket
->Status
= (Connection
->SignalState
& SEL_CONNECT
) ? STATUS_SUCCESS
: STATUS_CANCELLED
;
70 Bucket
->Information
= 0;
72 CompleteBucket(Connection
, Bucket
);
76 if( Connection
->SignalState
& (SEL_ACCEPT
| SEL_FIN
) ) {
77 /* Handle readable on a listening socket --
78 * TODO: Implement filtering
80 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
82 IsListEmpty(&Connection
->ListenRequest
) ?
83 "empty" : "nonempty"));
85 while (!IsListEmpty(&Connection
->ListenRequest
)) {
86 PIO_STACK_LOCATION IrpSp
;
88 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
90 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
92 Irp
= Bucket
->Request
.RequestContext
;
93 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
95 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
97 if (Connection
->SignalState
& SEL_ACCEPT
)
99 Status
= TCPServiceListeningSocket(Connection
->AddressFile
->Listener
,
100 Bucket
->AssociatedEndpoint
,
101 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
105 /* We got here because of a SEL_FIN event */
106 Status
= STATUS_CANCELLED
;
109 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
111 if( Status
== STATUS_PENDING
&& !(Connection
->SignalState
& SEL_FIN
) ) {
112 InsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
);
115 Bucket
->Status
= (Status
== STATUS_PENDING
) ? STATUS_CANCELLED
: Status
;
116 Bucket
->Information
= 0;
117 DereferenceObject(Bucket
->AssociatedEndpoint
);
119 CompleteBucket(Connection
, Bucket
);
124 /* Things that happen after we're connected */
125 if( Connection
->SignalState
& (SEL_READ
| SEL_FIN
) ) {
126 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
127 IsListEmpty(&Connection
->ReceiveRequest
) ?
128 "empty" : "nonempty"));
130 while (!IsListEmpty(&Connection
->ReceiveRequest
)) {
131 OSK_UINT RecvLen
= 0, Received
= 0;
132 PVOID RecvBuffer
= 0;
134 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
136 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
138 Irp
= Bucket
->Request
.RequestContext
;
139 Mdl
= Irp
->MdlAddress
;
141 TI_DbgPrint(DEBUG_TCP
,
142 ("Getting the user buffer from %x\n", Mdl
));
144 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
146 TI_DbgPrint(DEBUG_TCP
,
147 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
149 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
152 ("Connection->SocketContext: %x\n",
153 Connection
->SocketContext
));
154 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
156 if (Connection
->SignalState
& SEL_READ
)
158 Status
= TCPTranslateError(OskitTCPRecv(Connection
->SocketContext
,
166 /* We got here because of a SEL_FIN event */
167 Status
= STATUS_CANCELLED
;
170 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
172 if( Status
== STATUS_PENDING
&& !(Connection
->SignalState
& SEL_FIN
) ) {
173 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
176 TI_DbgPrint(DEBUG_TCP
,
177 ("Completing Receive request: %x %x\n",
178 Bucket
->Request
, Status
));
180 Bucket
->Status
= (Status
== STATUS_PENDING
) ? STATUS_CANCELLED
: Status
;
181 Bucket
->Information
= (Bucket
->Status
== STATUS_SUCCESS
) ? Received
: 0;
183 CompleteBucket(Connection
, Bucket
);
187 if( Connection
->SignalState
& (SEL_WRITE
| SEL_FIN
) ) {
188 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
189 IsListEmpty(&Connection
->SendRequest
) ?
190 "empty" : "nonempty"));
192 while (!IsListEmpty(&Connection
->SendRequest
)) {
193 OSK_UINT SendLen
= 0, Sent
= 0;
194 PVOID SendBuffer
= 0;
196 Entry
= RemoveHeadList( &Connection
->SendRequest
);
198 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
200 Irp
= Bucket
->Request
.RequestContext
;
201 Mdl
= Irp
->MdlAddress
;
203 TI_DbgPrint(DEBUG_TCP
,
204 ("Getting the user buffer from %x\n", Mdl
));
206 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
208 TI_DbgPrint(DEBUG_TCP
,
209 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
211 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
214 ("Connection->SocketContext: %x\n",
215 Connection
->SocketContext
));
217 if (Connection
->SignalState
& SEL_WRITE
)
219 Status
= TCPTranslateError(OskitTCPSend(Connection
->SocketContext
,
227 /* We got here because of a SEL_FIN event */
228 Status
= STATUS_CANCELLED
;
231 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
233 if( Status
== STATUS_PENDING
&& !(Connection
->SignalState
& SEL_FIN
) ) {
234 InsertHeadList( &Connection
->SendRequest
, &Bucket
->Entry
);
237 TI_DbgPrint(DEBUG_TCP
,
238 ("Completing Send request: %x %x\n",
239 Bucket
->Request
, Status
));
241 Bucket
->Status
= (Status
== STATUS_PENDING
) ? STATUS_CANCELLED
: Status
;
242 Bucket
->Information
= (Bucket
->Status
== STATUS_SUCCESS
) ? Sent
: 0;
244 CompleteBucket(Connection
, Bucket
);
248 if( Connection
->SignalState
& (SEL_WRITE
| SEL_FIN
) ) {
249 while (!IsListEmpty(&Connection
->ShutdownRequest
)) {
250 Entry
= RemoveHeadList( &Connection
->ShutdownRequest
);
252 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
254 if (!(Connection
->SignalState
& SEL_FIN
))
256 /* See if we can satisfy this after the events */
257 if (IsListEmpty(&Connection
->SendRequest
))
259 /* Send queue is empty so we're good to go */
260 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
));
264 /* We still have to wait */
265 Status
= STATUS_PENDING
;
270 /* We were cancelled by a FIN */
271 Status
= STATUS_CANCELLED
;
274 if( Status
== STATUS_PENDING
) {
275 InsertHeadList( &Connection
->ShutdownRequest
, &Bucket
->Entry
);
278 TI_DbgPrint(DEBUG_TCP
,
279 ("Completing shutdown request: %x %x\n",
280 Bucket
->Request
, Status
));
282 Bucket
->Status
= Status
;
283 Bucket
->Information
= 0;
285 CompleteBucket(Connection
, Bucket
);
290 if (Connection
->SignalState
& SEL_FIN
)
292 Connection
->SocketContext
= NULL
;
293 DereferenceObject(Connection
);
296 if (ClientInfo
.Unlocked
)
297 UnlockObjectFromDpcLevel(Connection
);
300 VOID
ConnectionFree(PVOID Object
) {
301 PCONNECTION_ENDPOINT Connection
= Object
;
304 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
306 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
307 RemoveEntryList(&Connection
->ListEntry
);
308 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
310 ExFreePoolWithTag( Connection
, CONN_ENDPT_TAG
);
313 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
314 PCONNECTION_ENDPOINT Connection
=
315 ExAllocatePoolWithTag(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
),
320 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
322 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
324 /* Initialize spin lock that protects the connection endpoint file object */
325 KeInitializeSpinLock(&Connection
->Lock
);
326 InitializeListHead(&Connection
->ConnectRequest
);
327 InitializeListHead(&Connection
->ListenRequest
);
328 InitializeListHead(&Connection
->ReceiveRequest
);
329 InitializeListHead(&Connection
->SendRequest
);
330 InitializeListHead(&Connection
->ShutdownRequest
);
332 /* Save client context pointer */
333 Connection
->ClientContext
= ClientContext
;
336 Connection
->RefCount
= 2;
337 Connection
->Free
= ConnectionFree
;
339 /* Add connection endpoint to global list */
340 ExInterlockedInsertTailList(&ConnectionEndpointListHead
,
341 &Connection
->ListEntry
,
342 &ConnectionEndpointListLock
);
347 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
348 UINT Family
, UINT Type
, UINT Proto
) {
352 LockObject(Connection
, &OldIrql
);
354 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
356 Connection
, Family
, Type
, Proto
));
358 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
359 &Connection
->SocketContext
,
364 ASSERT_KM_POINTER(Connection
->SocketContext
);
366 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
367 Connection
->SocketContext
));
369 UnlockObject(Connection
, OldIrql
);
374 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
376 * FUNCTION: Receives and queues TCP data
378 * IPPacket = Pointer to an IP packet that was received
380 * This is the low level interface for receiving TCP data
385 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
387 IPPacket
->HeaderSize
));
389 KeAcquireSpinLock(&ClientInfo
.Lock
, &OldIrql
);
390 ClientInfo
.Unlocked
= TRUE
;
391 ClientInfo
.OldIrql
= OldIrql
;
393 OskitTCPReceiveDatagram( IPPacket
->Header
,
395 IPPacket
->HeaderSize
);
397 ClientInfo
.Unlocked
= FALSE
;
398 KeReleaseSpinLock(&ClientInfo
.Lock
, OldIrql
);
402 int TCPSocketState( void *ClientData
,
404 void *WhichConnection
,
407 int TCPPacketSend( void *ClientData
,
411 POSK_IFADDR
TCPFindInterface( void *ClientData
,
414 OSK_SOCKADDR
*ReqAddr
);
416 NTSTATUS
TCPMemStartup( void );
417 void *TCPMalloc( void *ClientData
,
418 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
419 void TCPFree( void *ClientData
,
420 void *data
, OSK_PCHAR file
, OSK_UINT line
);
421 void TCPMemShutdown( void );
423 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
424 NULL
, /* Client Data */
425 TCPSocketState
, /* SocketState */
426 TCPPacketSend
, /* PacketSend */
427 TCPFindInterface
, /* FindInterface */
428 TCPMalloc
, /* Malloc */
434 static KEVENT TimerLoopEvent
;
435 static HANDLE TimerThreadHandle
;
438 * We are running 2 timers here, one with a 200ms interval (fast) and the other
439 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
440 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
441 * "slow" events at 500 and 1000.
444 TimerThread(PVOID Context
)
446 LARGE_INTEGER Timeout
;
448 unsigned Current
, NextFast
, NextSlow
, Next
;
455 if (Next
== NextFast
) {
458 if (Next
== NextSlow
) {
461 Next
= min(NextFast
, NextSlow
);
462 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
463 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
465 if (Status
!= STATUS_TIMEOUT
) {
466 PsTerminateSystemThread(Status
);
469 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
484 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
485 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
489 NTSTATUS
TCPStartup(VOID
)
491 * FUNCTION: Initializes the TCP subsystem
493 * Status of operation
498 Status
= TCPMemStartup();
499 if ( ! NT_SUCCESS(Status
) ) {
503 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
504 if( !NT_SUCCESS(Status
) ) {
509 KeInitializeSpinLock(&ClientInfo
.Lock
);
510 ClientInfo
.Unlocked
= FALSE
;
512 RegisterOskitTCPEventHandlers( &EventHandlers
);
515 /* Register this protocol with IP layer */
516 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
518 ExInitializeNPagedLookasideList(
519 &TCPSegmentList
, /* Lookaside list */
520 NULL
, /* Allocate routine */
521 NULL
, /* Free routine */
523 sizeof(TCP_SEGMENT
), /* Size of each entry */
529 TCPInitialized
= TRUE
;
531 return STATUS_SUCCESS
;
535 NTSTATUS
TCPShutdown(VOID
)
537 * FUNCTION: Shuts down the TCP subsystem
539 * Status of operation
542 LARGE_INTEGER WaitForThread
;
545 return STATUS_SUCCESS
;
547 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
548 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
549 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
551 /* Deregister this protocol with IP layer */
552 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
554 ExDeleteNPagedLookasideList(&TCPSegmentList
);
556 TCPInitialized
= FALSE
;
560 PortsShutdown( &TCPPorts
);
564 return STATUS_SUCCESS
;
567 NTSTATUS
TCPTranslateError( int OskitError
) {
570 switch( OskitError
) {
571 case 0: Status
= STATUS_SUCCESS
; break;
572 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
573 case OSK_EADDRINUSE
: Status
= STATUS_ADDRESS_ALREADY_EXISTS
; break;
574 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
575 case OSK_ECONNREFUSED
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
576 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_DISCONNECT
; break;
577 case OSK_ECONNABORTED
: Status
= STATUS_LOCAL_DISCONNECT
; 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 /* Freed in TCPSocketState */
625 TI_DbgPrint(DEBUG_TCP
,
626 ("Connecting to address %x:%x\n",
627 RemoteAddress
.Address
.IPv4Address
,
630 AddressToConnect
.sin_family
= AF_INET
;
631 AddressToBind
= AddressToConnect
;
633 LockObject(Connection
, &OldIrql
);
635 if (!Connection
->AddressFile
)
637 UnlockObject(Connection
, OldIrql
);
638 return STATUS_INVALID_PARAMETER
;
641 if (AddrIsUnspecified(&Connection
->AddressFile
->Address
))
643 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
645 UnlockObject(Connection
, OldIrql
);
646 return STATUS_NETWORK_UNREACHABLE
;
649 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
653 AddressToBind
.sin_addr
.s_addr
= Connection
->AddressFile
->Address
.Address
.IPv4Address
;
656 Status
= TCPTranslateError
657 ( OskitTCPBind( Connection
->SocketContext
,
659 sizeof(AddressToBind
) ) );
661 if (NT_SUCCESS(Status
)) {
662 memcpy( &AddressToConnect
.sin_addr
,
663 &RemoteAddress
.Address
.IPv4Address
,
664 sizeof(AddressToConnect
.sin_addr
) );
665 AddressToConnect
.sin_port
= RemotePort
;
667 Status
= TCPTranslateError
668 ( OskitTCPConnect( Connection
->SocketContext
,
670 sizeof(AddressToConnect
) ) );
672 if (Status
== STATUS_PENDING
)
674 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
677 UnlockObject(Connection
, OldIrql
);
678 return STATUS_NO_MEMORY
;
681 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
682 Bucket
->Request
.RequestContext
= Context
;
684 InsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
688 UnlockObject(Connection
, OldIrql
);
693 NTSTATUS TCPDisconnect
694 ( PCONNECTION_ENDPOINT Connection
,
696 PTDI_CONNECTION_INFORMATION ConnInfo
,
697 PTDI_CONNECTION_INFORMATION ReturnInfo
,
698 PTCP_COMPLETION_ROUTINE Complete
,
700 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
705 TI_DbgPrint(DEBUG_TCP
,("started\n"));
707 LockObject(Connection
, &OldIrql
);
709 if (Flags
& TDI_DISCONNECT_RELEASE
)
711 /* See if we can satisfy this right now */
712 if (IsListEmpty(&Connection
->SendRequest
))
714 /* Send queue is empty so we're good to go */
715 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
));
717 UnlockObject(Connection
, OldIrql
);
722 /* Otherwise we wait for the send queue to be empty */
725 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
727 /* This request overrides any pending graceful disconnects */
728 while (!IsListEmpty(&Connection
->ShutdownRequest
))
730 Entry
= RemoveHeadList(&Connection
->ShutdownRequest
);
732 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
734 Bucket
->Information
= 0;
735 Bucket
->Status
= STATUS_FILE_CLOSED
;
737 CompleteBucket(Connection
, Bucket
);
740 /* Also kill any pending reads and writes */
741 while (!IsListEmpty(&Connection
->SendRequest
))
743 Entry
= RemoveHeadList(&Connection
->SendRequest
);
745 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
747 Bucket
->Information
= 0;
748 Bucket
->Status
= STATUS_FILE_CLOSED
;
750 CompleteBucket(Connection
, Bucket
);
753 while (!IsListEmpty(&Connection
->ReceiveRequest
))
755 Entry
= RemoveHeadList(&Connection
->ReceiveRequest
);
757 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
759 Bucket
->Information
= 0;
760 Bucket
->Status
= STATUS_FILE_CLOSED
;
762 CompleteBucket(Connection
, Bucket
);
765 /* An abort never pends; we just drop everything and complete */
766 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
768 UnlockObject(Connection
, OldIrql
);
773 /* We couldn't complete the request now because we need to wait for outstanding I/O */
774 Bucket
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
777 UnlockObject(Connection
, OldIrql
);
778 return STATUS_NO_MEMORY
;
781 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
782 Bucket
->Request
.RequestContext
= Context
;
784 InsertTailList(&Connection
->ShutdownRequest
, &Bucket
->Entry
);
786 UnlockObject(Connection
, OldIrql
);
788 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
790 return STATUS_PENDING
;
794 ( PCONNECTION_ENDPOINT Connection
)
800 LockObject(Connection
, &OldIrql
);
801 Socket
= Connection
->SocketContext
;
802 Connection
->SocketContext
= NULL
;
804 /* We should not be associated to an address file at this point */
805 ASSERT(!Connection
->AddressFile
);
807 /* Don't try to close again if the other side closed us already */
810 /* We need to close here otherwise oskit will never indicate
811 * SEL_FIN and we will never fully close the connection */
812 Status
= TCPTranslateError( OskitTCPClose( Socket
) );
814 if (!NT_SUCCESS(Status
))
816 Connection
->SocketContext
= Socket
;
817 UnlockObject(Connection
, OldIrql
);
823 /* We are already closed by the other end so return success */
824 Status
= STATUS_SUCCESS
;
827 UnlockObject(Connection
, OldIrql
);
829 DereferenceObject(Connection
);
834 NTSTATUS TCPReceiveData
835 ( PCONNECTION_ENDPOINT Connection
,
838 PULONG BytesReceived
,
840 PTCP_COMPLETION_ROUTINE Complete
,
843 UINT DataLen
, Received
= 0;
848 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
849 ReceiveLength
, Connection
->SocketContext
));
851 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
853 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
855 LockObject(Connection
, &OldIrql
);
857 Status
= TCPTranslateError
859 ( Connection
->SocketContext
,
865 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
867 /* Keep this request around ... there was no data yet */
868 if( Status
== STATUS_PENDING
) {
869 /* Freed in TCPSocketState */
870 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
872 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
873 UnlockObject(Connection
, OldIrql
);
874 return STATUS_NO_MEMORY
;
877 Bucket
->Request
.RequestNotifyObject
= Complete
;
878 Bucket
->Request
.RequestContext
= Context
;
881 InsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
882 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
884 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
885 *BytesReceived
= Received
;
888 UnlockObject(Connection
, OldIrql
);
890 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
896 ( PCONNECTION_ENDPOINT Connection
,
901 PTCP_COMPLETION_ROUTINE Complete
,
908 LockObject(Connection
, &OldIrql
);
910 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
911 SendLength
, Connection
->SocketContext
));
913 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
914 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
915 Connection
->SocketContext
));
917 Status
= TCPTranslateError
918 ( OskitTCPSend( Connection
->SocketContext
,
919 (OSK_PCHAR
)BufferData
, SendLength
,
922 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
924 /* Keep this request around ... there was no data yet */
925 if( Status
== STATUS_PENDING
) {
926 /* Freed in TCPSocketState */
927 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
929 UnlockObject(Connection
, OldIrql
);
930 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
931 return STATUS_NO_MEMORY
;
934 Bucket
->Request
.RequestNotifyObject
= Complete
;
935 Bucket
->Request
.RequestContext
= Context
;
938 InsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
);
939 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
941 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
945 UnlockObject(Connection
, OldIrql
);
947 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
952 UINT
TCPAllocatePort( UINT HintPort
) {
954 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
957 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
960 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
963 VOID
TCPFreePort( UINT Port
) {
964 DeallocatePort( &TCPPorts
, Port
);
967 NTSTATUS TCPGetSockAddress
968 ( PCONNECTION_ENDPOINT Connection
,
969 PTRANSPORT_ADDRESS Address
,
970 BOOLEAN GetRemote
) {
971 OSK_UINT LocalAddress
, RemoteAddress
;
972 OSK_UI16 LocalPort
, RemotePort
;
973 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
977 LockObject(Connection
, &OldIrql
);
979 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
980 &LocalAddress
, &LocalPort
,
981 &RemoteAddress
, &RemotePort
));
983 UnlockObject(Connection
, OldIrql
);
985 if (!NT_SUCCESS(Status
))
988 AddressIP
->TAAddressCount
= 1;
989 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
990 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
991 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
992 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
997 BOOLEAN
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
999 PLIST_ENTRY ListHead
[5];
1003 BOOLEAN Found
= FALSE
;
1005 ListHead
[0] = &Endpoint
->SendRequest
;
1006 ListHead
[1] = &Endpoint
->ReceiveRequest
;
1007 ListHead
[2] = &Endpoint
->ConnectRequest
;
1008 ListHead
[3] = &Endpoint
->ListenRequest
;
1009 ListHead
[4] = &Endpoint
->ShutdownRequest
;
1011 LockObject(Endpoint
, &OldIrql
);
1013 for( i
= 0; i
< 5; i
++ )
1015 for( Entry
= ListHead
[i
]->Flink
;
1016 Entry
!= ListHead
[i
];
1017 Entry
= Entry
->Flink
)
1019 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
1020 if( Bucket
->Request
.RequestContext
== Irp
)
1022 RemoveEntryList( &Bucket
->Entry
);
1023 ExFreePoolWithTag( Bucket
, TDI_BUCKET_TAG
);
1030 UnlockObject(Endpoint
, OldIrql
);