2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/tcp.c
5 * PURPOSE: Transmission Control Protocol
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Art Yerkes (arty@users.sf.net)
9 * CSH 01/08-2000 Created
10 * arty 12/21/2004 Added accept
15 LONG TCP_IPIdentification
= 0;
16 static BOOLEAN TCPInitialized
= FALSE
;
17 static NPAGED_LOOKASIDE_LIST TCPSegmentList
;
18 LIST_ENTRY SignalledConnectionsList
;
19 KSPIN_LOCK SignalledConnectionsLock
;
20 LIST_ENTRY SleepingThreadsList
;
21 FAST_MUTEX SleepingThreadsLock
;
22 RECURSIVE_MUTEX TCPLock
;
25 static VOID
HandleSignalledConnection( PCONNECTION_ENDPOINT Connection
) {
26 NTSTATUS Status
= STATUS_SUCCESS
;
27 PTCP_COMPLETION_ROUTINE Complete
;
33 ASSERT_LOCKED(&TCPLock
);
35 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
36 Connection
, Connection
->SocketContext
));
38 if( Connection
->SignalState
& SEL_FIN
) {
39 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
41 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
42 &Connection
->Lock
)) != NULL
)
44 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
45 Complete
= Bucket
->Request
.RequestNotifyObject
;
47 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
52 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
53 &Connection
->Lock
)) != NULL
)
55 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
56 Complete
= Bucket
->Request
.RequestNotifyObject
;
58 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
63 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
64 &Connection
->Lock
)) != NULL
)
66 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
67 Complete
= Bucket
->Request
.RequestNotifyObject
;
69 /* We have to notify oskittcp of the abortion */
70 TCPAbortListenForSocket(Connection
->AddressFile
->Listener
,
73 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
78 while ((Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
79 &Connection
->Lock
)) != NULL
)
81 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
82 Complete
= Bucket
->Request
.RequestNotifyObject
;
84 Complete( Bucket
->Request
.RequestContext
, STATUS_CANCELLED
, 0 );
89 Connection
->SignalState
= 0;
92 /* Things that can happen when we try the initial connection */
93 if( Connection
->SignalState
& SEL_CONNECT
) {
94 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ConnectRequest
,
95 &Connection
->Lock
)) != NULL
) {
97 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
99 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
100 Complete
= Bucket
->Request
.RequestNotifyObject
;
101 TI_DbgPrint(DEBUG_TCP
,
102 ("Completing Request %x\n", Bucket
->Request
.RequestContext
));
104 Complete( Bucket
->Request
.RequestContext
, STATUS_SUCCESS
, 0 );
106 /* Frees the bucket allocated in TCPConnect */
107 exFreePool( Bucket
);
111 if( Connection
->SignalState
& SEL_ACCEPT
) {
112 /* Handle readable on a listening socket --
113 * TODO: Implement filtering
116 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
118 IsListEmpty(&Connection
->ListenRequest
) ?
119 "empty" : "nonempty"));
121 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ListenRequest
,
122 &Connection
->Lock
)) != NULL
) {
123 PIO_STACK_LOCATION IrpSp
;
125 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
126 Complete
= Bucket
->Request
.RequestNotifyObject
;
128 Irp
= Bucket
->Request
.RequestContext
;
129 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
131 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
132 Status
= TCPServiceListeningSocket
133 ( Connection
->AddressFile
->Listener
,
134 Bucket
->AssociatedEndpoint
,
135 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
137 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
139 if( Status
== STATUS_PENDING
) {
140 ExInterlockedInsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
, &Connection
->Lock
);
143 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
144 exFreePool( Bucket
);
149 /* Things that happen after we're connected */
150 if( Connection
->SignalState
& SEL_READ
) {
151 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
152 IsListEmpty(&Connection
->ReceiveRequest
) ?
153 "empty" : "nonempty"));
155 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->ReceiveRequest
,
156 &Connection
->Lock
)) != NULL
) {
157 OSK_UINT RecvLen
= 0, Received
= 0;
158 PVOID RecvBuffer
= 0;
160 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
161 Complete
= Bucket
->Request
.RequestNotifyObject
;
163 Irp
= Bucket
->Request
.RequestContext
;
164 Mdl
= Irp
->MdlAddress
;
166 TI_DbgPrint(DEBUG_TCP
,
167 ("Getting the user buffer from %x\n", Mdl
));
169 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
171 TI_DbgPrint(DEBUG_TCP
,
172 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
174 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
177 ("Connection->SocketContext: %x\n",
178 Connection
->SocketContext
));
179 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
181 Status
= TCPTranslateError
182 ( OskitTCPRecv( Connection
->SocketContext
,
188 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
190 if( Status
== STATUS_SUCCESS
) {
191 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
194 Complete( Bucket
->Request
.RequestContext
,
195 STATUS_SUCCESS
, Received
);
196 exFreePool( Bucket
);
197 } else if( Status
== STATUS_PENDING
) {
198 ExInterlockedInsertHeadList
199 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
202 TI_DbgPrint(DEBUG_TCP
,
203 ("Completing Receive request: %x %x\n",
204 Bucket
->Request
, Status
));
205 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
206 exFreePool( Bucket
);
210 if( Connection
->SignalState
& SEL_WRITE
) {
211 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
212 IsListEmpty(&Connection
->SendRequest
) ?
213 "empty" : "nonempty"));
215 while( (Entry
= ExInterlockedRemoveHeadList( &Connection
->SendRequest
,
216 &Connection
->Lock
)) != NULL
) {
217 OSK_UINT SendLen
= 0, Sent
= 0;
218 PVOID SendBuffer
= 0;
220 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
221 Complete
= Bucket
->Request
.RequestNotifyObject
;
223 Irp
= Bucket
->Request
.RequestContext
;
224 Mdl
= Irp
->MdlAddress
;
226 TI_DbgPrint(DEBUG_TCP
,
227 ("Getting the user buffer from %x\n", Mdl
));
229 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
231 TI_DbgPrint(DEBUG_TCP
,
232 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
234 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
237 ("Connection->SocketContext: %x\n",
238 Connection
->SocketContext
));
240 Status
= TCPTranslateError
241 ( OskitTCPSend( Connection
->SocketContext
,
247 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
249 if( Status
== STATUS_SUCCESS
) {
250 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
253 Complete( Bucket
->Request
.RequestContext
,
254 STATUS_SUCCESS
, Sent
);
255 exFreePool( Bucket
);
256 } else if( Status
== STATUS_PENDING
) {
257 ExInterlockedInsertHeadList
258 ( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
261 TI_DbgPrint(DEBUG_TCP
,
262 ("Completing Send request: %x %x\n",
263 Bucket
->Request
, Status
));
264 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
265 exFreePool( Bucket
);
270 Connection
->SignalState
= 0;
271 Connection
->Signalled
= FALSE
;
274 VOID
DrainSignals() {
275 PCONNECTION_ENDPOINT Connection
;
276 PLIST_ENTRY ListEntry
;
278 while( (ListEntry
= ExInterlockedRemoveHeadList(&SignalledConnectionsList
,
279 &SignalledConnectionsLock
)) != NULL
) {
280 Connection
= CONTAINING_RECORD( ListEntry
, CONNECTION_ENDPOINT
,
282 HandleSignalledConnection( Connection
);
286 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
287 PCONNECTION_ENDPOINT Connection
=
288 exAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
292 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
294 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
296 /* Initialize spin lock that protects the connection endpoint file object */
297 TcpipInitializeSpinLock(&Connection
->Lock
);
298 InitializeListHead(&Connection
->ConnectRequest
);
299 InitializeListHead(&Connection
->ListenRequest
);
300 InitializeListHead(&Connection
->ReceiveRequest
);
301 InitializeListHead(&Connection
->SendRequest
);
303 /* Save client context pointer */
304 Connection
->ClientContext
= ClientContext
;
309 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
310 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
311 exFreePool( Connection
);
314 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
315 UINT Family
, UINT Type
, UINT Proto
) {
318 ASSERT_LOCKED(&TCPLock
);
320 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
322 Connection
, Family
, Type
, Proto
));
324 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
325 &Connection
->SocketContext
,
330 ASSERT_KM_POINTER(Connection
->SocketContext
);
332 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
333 Connection
->SocketContext
));
338 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
340 * FUNCTION: Receives and queues TCP data
342 * IPPacket = Pointer to an IP packet that was received
344 * This is the low level interface for receiving TCP data
347 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
349 IPPacket
->HeaderSize
));
351 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
353 OskitTCPReceiveDatagram( IPPacket
->Header
,
355 IPPacket
->HeaderSize
);
359 TcpipRecursiveMutexLeave( &TCPLock
);
363 int TCPSocketState( void *ClientData
,
365 void *WhichConnection
,
368 int TCPPacketSend( void *ClientData
,
372 POSK_IFADDR
TCPFindInterface( void *ClientData
,
375 OSK_SOCKADDR
*ReqAddr
);
377 NTSTATUS
TCPMemStartup( void );
378 void *TCPMalloc( void *ClientData
,
379 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
380 void TCPFree( void *ClientData
,
381 void *data
, OSK_PCHAR file
, OSK_UINT line
);
382 void TCPMemShutdown( void );
384 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
387 void TCPWakeup( void *ClientData
, void *token
);
389 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
390 NULL
, /* Client Data */
391 TCPSocketState
, /* SocketState */
392 TCPPacketSend
, /* PacketSend */
393 TCPFindInterface
, /* FindInterface */
394 TCPMalloc
, /* Malloc */
396 TCPSleep
, /* Sleep */
397 TCPWakeup
/* Wakeup */
400 static KEVENT TimerLoopEvent
;
401 static HANDLE TimerThreadHandle
;
404 * We are running 2 timers here, one with a 200ms interval (fast) and the other
405 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
406 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
407 * "slow" events at 500 and 1000.
410 TimerThread(PVOID Context
)
412 LARGE_INTEGER Timeout
;
414 unsigned Current
, NextFast
, NextSlow
, Next
;
421 if (Next
== NextFast
) {
424 if (Next
== NextSlow
) {
427 Next
= min(NextFast
, NextSlow
);
428 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
429 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
431 if (Status
!= STATUS_TIMEOUT
) {
432 PsTerminateSystemThread(Status
);
435 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
436 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
437 if (Next
== NextSlow
) {
440 TcpipRecursiveMutexLeave( &TCPLock
);
455 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
456 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
461 NTSTATUS
TCPStartup(VOID
)
463 * FUNCTION: Initializes the TCP subsystem
465 * Status of operation
470 TcpipRecursiveMutexInit( &TCPLock
);
471 ExInitializeFastMutex( &SleepingThreadsLock
);
472 KeInitializeSpinLock( &SignalledConnectionsLock
);
473 InitializeListHead( &SleepingThreadsList
);
474 InitializeListHead( &SignalledConnectionsList
);
475 Status
= TCPMemStartup();
476 if ( ! NT_SUCCESS(Status
) ) {
480 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
481 if( !NT_SUCCESS(Status
) ) {
486 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
487 RegisterOskitTCPEventHandlers( &EventHandlers
);
489 TcpipRecursiveMutexLeave(&TCPLock
);
491 /* Register this protocol with IP layer */
492 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
494 ExInitializeNPagedLookasideList(
495 &TCPSegmentList
, /* Lookaside list */
496 NULL
, /* Allocate routine */
497 NULL
, /* Free routine */
499 sizeof(TCP_SEGMENT
), /* Size of each entry */
505 TCPInitialized
= TRUE
;
507 return STATUS_SUCCESS
;
511 NTSTATUS
TCPShutdown(VOID
)
513 * FUNCTION: Shuts down the TCP subsystem
515 * Status of operation
518 LARGE_INTEGER WaitForThread
;
521 return STATUS_SUCCESS
;
523 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
524 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
525 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
527 /* Deregister this protocol with IP layer */
528 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
530 ExDeleteNPagedLookasideList(&TCPSegmentList
);
532 TCPInitialized
= FALSE
;
536 PortsShutdown( &TCPPorts
);
540 return STATUS_SUCCESS
;
543 NTSTATUS
TCPTranslateError( int OskitError
) {
546 switch( OskitError
) {
547 case 0: Status
= STATUS_SUCCESS
; break;
548 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
549 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
550 case OSK_ECONNREFUSED
:
551 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
552 case OSK_EWOULDBLOCK
:
553 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
554 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
556 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
557 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
558 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
559 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
560 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
561 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
563 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
564 Status
= STATUS_INVALID_CONNECTION
;
568 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
573 ( PCONNECTION_ENDPOINT Connection
,
574 PTDI_CONNECTION_INFORMATION ConnInfo
,
575 PTDI_CONNECTION_INFORMATION ReturnInfo
,
576 PTCP_COMPLETION_ROUTINE Complete
,
579 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
580 IP_ADDRESS RemoteAddress
;
583 PNEIGHBOR_CACHE_ENTRY NCE
;
585 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
587 ASSERT_LOCKED(&TCPLock
);
589 Status
= AddrBuildAddress
590 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
594 if (!NT_SUCCESS(Status
)) {
595 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
599 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
601 return STATUS_NETWORK_UNREACHABLE
;
604 /* Freed in TCPSocketState */
605 TI_DbgPrint(DEBUG_TCP
,
606 ("Connecting to address %x:%x\n",
607 RemoteAddress
.Address
.IPv4Address
,
610 AddressToConnect
.sin_family
= AF_INET
;
611 AddressToBind
= AddressToConnect
;
612 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
614 Status
= TCPTranslateError
615 ( OskitTCPBind( Connection
->SocketContext
,
617 sizeof(AddressToBind
) ) );
619 if (NT_SUCCESS(Status
)) {
620 memcpy( &AddressToConnect
.sin_addr
,
621 &RemoteAddress
.Address
.IPv4Address
,
622 sizeof(AddressToConnect
.sin_addr
) );
623 AddressToConnect
.sin_port
= RemotePort
;
625 Status
= TCPTranslateError
626 ( OskitTCPConnect( Connection
->SocketContext
,
629 sizeof(AddressToConnect
) ) );
631 if (Status
== STATUS_PENDING
)
633 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
634 if( !Bucket
) return STATUS_NO_MEMORY
;
636 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
637 Bucket
->Request
.RequestContext
= Context
;
639 IoMarkIrpPending((PIRP
)Context
);
641 ExInterlockedInsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
, &Connection
->Lock
);
648 NTSTATUS TCPDisconnect
649 ( PCONNECTION_ENDPOINT Connection
,
651 PTDI_CONNECTION_INFORMATION ConnInfo
,
652 PTDI_CONNECTION_INFORMATION ReturnInfo
,
653 PTCP_COMPLETION_ROUTINE Complete
,
655 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
657 ASSERT_LOCKED(&TCPLock
);
659 TI_DbgPrint(DEBUG_TCP
,("started\n"));
661 if (Flags
& TDI_DISCONNECT_RELEASE
)
662 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
664 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
665 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
667 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
673 ( PCONNECTION_ENDPOINT Connection
) {
676 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
678 ASSERT_LOCKED(&TCPLock
);
680 /* Make our code remove all pending IRPs */
681 Connection
->SignalState
|= SEL_FIN
;
682 HandleSignalledConnection(Connection
);
684 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
685 if (Status
== STATUS_SUCCESS
)
686 Connection
->SocketContext
= NULL
;
688 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
693 NTSTATUS TCPReceiveData
694 ( PCONNECTION_ENDPOINT Connection
,
697 PULONG BytesReceived
,
699 PTCP_COMPLETION_ROUTINE Complete
,
702 UINT DataLen
, Received
= 0;
706 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
707 ReceiveLength
, Connection
->SocketContext
));
709 ASSERT_LOCKED(&TCPLock
);
711 ASSERT_KM_POINTER(Connection
->SocketContext
);
713 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
715 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
717 Status
= TCPTranslateError
719 ( Connection
->SocketContext
,
725 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
727 /* Keep this request around ... there was no data yet */
728 if( Status
== STATUS_PENDING
) {
729 /* Freed in TCPSocketState */
730 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
732 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
733 return STATUS_NO_MEMORY
;
736 Bucket
->Request
.RequestNotifyObject
= Complete
;
737 Bucket
->Request
.RequestContext
= Context
;
740 IoMarkIrpPending((PIRP
)Context
);
742 ExInterlockedInsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
, &Connection
->Lock
);
743 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
745 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
746 *BytesReceived
= Received
;
749 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
755 ( PCONNECTION_ENDPOINT Connection
,
760 PTCP_COMPLETION_ROUTINE Complete
,
766 ASSERT_LOCKED(&TCPLock
);
768 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
769 SendLength
, Connection
->SocketContext
));
771 ASSERT_KM_POINTER(Connection
->SocketContext
);
773 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
774 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
775 Connection
->SocketContext
));
778 Status
= TCPTranslateError
779 ( OskitTCPSend( Connection
->SocketContext
,
780 (OSK_PCHAR
)BufferData
, SendLength
,
783 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
785 /* Keep this request around ... there was no data yet */
786 if( Status
== STATUS_PENDING
) {
787 /* Freed in TCPSocketState */
788 Bucket
= exAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
790 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
791 return STATUS_NO_MEMORY
;
794 Bucket
->Request
.RequestNotifyObject
= Complete
;
795 Bucket
->Request
.RequestContext
= Context
;
798 IoMarkIrpPending((PIRP
)Context
);
800 ExInterlockedInsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
, &Connection
->Lock
);
801 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
803 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
807 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
812 VOID
TCPTimeout(VOID
) {
813 /* Now handled by TimerThread */
816 UINT
TCPAllocatePort( UINT HintPort
) {
818 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
821 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
824 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
827 VOID
TCPFreePort( UINT Port
) {
828 DeallocatePort( &TCPPorts
, Port
);
831 NTSTATUS TCPGetSockAddress
832 ( PCONNECTION_ENDPOINT Connection
,
833 PTRANSPORT_ADDRESS Address
,
834 BOOLEAN GetRemote
) {
835 OSK_UINT LocalAddress
, RemoteAddress
;
836 OSK_UI16 LocalPort
, RemotePort
;
837 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
840 ASSERT_LOCKED(&TCPLock
);
842 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
843 &LocalAddress
, &LocalPort
,
844 &RemoteAddress
, &RemotePort
));
845 if (!NT_SUCCESS(Status
))
848 AddressIP
->TAAddressCount
= 1;
849 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
850 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
851 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
852 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
857 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
859 PLIST_ENTRY ListHead
[4];
864 ListHead
[0] = &Endpoint
->SendRequest
;
865 ListHead
[1] = &Endpoint
->ReceiveRequest
;
866 ListHead
[2] = &Endpoint
->ConnectRequest
;
867 ListHead
[3] = &Endpoint
->ListenRequest
;
869 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
871 for( i
= 0; i
< 4; i
++ )
873 for( Entry
= ListHead
[i
]->Flink
;
874 Entry
!= ListHead
[i
];
875 Entry
= Entry
->Flink
)
877 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
878 if( Bucket
->Request
.RequestContext
== Irp
)
880 RemoveEntryList( &Bucket
->Entry
);
881 exFreePool( Bucket
);
887 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);