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 ULONG
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 Connection
->SignalState
&= ~SEL_READ
;
42 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
43 &Connection
->Lock
)) != NULL
)
45 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
46 Complete
= Bucket
->Request
.RequestNotifyObject
;
48 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
53 Connection
->SignalState
&= ~SEL_WRITE
;
54 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
55 &Connection
->Lock
)) != NULL
)
57 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
58 Complete
= Bucket
->Request
.RequestNotifyObject
;
60 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
65 Connection
->SignalState
&= ~SEL_ACCEPT
;
66 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
67 &Connection
->Lock
)) != NULL
)
69 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
70 Complete
= Bucket
->Request
.RequestNotifyObject
;
72 /* We have to notify oskittcp of the abortion */
73 TCPAbortListenForSocket(Connection
->AddressFile
->Listener
,
76 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
81 Connection
->SignalState
&= ~SEL_CONNECT
;
82 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
83 &Connection
->Lock
)) != NULL
)
85 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
86 Complete
= Bucket
->Request
.RequestNotifyObject
;
88 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
94 /* Things that can happen when we try the initial connection */
95 if( Connection
->SignalState
& SEL_CONNECT
) {
96 Connection
->SignalState
&= ~SEL_CONNECT
;
97 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
98 &Connection
->Lock
)) != NULL
) {
100 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
102 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
103 Complete
= Bucket
->Request
.RequestNotifyObject
;
104 TI_DbgPrint(DEBUG_TCP
,
105 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
107 Complete( Bucket
->Request
.RequestContext
, STATUS_SUCCESS
, 0 );
109 /* Frees the bucket allocated in TCPConnect */
110 exFreePool( Bucket
);
114 if( Connection
->SignalState
& SEL_ACCEPT
) {
115 /* Handle readable on a listening socket --
116 * TODO: Implement filtering
119 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
121 IsListEmpty(&Connection
->ListenRequest
) ?
122 "empty" : "nonempty"));
124 Connection
->SignalState
&= ~SEL_ACCEPT
;
125 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
126 &Connection
->Lock
)) != NULL
) {
127 PIO_STACK_LOCATION IrpSp
;
129 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
130 Complete
= Bucket
->Request
.RequestNotifyObject
;
132 Irp
= Bucket
->Request
.RequestContext
;
133 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
135 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 Connection
->SignalState
|= SEL_ACCEPT
;
145 ExInterlockedInsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
, &Connection
->Lock
);
148 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
149 exFreePool( Bucket
);
154 /* Things that happen after we're connected */
155 if( Connection
->SignalState
& SEL_READ
) {
156 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
157 IsListEmpty(&Connection
->ReceiveRequest
) ?
158 "empty" : "nonempty"));
160 Connection
->SignalState
&= ~SEL_READ
;
161 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
162 &Connection
->Lock
)) != NULL
) {
163 OSK_UINT RecvLen
= 0, Received
= 0;
164 PVOID RecvBuffer
= 0;
166 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
167 Complete
= Bucket
->Request
.RequestNotifyObject
;
169 Irp
= Bucket
->Request
.RequestContext
;
170 Mdl
= Irp
->MdlAddress
;
172 TI_DbgPrint(DEBUG_TCP
,
173 ("Getting the user buffer from %x\n", Mdl
));
175 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
177 TI_DbgPrint(DEBUG_TCP
,
178 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
180 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
183 ("Connection->SocketContext: %x\n",
184 Connection
->SocketContext
));
185 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
187 Status
= TCPTranslateError
188 ( OskitTCPRecv( Connection
->SocketContext
,
194 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
196 if( Status
== STATUS_SUCCESS
) {
197 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
200 Complete( Bucket
->Request
.RequestContext
,
201 STATUS_SUCCESS
, Received
);
202 exFreePool( Bucket
);
203 } else if( Status
== STATUS_PENDING
) {
204 ExInterlockedInsertHeadList
205 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
206 Connection
->SignalState
|= SEL_READ
;
209 TI_DbgPrint(DEBUG_TCP
,
210 ("Completing Receive request: %x %x\n",
211 Bucket
->Request
, Status
));
212 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
213 exFreePool( Bucket
);
217 if( Connection
->SignalState
& SEL_WRITE
) {
218 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
219 IsListEmpty(&Connection
->SendRequest
) ?
220 "empty" : "nonempty"));
222 Connection
->SignalState
&= ~SEL_WRITE
;
223 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
224 &Connection
->Lock
)) != NULL
) {
225 OSK_UINT SendLen
= 0, Sent
= 0;
226 PVOID SendBuffer
= 0;
228 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
229 Complete
= Bucket
->Request
.RequestNotifyObject
;
231 Irp
= Bucket
->Request
.RequestContext
;
232 Mdl
= Irp
->MdlAddress
;
234 TI_DbgPrint(DEBUG_TCP
,
235 ("Getting the user buffer from %x\n", Mdl
));
237 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
239 TI_DbgPrint(DEBUG_TCP
,
240 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
242 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
245 ("Connection->SocketContext: %x\n",
246 Connection
->SocketContext
));
248 Status
= TCPTranslateError
249 ( OskitTCPSend( Connection
->SocketContext
,
255 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
257 if( Status
== STATUS_SUCCESS
) {
258 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
261 Complete( Bucket
->Request
.RequestContext
,
262 STATUS_SUCCESS
, Sent
);
263 exFreePool( Bucket
);
264 } else if( Status
== STATUS_PENDING
) {
265 ExInterlockedInsertHeadList
266 ( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
267 Connection
->SignalState
|= SEL_WRITE
;
270 TI_DbgPrint(DEBUG_TCP
,
271 ("Completing Send request: %x %x\n",
272 Bucket
->Request
, Status
));
273 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
274 exFreePool( Bucket
);
279 return Connection
->SignalState
;
282 static VOID
DrainSignals() {
283 PCONNECTION_ENDPOINT Connection
;
284 PLIST_ENTRY CurrentEntry
, NextEntry
;
288 KeAcquireSpinLock(&SignalledConnectionsLock
, &OldIrql
);
289 CurrentEntry
= SignalledConnectionsList
.Flink
;
290 while (CurrentEntry
!= &SignalledConnectionsList
)
292 NextEntry
= CurrentEntry
->Flink
;
293 Connection
= CONTAINING_RECORD( CurrentEntry
, CONNECTION_ENDPOINT
,
296 KeReleaseSpinLock(&SignalledConnectionsLock
, OldIrql
);
297 NewState
= HandleSignalledConnection(Connection
);
298 KeAcquireSpinLock(&SignalledConnectionsLock
, &OldIrql
);
300 if (NewState
== SEL_FIN
|| NewState
== 0)
302 RemoveEntryList(CurrentEntry
);
305 CurrentEntry
= NextEntry
;
307 KeReleaseSpinLock(&SignalledConnectionsLock
, OldIrql
);
310 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
311 PCONNECTION_ENDPOINT Connection
=
312 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
316 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
318 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
320 /* Initialize spin lock that protects the connection endpoint file object */
321 TcpipInitializeSpinLock(&Connection
->Lock
);
322 InitializeListHead(&Connection
->ConnectRequest
);
323 InitializeListHead(&Connection
->ListenRequest
);
324 InitializeListHead(&Connection
->ReceiveRequest
);
325 InitializeListHead(&Connection
->SendRequest
);
327 /* Save client context pointer */
328 Connection
->ClientContext
= ClientContext
;
333 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
334 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
335 exFreePool( Connection
);
338 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
339 UINT Family
, UINT Type
, UINT Proto
) {
342 ASSERT_LOCKED(&TCPLock
);
344 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
346 Connection
, Family
, Type
, Proto
));
348 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
349 &Connection
->SocketContext
,
354 ASSERT_KM_POINTER(Connection
->SocketContext
);
356 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
357 Connection
->SocketContext
));
362 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
364 * FUNCTION: Receives and queues TCP data
366 * IPPacket = Pointer to an IP packet that was received
368 * This is the low level interface for receiving TCP data
371 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
373 IPPacket
->HeaderSize
));
375 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
377 OskitTCPReceiveDatagram( IPPacket
->Header
,
379 IPPacket
->HeaderSize
);
381 TcpipRecursiveMutexLeave( &TCPLock
);
385 int TCPSocketState( void *ClientData
,
387 void *WhichConnection
,
390 int TCPPacketSend( void *ClientData
,
394 POSK_IFADDR
TCPFindInterface( void *ClientData
,
397 OSK_SOCKADDR
*ReqAddr
);
399 NTSTATUS
TCPMemStartup( void );
400 void *TCPMalloc( void *ClientData
,
401 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
402 void TCPFree( void *ClientData
,
403 void *data
, OSK_PCHAR file
, OSK_UINT line
);
404 void TCPMemShutdown( void );
406 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
409 void TCPWakeup( void *ClientData
, void *token
);
411 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
412 NULL
, /* Client Data */
413 TCPSocketState
, /* SocketState */
414 TCPPacketSend
, /* PacketSend */
415 TCPFindInterface
, /* FindInterface */
416 TCPMalloc
, /* Malloc */
418 TCPSleep
, /* Sleep */
419 TCPWakeup
/* Wakeup */
422 static KEVENT TimerLoopEvent
;
423 static HANDLE TimerThreadHandle
;
426 * We are running 2 timers here, one with a 200ms interval (fast) and the other
427 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
428 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
429 * "slow" events at 500 and 1000.
432 TimerThread(PVOID Context
)
434 LARGE_INTEGER Timeout
;
436 unsigned Current
, NextFast
, NextSlow
, Next
;
443 if (Next
== NextFast
) {
446 if (Next
== NextSlow
) {
449 Next
= min(NextFast
, NextSlow
);
450 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
451 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
453 if (Status
!= STATUS_TIMEOUT
) {
454 PsTerminateSystemThread(Status
);
457 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
458 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
459 if (Next
== NextSlow
) {
462 TcpipRecursiveMutexLeave( &TCPLock
);
477 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
478 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
483 NTSTATUS
TCPStartup(VOID
)
485 * FUNCTION: Initializes the TCP subsystem
487 * Status of operation
492 TcpipRecursiveMutexInit( &TCPLock
);
493 ExInitializeFastMutex( &SleepingThreadsLock
);
494 KeInitializeSpinLock( &SignalledConnectionsLock
);
495 InitializeListHead( &SleepingThreadsList
);
496 InitializeListHead( &SignalledConnectionsList
);
497 Status
= TCPMemStartup();
498 if ( ! NT_SUCCESS(Status
) ) {
502 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
503 if( !NT_SUCCESS(Status
) ) {
508 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
509 RegisterOskitTCPEventHandlers( &EventHandlers
);
511 TcpipRecursiveMutexLeave(&TCPLock
);
513 /* Register this protocol with IP layer */
514 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
516 ExInitializeNPagedLookasideList(
517 &TCPSegmentList
, /* Lookaside list */
518 NULL
, /* Allocate routine */
519 NULL
, /* Free routine */
521 sizeof(TCP_SEGMENT
), /* Size of each entry */
527 TCPInitialized
= TRUE
;
529 return STATUS_SUCCESS
;
533 NTSTATUS
TCPShutdown(VOID
)
535 * FUNCTION: Shuts down the TCP subsystem
537 * Status of operation
540 LARGE_INTEGER WaitForThread
;
543 return STATUS_SUCCESS
;
545 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
546 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
547 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
549 /* Deregister this protocol with IP layer */
550 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
552 ExDeleteNPagedLookasideList(&TCPSegmentList
);
554 TCPInitialized
= FALSE
;
558 PortsShutdown( &TCPPorts
);
562 return STATUS_SUCCESS
;
565 NTSTATUS
TCPTranslateError( int OskitError
) {
568 switch( OskitError
) {
569 case 0: Status
= STATUS_SUCCESS
; break;
570 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
571 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
572 case OSK_ECONNREFUSED
:
573 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
574 case OSK_EWOULDBLOCK
:
575 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
576 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
578 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
579 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
580 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
581 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
582 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
583 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
585 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
586 Status
= STATUS_INVALID_CONNECTION
;
590 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
595 ( PCONNECTION_ENDPOINT Connection
,
596 PTDI_CONNECTION_INFORMATION ConnInfo
,
597 PTDI_CONNECTION_INFORMATION ReturnInfo
,
598 PTCP_COMPLETION_ROUTINE Complete
,
601 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
602 IP_ADDRESS RemoteAddress
;
605 PNEIGHBOR_CACHE_ENTRY NCE
;
607 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
609 ASSERT_LOCKED(&TCPLock
);
611 Status
= AddrBuildAddress
612 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
616 if (!NT_SUCCESS(Status
)) {
617 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
621 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
623 return STATUS_NETWORK_UNREACHABLE
;
626 /* Freed in TCPSocketState */
627 TI_DbgPrint(DEBUG_TCP
,
628 ("Connecting to address %x:%x\n",
629 RemoteAddress
.Address
.IPv4Address
,
632 AddressToConnect
.sin_family
= AF_INET
;
633 AddressToBind
= AddressToConnect
;
634 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
636 Status
= TCPTranslateError
637 ( OskitTCPBind( Connection
->SocketContext
,
639 sizeof(AddressToBind
) ) );
641 if (NT_SUCCESS(Status
)) {
642 memcpy( &AddressToConnect
.sin_addr
,
643 &RemoteAddress
.Address
.IPv4Address
,
644 sizeof(AddressToConnect
.sin_addr
) );
645 AddressToConnect
.sin_port
= RemotePort
;
647 Status
= TCPTranslateError
648 ( OskitTCPConnect( Connection
->SocketContext
,
651 sizeof(AddressToConnect
) ) );
653 if (Status
== STATUS_PENDING
)
655 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
656 if( !Bucket
) return STATUS_NO_MEMORY
;
658 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
659 Bucket
->Request
.RequestContext
= Context
;
661 IoMarkIrpPending((PIRP
)Context
);
663 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
, &Connection
->Lock
);
670 NTSTATUS TCPDisconnect
671 ( PCONNECTION_ENDPOINT Connection
,
673 PTDI_CONNECTION_INFORMATION ConnInfo
,
674 PTDI_CONNECTION_INFORMATION ReturnInfo
,
675 PTCP_COMPLETION_ROUTINE Complete
,
677 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
679 ASSERT_LOCKED(&TCPLock
);
681 TI_DbgPrint(DEBUG_TCP
,("started\n"));
683 if (Flags
& TDI_DISCONNECT_RELEASE
)
684 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
686 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
687 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
689 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
695 ( PCONNECTION_ENDPOINT Connection
) {
698 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
700 ASSERT_LOCKED(&TCPLock
);
702 /* Make our code remove all pending IRPs */
703 Connection
->SignalState
|= SEL_FIN
;
704 HandleSignalledConnection(Connection
);
706 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
707 if (Status
== STATUS_SUCCESS
)
708 Connection
->SocketContext
= NULL
;
710 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
715 NTSTATUS TCPReceiveData
716 ( PCONNECTION_ENDPOINT Connection
,
719 PULONG BytesReceived
,
721 PTCP_COMPLETION_ROUTINE Complete
,
724 UINT DataLen
, Received
= 0;
728 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
729 ReceiveLength
, Connection
->SocketContext
));
731 ASSERT_LOCKED(&TCPLock
);
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 Status
= TCPTranslateError
741 ( Connection
->SocketContext
,
747 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
749 /* Keep this request around ... there was no data yet */
750 if( Status
== STATUS_PENDING
) {
751 /* Freed in TCPSocketState */
752 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
754 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
755 return STATUS_NO_MEMORY
;
758 Bucket
->Request
.RequestNotifyObject
= Complete
;
759 Bucket
->Request
.RequestContext
= Context
;
762 IoMarkIrpPending((PIRP
)Context
);
764 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
765 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
767 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
768 *BytesReceived
= Received
;
771 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
777 ( PCONNECTION_ENDPOINT Connection
,
782 PTCP_COMPLETION_ROUTINE Complete
,
788 ASSERT_LOCKED(&TCPLock
);
790 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
791 SendLength
, Connection
->SocketContext
));
793 ASSERT_KM_POINTER(Connection
->SocketContext
);
795 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
796 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
797 Connection
->SocketContext
));
800 Status
= TCPTranslateError
801 ( OskitTCPSend( Connection
->SocketContext
,
802 (OSK_PCHAR
)BufferData
, SendLength
,
805 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
807 /* Keep this request around ... there was no data yet */
808 if( Status
== STATUS_PENDING
) {
809 /* Freed in TCPSocketState */
810 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
812 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
813 return STATUS_NO_MEMORY
;
816 Bucket
->Request
.RequestNotifyObject
= Complete
;
817 Bucket
->Request
.RequestContext
= Context
;
820 IoMarkIrpPending((PIRP
)Context
);
822 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
823 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
825 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
829 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
834 VOID
TCPTimeout(VOID
) {
835 /* Now handled by TimerThread */
838 UINT
TCPAllocatePort( UINT HintPort
) {
840 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
843 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
846 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
849 VOID
TCPFreePort( UINT Port
) {
850 DeallocatePort( &TCPPorts
, Port
);
853 NTSTATUS TCPGetSockAddress
854 ( PCONNECTION_ENDPOINT Connection
,
855 PTRANSPORT_ADDRESS Address
,
856 BOOLEAN GetRemote
) {
857 OSK_UINT LocalAddress
, RemoteAddress
;
858 OSK_UI16 LocalPort
, RemotePort
;
859 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
862 ASSERT_LOCKED(&TCPLock
);
864 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
865 &LocalAddress
, &LocalPort
,
866 &RemoteAddress
, &RemotePort
));
867 if (!NT_SUCCESS(Status
))
870 AddressIP
->TAAddressCount
= 1;
871 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
872 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
873 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
874 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
879 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
881 PLIST_ENTRY ListHead
[4];
886 ListHead
[0] = &Endpoint
->SendRequest
;
887 ListHead
[1] = &Endpoint
->ReceiveRequest
;
888 ListHead
[2] = &Endpoint
->ConnectRequest
;
889 ListHead
[3] = &Endpoint
->ListenRequest
;
891 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
893 for( i
= 0; i
< 4; i
++ )
895 for( Entry
= ListHead
[i
]->Flink
;
896 Entry
!= ListHead
[i
];
897 Entry
= Entry
->Flink
)
899 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
900 if( Bucket
->Request
.RequestContext
== Irp
)
902 RemoveEntryList( &Bucket
->Entry
);
903 exFreePool( Bucket
);
909 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);