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
;
21 VOID
HandleSignalledConnection(PCONNECTION_ENDPOINT Connection
)
28 ULONG SocketError
= 0;
30 PTCP_COMPLETION_ROUTINE Complete
;
32 if (ClientInfo
.Unlocked
)
33 LockObjectAtDpcLevel(Connection
);
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 /* If OskitTCP initiated the disconnect, try to read the socket error that occurred */
42 if (Connection
->SocketContext
)
43 SocketError
= TCPTranslateError(OskitTCPGetSocketError(Connection
->SocketContext
));
45 /* Default to STATUS_CANCELLED if we initiated the disconnect or no socket error was reported */
46 if (!Connection
->SocketContext
|| !SocketError
)
47 SocketError
= STATUS_CANCELLED
;
49 while (!IsListEmpty(&Connection
->ReceiveRequest
))
51 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
53 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
55 Bucket
->Status
= SocketError
;
56 Bucket
->Information
= 0;
58 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
61 while (!IsListEmpty(&Connection
->SendRequest
))
63 Entry
= RemoveHeadList( &Connection
->SendRequest
);
65 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
67 Bucket
->Status
= SocketError
;
68 Bucket
->Information
= 0;
70 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
73 while (!IsListEmpty(&Connection
->ListenRequest
))
75 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
77 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
79 Bucket
->Status
= SocketError
;
80 Bucket
->Information
= 0;
81 DereferenceObject(Bucket
->AssociatedEndpoint
);
83 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
86 while (!IsListEmpty(&Connection
->ConnectRequest
))
88 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
90 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
92 Bucket
->Status
= SocketError
;
93 Bucket
->Information
= 0;
95 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
98 Connection
->SignalState
= SEL_FIN
;
101 /* Things that can happen when we try the initial connection */
102 if( Connection
->SignalState
& SEL_CONNECT
) {
103 while (!IsListEmpty(&Connection
->ConnectRequest
)) {
104 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
106 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
108 Bucket
->Status
= STATUS_SUCCESS
;
109 Bucket
->Information
= 0;
111 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
115 if( Connection
->SignalState
& SEL_ACCEPT
) {
116 /* Handle readable on a listening socket --
117 * TODO: Implement filtering
119 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
121 IsListEmpty(&Connection
->ListenRequest
) ?
122 "empty" : "nonempty"));
124 while (!IsListEmpty(&Connection
->ListenRequest
)) {
125 PIO_STACK_LOCATION IrpSp
;
127 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
129 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
131 Irp
= Bucket
->Request
.RequestContext
;
132 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
134 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
136 Status
= TCPServiceListeningSocket
137 ( Connection
->AddressFile
->Listener
,
138 Bucket
->AssociatedEndpoint
,
139 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
141 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
143 if( Status
== STATUS_PENDING
) {
144 InsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
);
147 Bucket
->Status
= Status
;
148 Bucket
->Information
= 0;
149 DereferenceObject(Bucket
->AssociatedEndpoint
);
151 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
156 /* Things that happen after we're connected */
157 if( Connection
->SignalState
& SEL_READ
) {
158 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
159 IsListEmpty(&Connection
->ReceiveRequest
) ?
160 "empty" : "nonempty"));
162 while (!IsListEmpty(&Connection
->ReceiveRequest
)) {
163 OSK_UINT RecvLen
= 0, Received
= 0;
164 PVOID RecvBuffer
= 0;
166 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
168 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
170 Irp
= Bucket
->Request
.RequestContext
;
171 Mdl
= Irp
->MdlAddress
;
173 TI_DbgPrint(DEBUG_TCP
,
174 ("Getting the user buffer from %x\n", Mdl
));
176 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
178 TI_DbgPrint(DEBUG_TCP
,
179 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
181 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
184 ("Connection->SocketContext: %x\n",
185 Connection
->SocketContext
));
186 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
188 Status
= TCPTranslateError
189 ( OskitTCPRecv( Connection
->SocketContext
,
195 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
197 if( Status
== STATUS_PENDING
) {
198 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
201 TI_DbgPrint(DEBUG_TCP
,
202 ("Completing Receive request: %x %x\n",
203 Bucket
->Request
, Status
));
205 Bucket
->Status
= Status
;
206 Bucket
->Information
= (Status
== STATUS_SUCCESS
) ? Received
: 0;
208 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
212 if( Connection
->SignalState
& SEL_WRITE
) {
213 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
214 IsListEmpty(&Connection
->SendRequest
) ?
215 "empty" : "nonempty"));
217 while (!IsListEmpty(&Connection
->SendRequest
)) {
218 OSK_UINT SendLen
= 0, Sent
= 0;
219 PVOID SendBuffer
= 0;
221 Entry
= RemoveHeadList( &Connection
->SendRequest
);
223 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
225 Irp
= Bucket
->Request
.RequestContext
;
226 Mdl
= Irp
->MdlAddress
;
228 TI_DbgPrint(DEBUG_TCP
,
229 ("Getting the user buffer from %x\n", Mdl
));
231 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
233 TI_DbgPrint(DEBUG_TCP
,
234 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
236 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
239 ("Connection->SocketContext: %x\n",
240 Connection
->SocketContext
));
242 Status
= TCPTranslateError
243 ( OskitTCPSend( Connection
->SocketContext
,
249 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
251 if( Status
== STATUS_PENDING
) {
252 InsertHeadList( &Connection
->SendRequest
, &Bucket
->Entry
);
255 TI_DbgPrint(DEBUG_TCP
,
256 ("Completing Send request: %x %x\n",
257 Bucket
->Request
, Status
));
259 Bucket
->Status
= Status
;
260 Bucket
->Information
= (Status
== STATUS_SUCCESS
) ? Sent
: 0;
262 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
267 ReferenceObject(Connection
);
268 if (ClientInfo
.Unlocked
)
270 UnlockObjectFromDpcLevel(Connection
);
271 KeReleaseSpinLock(&ClientInfo
.Lock
, ClientInfo
.OldIrql
);
275 UnlockObject(Connection
, Connection
->OldIrql
);
278 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->CompletionQueue
,
281 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
282 Complete
= Bucket
->Request
.RequestNotifyObject
;
284 Complete(Bucket
->Request
.RequestContext
, Bucket
->Status
, Bucket
->Information
);
286 ExFreePoolWithTag(Bucket
, TDI_BUCKET_TAG
);
289 if (!ClientInfo
.Unlocked
)
291 LockObject(Connection
, &OldIrql
);
295 KeAcquireSpinLock(&ClientInfo
.Lock
, &ClientInfo
.OldIrql
);
297 DereferenceObject(Connection
);
299 /* If the socket is dead, remove the reference we added for oskit */
300 if (Connection
->SignalState
& SEL_FIN
)
301 DereferenceObject(Connection
);
304 VOID
ConnectionFree(PVOID Object
) {
305 PCONNECTION_ENDPOINT Connection
= Object
;
308 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
310 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
311 RemoveEntryList(&Connection
->ListEntry
);
312 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
314 ExFreePoolWithTag( Connection
, CONN_ENDPT_TAG
);
317 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
318 PCONNECTION_ENDPOINT Connection
=
319 ExAllocatePoolWithTag(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
),
324 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
326 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
328 /* Initialize spin lock that protects the connection endpoint file object */
329 KeInitializeSpinLock(&Connection
->Lock
);
330 InitializeListHead(&Connection
->ConnectRequest
);
331 InitializeListHead(&Connection
->ListenRequest
);
332 InitializeListHead(&Connection
->ReceiveRequest
);
333 InitializeListHead(&Connection
->SendRequest
);
334 InitializeListHead(&Connection
->CompletionQueue
);
336 /* Save client context pointer */
337 Connection
->ClientContext
= ClientContext
;
339 /* Add an extra reference for oskit */
340 Connection
->RefCount
= 2;
341 Connection
->Free
= ConnectionFree
;
343 /* Add connection endpoint to global list */
344 ExInterlockedInsertTailList(&ConnectionEndpointListHead
,
345 &Connection
->ListEntry
,
346 &ConnectionEndpointListLock
);
351 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
352 UINT Family
, UINT Type
, UINT Proto
) {
356 LockObject(Connection
, &OldIrql
);
358 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
360 Connection
, Family
, Type
, Proto
));
362 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
363 &Connection
->SocketContext
,
368 ASSERT_KM_POINTER(Connection
->SocketContext
);
370 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
371 Connection
->SocketContext
));
373 UnlockObject(Connection
, OldIrql
);
378 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
380 * FUNCTION: Receives and queues TCP data
382 * IPPacket = Pointer to an IP packet that was received
384 * This is the low level interface for receiving TCP data
389 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
391 IPPacket
->HeaderSize
));
393 KeAcquireSpinLock(&ClientInfo
.Lock
, &OldIrql
);
394 ClientInfo
.Unlocked
= TRUE
;
395 ClientInfo
.OldIrql
= OldIrql
;
397 OskitTCPReceiveDatagram( IPPacket
->Header
,
399 IPPacket
->HeaderSize
);
401 ClientInfo
.Unlocked
= FALSE
;
402 KeReleaseSpinLock(&ClientInfo
.Lock
, OldIrql
);
406 int TCPSocketState( void *ClientData
,
408 void *WhichConnection
,
411 int TCPPacketSend( void *ClientData
,
415 POSK_IFADDR
TCPFindInterface( void *ClientData
,
418 OSK_SOCKADDR
*ReqAddr
);
420 NTSTATUS
TCPMemStartup( void );
421 void *TCPMalloc( void *ClientData
,
422 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
423 void TCPFree( void *ClientData
,
424 void *data
, OSK_PCHAR file
, OSK_UINT line
);
425 void TCPMemShutdown( void );
427 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
428 NULL
, /* Client Data */
429 TCPSocketState
, /* SocketState */
430 TCPPacketSend
, /* PacketSend */
431 TCPFindInterface
, /* FindInterface */
432 TCPMalloc
, /* Malloc */
438 static KEVENT TimerLoopEvent
;
439 static HANDLE TimerThreadHandle
;
442 * We are running 2 timers here, one with a 200ms interval (fast) and the other
443 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
444 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
445 * "slow" events at 500 and 1000.
448 TimerThread(PVOID Context
)
450 LARGE_INTEGER Timeout
;
452 unsigned Current
, NextFast
, NextSlow
, Next
;
459 if (Next
== NextFast
) {
462 if (Next
== NextSlow
) {
465 Next
= min(NextFast
, NextSlow
);
466 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
467 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
469 if (Status
!= STATUS_TIMEOUT
) {
470 PsTerminateSystemThread(Status
);
473 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
488 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
489 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
493 NTSTATUS
TCPStartup(VOID
)
495 * FUNCTION: Initializes the TCP subsystem
497 * Status of operation
502 Status
= TCPMemStartup();
503 if ( ! NT_SUCCESS(Status
) ) {
507 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
508 if( !NT_SUCCESS(Status
) ) {
513 KeInitializeSpinLock(&ClientInfo
.Lock
);
514 ClientInfo
.Unlocked
= FALSE
;
516 RegisterOskitTCPEventHandlers( &EventHandlers
);
519 /* Register this protocol with IP layer */
520 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
522 ExInitializeNPagedLookasideList(
523 &TCPSegmentList
, /* Lookaside list */
524 NULL
, /* Allocate routine */
525 NULL
, /* Free routine */
527 sizeof(TCP_SEGMENT
), /* Size of each entry */
533 TCPInitialized
= TRUE
;
535 return STATUS_SUCCESS
;
539 NTSTATUS
TCPShutdown(VOID
)
541 * FUNCTION: Shuts down the TCP subsystem
543 * Status of operation
546 LARGE_INTEGER WaitForThread
;
549 return STATUS_SUCCESS
;
551 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
552 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
553 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
555 /* Deregister this protocol with IP layer */
556 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
558 ExDeleteNPagedLookasideList(&TCPSegmentList
);
560 TCPInitialized
= FALSE
;
564 PortsShutdown( &TCPPorts
);
568 return STATUS_SUCCESS
;
571 NTSTATUS
TCPTranslateError( int OskitError
) {
574 switch( OskitError
) {
575 case 0: Status
= STATUS_SUCCESS
; break;
576 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
577 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
578 case OSK_ECONNREFUSED
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
580 case OSK_ECONNABORTED
: Status
= STATUS_REMOTE_DISCONNECT
; break;
581 case OSK_EWOULDBLOCK
:
582 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
583 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
585 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
586 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
587 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
588 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
589 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
590 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
592 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
593 Status
= STATUS_INVALID_CONNECTION
;
597 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
602 ( PCONNECTION_ENDPOINT Connection
,
603 PTDI_CONNECTION_INFORMATION ConnInfo
,
604 PTDI_CONNECTION_INFORMATION ReturnInfo
,
605 PTCP_COMPLETION_ROUTINE Complete
,
608 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
609 IP_ADDRESS RemoteAddress
;
612 PNEIGHBOR_CACHE_ENTRY NCE
;
615 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
617 Status
= AddrBuildAddress
618 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
622 if (!NT_SUCCESS(Status
)) {
623 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
627 /* Freed in TCPSocketState */
628 TI_DbgPrint(DEBUG_TCP
,
629 ("Connecting to address %x:%x\n",
630 RemoteAddress
.Address
.IPv4Address
,
633 AddressToConnect
.sin_family
= AF_INET
;
634 AddressToBind
= AddressToConnect
;
636 LockObject(Connection
, &OldIrql
);
638 if (!Connection
->AddressFile
)
640 UnlockObject(Connection
, OldIrql
);
641 return STATUS_INVALID_PARAMETER
;
644 if (AddrIsUnspecified(&Connection
->AddressFile
->Address
))
646 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
648 UnlockObject(Connection
, OldIrql
);
649 return STATUS_NETWORK_UNREACHABLE
;
652 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
656 AddressToBind
.sin_addr
.s_addr
= Connection
->AddressFile
->Address
.Address
.IPv4Address
;
659 Status
= TCPTranslateError
660 ( OskitTCPBind( Connection
->SocketContext
,
662 sizeof(AddressToBind
) ) );
664 if (NT_SUCCESS(Status
)) {
665 memcpy( &AddressToConnect
.sin_addr
,
666 &RemoteAddress
.Address
.IPv4Address
,
667 sizeof(AddressToConnect
.sin_addr
) );
668 AddressToConnect
.sin_port
= RemotePort
;
670 Status
= TCPTranslateError
671 ( OskitTCPConnect( Connection
->SocketContext
,
673 sizeof(AddressToConnect
) ) );
675 if (Status
== STATUS_PENDING
)
677 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
680 UnlockObject(Connection
, OldIrql
);
681 return STATUS_NO_MEMORY
;
684 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
685 Bucket
->Request
.RequestContext
= Context
;
687 InsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
691 UnlockObject(Connection
, OldIrql
);
696 NTSTATUS TCPDisconnect
697 ( PCONNECTION_ENDPOINT Connection
,
699 PTDI_CONNECTION_INFORMATION ConnInfo
,
700 PTDI_CONNECTION_INFORMATION ReturnInfo
,
701 PTCP_COMPLETION_ROUTINE Complete
,
703 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
706 TI_DbgPrint(DEBUG_TCP
,("started\n"));
708 LockObject(Connection
, &OldIrql
);
710 if (Flags
& TDI_DISCONNECT_RELEASE
)
711 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
713 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
714 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
716 UnlockObject(Connection
, OldIrql
);
718 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
724 ( PCONNECTION_ENDPOINT Connection
)
730 /* We don't rely on SocketContext == NULL for socket
731 * closure anymore but we still need it to determine
732 * if we caused the closure
734 LockObject(Connection
, &OldIrql
);
735 Socket
= Connection
->SocketContext
;
736 Connection
->SocketContext
= NULL
;
738 /* We need to close here otherwise oskit will never indicate
739 * SEL_FIN and we will never fully close the connection
741 Status
= TCPTranslateError( OskitTCPClose( Socket
) );
743 if (!NT_SUCCESS(Status
))
745 Connection
->SocketContext
= Socket
;
746 UnlockObject(Connection
, OldIrql
);
750 if (Connection
->AddressFile
)
751 DereferenceObject(Connection
->AddressFile
);
753 UnlockObject(Connection
, OldIrql
);
755 DereferenceObject(Connection
);
760 NTSTATUS TCPReceiveData
761 ( PCONNECTION_ENDPOINT Connection
,
764 PULONG BytesReceived
,
766 PTCP_COMPLETION_ROUTINE Complete
,
769 UINT DataLen
, Received
= 0;
774 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
775 ReceiveLength
, Connection
->SocketContext
));
777 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
779 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
781 LockObject(Connection
, &OldIrql
);
783 Status
= TCPTranslateError
785 ( Connection
->SocketContext
,
791 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
793 /* Keep this request around ... there was no data yet */
794 if( Status
== STATUS_PENDING
) {
795 /* Freed in TCPSocketState */
796 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
798 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
799 UnlockObject(Connection
, OldIrql
);
800 return STATUS_NO_MEMORY
;
803 Bucket
->Request
.RequestNotifyObject
= Complete
;
804 Bucket
->Request
.RequestContext
= Context
;
807 InsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
808 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
810 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
811 *BytesReceived
= Received
;
814 UnlockObject(Connection
, OldIrql
);
816 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
822 ( PCONNECTION_ENDPOINT Connection
,
827 PTCP_COMPLETION_ROUTINE Complete
,
834 LockObject(Connection
, &OldIrql
);
836 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
837 SendLength
, Connection
->SocketContext
));
839 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
840 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
841 Connection
->SocketContext
));
843 Status
= TCPTranslateError
844 ( OskitTCPSend( Connection
->SocketContext
,
845 (OSK_PCHAR
)BufferData
, SendLength
,
848 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
850 /* Keep this request around ... there was no data yet */
851 if( Status
== STATUS_PENDING
) {
852 /* Freed in TCPSocketState */
853 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
855 UnlockObject(Connection
, OldIrql
);
856 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
857 return STATUS_NO_MEMORY
;
860 Bucket
->Request
.RequestNotifyObject
= Complete
;
861 Bucket
->Request
.RequestContext
= Context
;
864 InsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
);
865 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
867 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
871 UnlockObject(Connection
, OldIrql
);
873 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
878 UINT
TCPAllocatePort( UINT HintPort
) {
880 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
883 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
886 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
889 VOID
TCPFreePort( UINT Port
) {
890 DeallocatePort( &TCPPorts
, Port
);
893 NTSTATUS TCPGetSockAddress
894 ( PCONNECTION_ENDPOINT Connection
,
895 PTRANSPORT_ADDRESS Address
,
896 BOOLEAN GetRemote
) {
897 OSK_UINT LocalAddress
, RemoteAddress
;
898 OSK_UI16 LocalPort
, RemotePort
;
899 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
903 LockObject(Connection
, &OldIrql
);
905 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
906 &LocalAddress
, &LocalPort
,
907 &RemoteAddress
, &RemotePort
));
909 UnlockObject(Connection
, OldIrql
);
911 if (!NT_SUCCESS(Status
))
914 AddressIP
->TAAddressCount
= 1;
915 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
916 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
917 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
918 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
923 BOOLEAN
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
925 PLIST_ENTRY ListHead
[4];
929 BOOLEAN Found
= FALSE
;
931 ListHead
[0] = &Endpoint
->SendRequest
;
932 ListHead
[1] = &Endpoint
->ReceiveRequest
;
933 ListHead
[2] = &Endpoint
->ConnectRequest
;
934 ListHead
[3] = &Endpoint
->ListenRequest
;
936 LockObject(Endpoint
, &OldIrql
);
938 for( i
= 0; i
< 4; i
++ )
940 for( Entry
= ListHead
[i
]->Flink
;
941 Entry
!= ListHead
[i
];
942 Entry
= Entry
->Flink
)
944 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
945 if( Bucket
->Request
.RequestContext
== Irp
)
947 RemoveEntryList( &Bucket
->Entry
);
948 ExFreePoolWithTag( Bucket
, TDI_BUCKET_TAG
);
955 UnlockObject(Endpoint
, OldIrql
);