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 ProcessCompletions(PCONNECTION_ENDPOINT Connection
)
24 PLIST_ENTRY CurrentEntry
;
26 PTCP_COMPLETION_ROUTINE Complete
;
28 while ((CurrentEntry
= ExInterlockedRemoveHeadList(&Connection
->CompletionQueue
,
31 Bucket
= CONTAINING_RECORD(CurrentEntry
, TDI_BUCKET
, Entry
);
32 Complete
= Bucket
->Request
.RequestNotifyObject
;
34 Complete(Bucket
->Request
.RequestContext
, Bucket
->Status
, Bucket
->Information
);
36 ExFreePoolWithTag(Bucket
, TDI_BUCKET_TAG
);
39 if (!Connection
->SocketContext
)
40 TCPFreeConnectionEndpoint(Connection
);
43 VOID
HandleSignalledConnection(PCONNECTION_ENDPOINT Connection
)
52 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
53 Connection
, Connection
->SocketContext
));
55 if( !Connection
->SocketContext
|| Connection
->SignalState
& SEL_FIN
) {
56 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
58 /* If OskitTCP initiated the disconnect, try to read the socket error that occurred */
59 if (Connection
->SocketContext
)
60 SocketError
= TCPTranslateError(OskitTCPGetSocketError(Connection
->SocketContext
));
62 /* Default to STATUS_CANCELLED if we initiated the disconnect or no socket error was reported */
63 if (!Connection
->SocketContext
|| !SocketError
)
64 SocketError
= STATUS_CANCELLED
;
66 while (!IsListEmpty(&Connection
->ReceiveRequest
))
68 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
70 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
72 Bucket
->Status
= SocketError
;
73 Bucket
->Information
= 0;
75 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
78 while (!IsListEmpty(&Connection
->SendRequest
))
80 Entry
= RemoveHeadList( &Connection
->SendRequest
);
82 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
84 Bucket
->Status
= SocketError
;
85 Bucket
->Information
= 0;
87 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
90 while (!IsListEmpty(&Connection
->ListenRequest
))
92 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
94 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
96 Bucket
->Status
= SocketError
;
97 Bucket
->Information
= 0;
99 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
102 while (!IsListEmpty(&Connection
->ConnectRequest
))
104 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
106 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
108 Bucket
->Status
= SocketError
;
109 Bucket
->Information
= 0;
111 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
114 Connection
->SignalState
= 0;
117 /* Things that can happen when we try the initial connection */
118 if( Connection
->SignalState
& SEL_CONNECT
) {
119 while (!IsListEmpty(&Connection
->ConnectRequest
)) {
120 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
122 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
124 Bucket
->Status
= STATUS_SUCCESS
;
125 Bucket
->Information
= 0;
127 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
131 if( Connection
->SignalState
& SEL_ACCEPT
) {
132 /* Handle readable on a listening socket --
133 * TODO: Implement filtering
135 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
137 IsListEmpty(&Connection
->ListenRequest
) ?
138 "empty" : "nonempty"));
140 while (!IsListEmpty(&Connection
->ListenRequest
)) {
141 PIO_STACK_LOCATION IrpSp
;
143 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
145 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
147 Irp
= Bucket
->Request
.RequestContext
;
148 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
150 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
152 Status
= TCPServiceListeningSocket
153 ( Connection
->AddressFile
->Listener
,
154 Bucket
->AssociatedEndpoint
,
155 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
157 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
159 if( Status
== STATUS_PENDING
) {
160 InsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
);
163 Bucket
->Status
= Status
;
164 Bucket
->Information
= 0;
166 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
171 /* Things that happen after we're connected */
172 if( Connection
->SignalState
& SEL_READ
) {
173 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
174 IsListEmpty(&Connection
->ReceiveRequest
) ?
175 "empty" : "nonempty"));
177 while (!IsListEmpty(&Connection
->ReceiveRequest
)) {
178 OSK_UINT RecvLen
= 0, Received
= 0;
179 PVOID RecvBuffer
= 0;
181 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
183 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
185 Irp
= Bucket
->Request
.RequestContext
;
186 Mdl
= Irp
->MdlAddress
;
188 TI_DbgPrint(DEBUG_TCP
,
189 ("Getting the user buffer from %x\n", Mdl
));
191 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
193 TI_DbgPrint(DEBUG_TCP
,
194 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
196 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
199 ("Connection->SocketContext: %x\n",
200 Connection
->SocketContext
));
201 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
203 Status
= TCPTranslateError
204 ( OskitTCPRecv( Connection
->SocketContext
,
210 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
212 if( Status
== STATUS_PENDING
) {
213 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
216 TI_DbgPrint(DEBUG_TCP
,
217 ("Completing Receive request: %x %x\n",
218 Bucket
->Request
, Status
));
220 Bucket
->Status
= Status
;
221 Bucket
->Information
= (Status
== STATUS_SUCCESS
) ? Received
: 0;
223 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
227 if( Connection
->SignalState
& SEL_WRITE
) {
228 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
229 IsListEmpty(&Connection
->SendRequest
) ?
230 "empty" : "nonempty"));
232 while (!IsListEmpty(&Connection
->SendRequest
)) {
233 OSK_UINT SendLen
= 0, Sent
= 0;
234 PVOID SendBuffer
= 0;
236 Entry
= RemoveHeadList( &Connection
->SendRequest
);
238 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
240 Irp
= Bucket
->Request
.RequestContext
;
241 Mdl
= Irp
->MdlAddress
;
243 TI_DbgPrint(DEBUG_TCP
,
244 ("Getting the user buffer from %x\n", Mdl
));
246 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
248 TI_DbgPrint(DEBUG_TCP
,
249 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
251 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
254 ("Connection->SocketContext: %x\n",
255 Connection
->SocketContext
));
257 Status
= TCPTranslateError
258 ( OskitTCPSend( Connection
->SocketContext
,
264 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
266 if( Status
== STATUS_PENDING
) {
267 InsertHeadList( &Connection
->SendRequest
, &Bucket
->Entry
);
270 TI_DbgPrint(DEBUG_TCP
,
271 ("Completing Send request: %x %x\n",
272 Bucket
->Request
, Status
));
274 Bucket
->Status
= Status
;
275 Bucket
->Information
= (Status
== STATUS_SUCCESS
) ? Sent
: 0;
277 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
284 VOID
DrainSignals(VOID
) {
285 PCONNECTION_ENDPOINT Connection
;
286 PLIST_ENTRY CurrentEntry
;
289 KeAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
290 CurrentEntry
= ConnectionEndpointListHead
.Flink
;
291 while (CurrentEntry
!= &ConnectionEndpointListHead
)
293 Connection
= CONTAINING_RECORD( CurrentEntry
, CONNECTION_ENDPOINT
,
295 CurrentEntry
= CurrentEntry
->Flink
;
296 KeReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
298 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
299 if (Connection
->SocketContext
)
301 HandleSignalledConnection(Connection
);
302 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
304 ProcessCompletions(Connection
);
308 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
311 KeAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
313 KeReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
316 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
317 PCONNECTION_ENDPOINT Connection
=
318 ExAllocatePoolWithTag(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
),
323 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
325 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
327 /* Initialize spin lock that protects the connection endpoint file object */
328 KeInitializeSpinLock(&Connection
->Lock
);
329 InitializeListHead(&Connection
->ConnectRequest
);
330 InitializeListHead(&Connection
->ListenRequest
);
331 InitializeListHead(&Connection
->ReceiveRequest
);
332 InitializeListHead(&Connection
->SendRequest
);
333 InitializeListHead(&Connection
->CompletionQueue
);
335 /* Save client context pointer */
336 Connection
->ClientContext
= ClientContext
;
338 /* Add connection endpoint to global list */
339 ExInterlockedInsertTailList(&ConnectionEndpointListHead
,
340 &Connection
->ListEntry
,
341 &ConnectionEndpointListLock
);
346 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
349 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
351 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
352 RemoveEntryList(&Connection
->ListEntry
);
353 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
355 ExFreePoolWithTag( Connection
, CONN_ENDPT_TAG
);
358 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
359 UINT Family
, UINT Type
, UINT Proto
) {
363 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
365 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
367 Connection
, Family
, Type
, Proto
));
369 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
370 &Connection
->SocketContext
,
375 ASSERT_KM_POINTER(Connection
->SocketContext
);
377 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
378 Connection
->SocketContext
));
380 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
385 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
387 * FUNCTION: Receives and queues TCP data
389 * IPPacket = Pointer to an IP packet that was received
391 * This is the low level interface for receiving TCP data
396 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
398 IPPacket
->HeaderSize
));
400 KeAcquireSpinLock(&ClientInfo
.Lock
, &OldIrql
);
401 ClientInfo
.Unlocked
= TRUE
;
403 OskitTCPReceiveDatagram( IPPacket
->Header
,
405 IPPacket
->HeaderSize
);
407 ClientInfo
.Unlocked
= FALSE
;
408 KeReleaseSpinLock(&ClientInfo
.Lock
, OldIrql
);
412 int TCPSocketState( void *ClientData
,
414 void *WhichConnection
,
417 int TCPPacketSend( void *ClientData
,
421 POSK_IFADDR
TCPFindInterface( void *ClientData
,
424 OSK_SOCKADDR
*ReqAddr
);
426 NTSTATUS
TCPMemStartup( void );
427 void *TCPMalloc( void *ClientData
,
428 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
429 void TCPFree( void *ClientData
,
430 void *data
, OSK_PCHAR file
, OSK_UINT line
);
431 void TCPMemShutdown( void );
433 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
434 NULL
, /* Client Data */
435 TCPSocketState
, /* SocketState */
436 TCPPacketSend
, /* PacketSend */
437 TCPFindInterface
, /* FindInterface */
438 TCPMalloc
, /* Malloc */
444 static KEVENT TimerLoopEvent
;
445 static HANDLE TimerThreadHandle
;
448 * We are running 2 timers here, one with a 200ms interval (fast) and the other
449 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
450 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
451 * "slow" events at 500 and 1000.
454 TimerThread(PVOID Context
)
456 LARGE_INTEGER Timeout
;
458 unsigned Current
, NextFast
, NextSlow
, Next
;
465 if (Next
== NextFast
) {
468 if (Next
== NextSlow
) {
471 Next
= min(NextFast
, NextSlow
);
472 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
473 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
475 if (Status
!= STATUS_TIMEOUT
) {
476 PsTerminateSystemThread(Status
);
479 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
495 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
496 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
500 NTSTATUS
TCPStartup(VOID
)
502 * FUNCTION: Initializes the TCP subsystem
504 * Status of operation
509 Status
= TCPMemStartup();
510 if ( ! NT_SUCCESS(Status
) ) {
514 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
515 if( !NT_SUCCESS(Status
) ) {
520 KeInitializeSpinLock(&ClientInfo
.Lock
);
521 ClientInfo
.Unlocked
= FALSE
;
523 RegisterOskitTCPEventHandlers( &EventHandlers
);
526 /* Register this protocol with IP layer */
527 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
529 ExInitializeNPagedLookasideList(
530 &TCPSegmentList
, /* Lookaside list */
531 NULL
, /* Allocate routine */
532 NULL
, /* Free routine */
534 sizeof(TCP_SEGMENT
), /* Size of each entry */
540 TCPInitialized
= TRUE
;
542 return STATUS_SUCCESS
;
546 NTSTATUS
TCPShutdown(VOID
)
548 * FUNCTION: Shuts down the TCP subsystem
550 * Status of operation
553 LARGE_INTEGER WaitForThread
;
556 return STATUS_SUCCESS
;
558 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
559 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
560 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
562 /* Deregister this protocol with IP layer */
563 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
565 ExDeleteNPagedLookasideList(&TCPSegmentList
);
567 TCPInitialized
= FALSE
;
571 PortsShutdown( &TCPPorts
);
575 return STATUS_SUCCESS
;
578 NTSTATUS
TCPTranslateError( int OskitError
) {
581 switch( OskitError
) {
582 case 0: Status
= STATUS_SUCCESS
; break;
583 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
584 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
585 case OSK_ECONNREFUSED
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
587 case OSK_ECONNABORTED
: Status
= STATUS_REMOTE_DISCONNECT
; break;
588 case OSK_EWOULDBLOCK
:
589 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
590 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
592 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
593 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
594 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
595 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
596 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
597 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
599 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
600 Status
= STATUS_INVALID_CONNECTION
;
604 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
609 ( PCONNECTION_ENDPOINT Connection
,
610 PTDI_CONNECTION_INFORMATION ConnInfo
,
611 PTDI_CONNECTION_INFORMATION ReturnInfo
,
612 PTCP_COMPLETION_ROUTINE Complete
,
615 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
616 IP_ADDRESS RemoteAddress
;
619 PNEIGHBOR_CACHE_ENTRY NCE
;
622 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
624 Status
= AddrBuildAddress
625 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
629 if (!NT_SUCCESS(Status
)) {
630 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
634 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
636 return STATUS_NETWORK_UNREACHABLE
;
639 /* Freed in TCPSocketState */
640 TI_DbgPrint(DEBUG_TCP
,
641 ("Connecting to address %x:%x\n",
642 RemoteAddress
.Address
.IPv4Address
,
645 AddressToConnect
.sin_family
= AF_INET
;
646 AddressToBind
= AddressToConnect
;
647 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
649 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
651 Status
= TCPTranslateError
652 ( OskitTCPBind( Connection
->SocketContext
,
654 sizeof(AddressToBind
) ) );
656 if (NT_SUCCESS(Status
)) {
657 memcpy( &AddressToConnect
.sin_addr
,
658 &RemoteAddress
.Address
.IPv4Address
,
659 sizeof(AddressToConnect
.sin_addr
) );
660 AddressToConnect
.sin_port
= RemotePort
;
662 Status
= TCPTranslateError
663 ( OskitTCPConnect( Connection
->SocketContext
,
665 sizeof(AddressToConnect
) ) );
667 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
669 if (Status
== STATUS_PENDING
)
671 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
674 return STATUS_NO_MEMORY
;
677 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
678 Bucket
->Request
.RequestContext
= Context
;
680 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
,
684 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
690 NTSTATUS TCPDisconnect
691 ( PCONNECTION_ENDPOINT Connection
,
693 PTDI_CONNECTION_INFORMATION ConnInfo
,
694 PTDI_CONNECTION_INFORMATION ReturnInfo
,
695 PTCP_COMPLETION_ROUTINE Complete
,
697 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
700 TI_DbgPrint(DEBUG_TCP
,("started\n"));
702 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
704 if (Flags
& TDI_DISCONNECT_RELEASE
)
705 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
707 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
708 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
710 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
712 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
718 ( PCONNECTION_ENDPOINT Connection
) {
723 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
725 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
726 Socket
= Connection
->SocketContext
;
727 Connection
->SocketContext
= NULL
;
728 Status
= TCPTranslateError( OskitTCPClose( Socket
) );
729 if (!NT_SUCCESS(Status
))
731 Connection
->SocketContext
= Socket
;
733 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
735 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
740 NTSTATUS TCPReceiveData
741 ( PCONNECTION_ENDPOINT Connection
,
744 PULONG BytesReceived
,
746 PTCP_COMPLETION_ROUTINE Complete
,
749 UINT DataLen
, Received
= 0;
754 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
755 ReceiveLength
, Connection
->SocketContext
));
757 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
759 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
761 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
763 ASSERT_KM_POINTER(Connection
->SocketContext
);
765 Status
= TCPTranslateError
767 ( Connection
->SocketContext
,
773 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
775 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
777 /* Keep this request around ... there was no data yet */
778 if( Status
== STATUS_PENDING
) {
779 /* Freed in TCPSocketState */
780 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
782 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
783 return STATUS_NO_MEMORY
;
786 Bucket
->Request
.RequestNotifyObject
= Complete
;
787 Bucket
->Request
.RequestContext
= Context
;
790 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
,
792 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
794 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
795 *BytesReceived
= Received
;
798 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
804 ( PCONNECTION_ENDPOINT Connection
,
809 PTCP_COMPLETION_ROUTINE Complete
,
816 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
818 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
819 SendLength
, Connection
->SocketContext
));
821 ASSERT_KM_POINTER(Connection
->SocketContext
);
823 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
824 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
825 Connection
->SocketContext
));
827 Status
= TCPTranslateError
828 ( OskitTCPSend( Connection
->SocketContext
,
829 (OSK_PCHAR
)BufferData
, SendLength
,
832 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
834 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
836 /* Keep this request around ... there was no data yet */
837 if( Status
== STATUS_PENDING
) {
838 /* Freed in TCPSocketState */
839 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
841 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
842 return STATUS_NO_MEMORY
;
845 Bucket
->Request
.RequestNotifyObject
= Complete
;
846 Bucket
->Request
.RequestContext
= Context
;
849 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
,
851 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
853 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
857 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
862 UINT
TCPAllocatePort( UINT HintPort
) {
864 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
867 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
870 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
873 VOID
TCPFreePort( UINT Port
) {
874 DeallocatePort( &TCPPorts
, Port
);
877 NTSTATUS TCPGetSockAddress
878 ( PCONNECTION_ENDPOINT Connection
,
879 PTRANSPORT_ADDRESS Address
,
880 BOOLEAN GetRemote
) {
881 OSK_UINT LocalAddress
, RemoteAddress
;
882 OSK_UI16 LocalPort
, RemotePort
;
883 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
887 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
889 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
890 &LocalAddress
, &LocalPort
,
891 &RemoteAddress
, &RemotePort
));
893 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
895 if (!NT_SUCCESS(Status
))
898 AddressIP
->TAAddressCount
= 1;
899 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
900 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
901 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
902 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
907 BOOLEAN
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
909 PLIST_ENTRY ListHead
[4];
913 BOOLEAN Found
= FALSE
;
915 ListHead
[0] = &Endpoint
->SendRequest
;
916 ListHead
[1] = &Endpoint
->ReceiveRequest
;
917 ListHead
[2] = &Endpoint
->ConnectRequest
;
918 ListHead
[3] = &Endpoint
->ListenRequest
;
920 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
922 for( i
= 0; i
< 4; i
++ )
924 for( Entry
= ListHead
[i
]->Flink
;
925 Entry
!= ListHead
[i
];
926 Entry
= Entry
->Flink
)
928 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
929 if( Bucket
->Request
.RequestContext
== Irp
)
931 RemoveEntryList( &Bucket
->Entry
);
932 ExFreePoolWithTag( Bucket
, TDI_BUCKET_TAG
);
939 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);