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 SignalledConnections
;
19 LIST_ENTRY SleepingThreadsList
;
20 FAST_MUTEX SleepingThreadsLock
;
21 RECURSIVE_MUTEX TCPLock
;
24 static VOID
HandleSignalledConnection( PCONNECTION_ENDPOINT Connection
,
26 NTSTATUS Status
= STATUS_SUCCESS
;
27 PTCP_COMPLETION_ROUTINE Complete
;
33 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
34 Connection
, Connection
->SocketContext
));
36 /* Things that can happen when we try the initial connection */
37 if( NewState
& SEL_CONNECT
) {
38 while( !IsListEmpty( &Connection
->ConnectRequest
) ) {
39 Connection
->State
|= NewState
;
40 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
41 TI_DbgPrint(DEBUG_TCP
, ("Connect Event\n"));
43 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
44 Complete
= Bucket
->Request
.RequestNotifyObject
;
45 TI_DbgPrint(DEBUG_TCP
,
46 ("Completing Request %x\n", Bucket
->Request
));
48 if( (NewState
& (SEL_CONNECT
| SEL_FIN
)) ==
49 (SEL_CONNECT
| SEL_FIN
) )
50 Status
= STATUS_CONNECTION_REFUSED
;
52 Status
= STATUS_SUCCESS
;
54 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
56 /* Frees the bucket allocated in TCPConnect */
57 PoolFreeBuffer( Bucket
);
61 if( NewState
& SEL_ACCEPT
) {
62 /* Handle readable on a listening socket --
63 * TODO: Implement filtering
66 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
68 IsListEmpty(&Connection
->ListenRequest
) ?
69 "empty" : "nonempty"));
71 while( !IsListEmpty( &Connection
->ListenRequest
) ) {
72 PIO_STACK_LOCATION IrpSp
;
74 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
75 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
76 Complete
= Bucket
->Request
.RequestNotifyObject
;
78 Irp
= Bucket
->Request
.RequestContext
;
79 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
81 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
82 Status
= TCPServiceListeningSocket
83 ( Connection
->AddressFile
->Listener
,
84 Bucket
->AssociatedEndpoint
,
85 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
87 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
89 if( Status
== STATUS_PENDING
) {
90 InsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
);
93 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
94 PoolFreeBuffer( Bucket
);
99 /* Things that happen after we're connected */
100 if( NewState
& SEL_READ
) {
101 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
102 IsListEmpty(&Connection
->ReceiveRequest
) ?
103 "empty" : "nonempty"));
105 while( !IsListEmpty( &Connection
->ReceiveRequest
) ) {
106 OSK_UINT RecvLen
= 0, Received
= 0;
107 OSK_PCHAR RecvBuffer
= 0;
109 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
110 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
111 Complete
= Bucket
->Request
.RequestNotifyObject
;
113 Irp
= Bucket
->Request
.RequestContext
;
114 Mdl
= Irp
->MdlAddress
;
116 TI_DbgPrint(DEBUG_TCP
,
117 ("Getting the user buffer from %x\n", Mdl
));
119 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
121 TI_DbgPrint(DEBUG_TCP
,
122 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
124 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
127 ("Connection->SocketContext: %x\n",
128 Connection
->SocketContext
));
129 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
131 Status
= TCPTranslateError
132 ( OskitTCPRecv( Connection
->SocketContext
,
138 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
140 if( Status
== STATUS_SUCCESS
) {
141 TI_DbgPrint(DEBUG_TCP
,("Received %d bytes with status %x\n",
144 Complete( Bucket
->Request
.RequestContext
,
145 STATUS_SUCCESS
, Received
);
146 PoolFreeBuffer( Bucket
);
147 } else if( Status
== STATUS_PENDING
) {
149 ( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
152 TI_DbgPrint(DEBUG_TCP
,
153 ("Completing Receive request: %x %x\n",
154 Bucket
->Request
, Status
));
155 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
156 PoolFreeBuffer( Bucket
);
160 if( NewState
& SEL_WRITE
) {
161 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
162 IsListEmpty(&Connection
->ReceiveRequest
) ?
163 "empty" : "nonempty"));
165 while( !IsListEmpty( &Connection
->SendRequest
) ) {
166 OSK_UINT SendLen
= 0, Sent
= 0;
167 OSK_PCHAR SendBuffer
= 0;
169 Entry
= RemoveHeadList( &Connection
->SendRequest
);
170 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
171 Complete
= Bucket
->Request
.RequestNotifyObject
;
173 Irp
= Bucket
->Request
.RequestContext
;
174 Mdl
= Irp
->MdlAddress
;
176 TI_DbgPrint(DEBUG_TCP
,
177 ("Getting the user buffer from %x\n", Mdl
));
179 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
181 TI_DbgPrint(DEBUG_TCP
,
182 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
184 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
187 ("Connection->SocketContext: %x\n",
188 Connection
->SocketContext
));
190 Status
= TCPTranslateError
191 ( OskitTCPSend( Connection
->SocketContext
,
197 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
199 if( Status
== STATUS_SUCCESS
) {
200 TI_DbgPrint(DEBUG_TCP
,("Sent %d bytes with status %x\n",
203 Complete( Bucket
->Request
.RequestContext
,
204 STATUS_SUCCESS
, Sent
);
205 PoolFreeBuffer( Bucket
);
206 } else if( Status
== STATUS_PENDING
) {
208 ( &Connection
->SendRequest
, &Bucket
->Entry
);
211 TI_DbgPrint(DEBUG_TCP
,
212 ("Completing Send request: %x %x\n",
213 Bucket
->Request
, Status
));
214 Complete( Bucket
->Request
.RequestContext
, Status
, 0 );
215 PoolFreeBuffer( Bucket
);
220 if( NewState
& SEL_FIN
) {
221 PLIST_ENTRY ListsToErase
[4];
222 NTSTATUS IrpStatus
[4];
225 TI_DbgPrint(DEBUG_TCP
, ("EOF From socket\n"));
227 ListsToErase
[0] = &Connection
->ReceiveRequest
;
228 IrpStatus
[0] = STATUS_SUCCESS
;
229 ListsToErase
[1] = &Connection
->ListenRequest
;
230 IrpStatus
[1] = STATUS_UNSUCCESSFUL
;
231 ListsToErase
[2] = &Connection
->ConnectRequest
;
232 IrpStatus
[2] = STATUS_UNSUCCESSFUL
;
236 for( i
= 0; ListsToErase
[i
]; i
++ ) {
237 while( !IsListEmpty( ListsToErase
[i
] ) ) {
238 Entry
= RemoveHeadList( ListsToErase
[i
] );
239 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
240 Complete
= Bucket
->Request
.RequestNotifyObject
;
241 Complete( Bucket
->Request
.RequestContext
, IrpStatus
[i
], 0 );
242 PoolFreeBuffer( Bucket
);
247 Connection
->Signalled
= FALSE
;
250 VOID
DrainSignals() {
251 PCONNECTION_ENDPOINT Connection
;
252 PLIST_ENTRY ListEntry
;
254 while( !IsListEmpty( &SignalledConnections
) ) {
255 ListEntry
= RemoveHeadList( &SignalledConnections
);
256 Connection
= CONTAINING_RECORD( ListEntry
, CONNECTION_ENDPOINT
,
258 HandleSignalledConnection( Connection
, Connection
->SignalState
);
262 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
263 PCONNECTION_ENDPOINT Connection
=
264 ExAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
268 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
270 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
272 /* Initialize spin lock that protects the connection endpoint file object */
273 TcpipInitializeSpinLock(&Connection
->Lock
);
274 InitializeListHead(&Connection
->ConnectRequest
);
275 InitializeListHead(&Connection
->ListenRequest
);
276 InitializeListHead(&Connection
->ReceiveRequest
);
277 InitializeListHead(&Connection
->SendRequest
);
279 /* Save client context pointer */
280 Connection
->ClientContext
= ClientContext
;
285 VOID
TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection
) {
286 TI_DbgPrint(MAX_TRACE
,("FIXME: Cancel all pending requests\n"));
287 /* XXX Cancel all pending requests */
288 ExFreePool( Connection
);
291 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
292 UINT Family
, UINT Type
, UINT Proto
) {
295 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
297 Connection
, Family
, Type
, Proto
));
299 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
300 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
301 &Connection
->SocketContext
,
306 ASSERT_KM_POINTER(Connection
->SocketContext
);
308 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
309 Connection
->SocketContext
));
311 TcpipRecursiveMutexLeave( &TCPLock
);
316 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
318 * FUNCTION: Receives and queues TCP data
320 * IPPacket = Pointer to an IP packet that was received
322 * This is the low level interface for receiving TCP data
325 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
327 IPPacket
->HeaderSize
));
329 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
331 OskitTCPReceiveDatagram( IPPacket
->Header
,
333 IPPacket
->HeaderSize
);
337 TcpipRecursiveMutexLeave( &TCPLock
);
341 int TCPSocketState( void *ClientData
,
343 void *WhichConnection
,
346 int TCPPacketSend( void *ClientData
,
350 POSK_IFADDR
TCPFindInterface( void *ClientData
,
353 OSK_SOCKADDR
*ReqAddr
);
355 NTSTATUS
TCPMemStartup( void );
356 void *TCPMalloc( void *ClientData
,
357 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
358 void TCPFree( void *ClientData
,
359 void *data
, OSK_PCHAR file
, OSK_UINT line
);
360 void TCPMemShutdown( void );
362 int TCPSleep( void *ClientData
, void *token
, int priority
, char *msg
,
365 void TCPWakeup( void *ClientData
, void *token
);
367 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
368 NULL
, /* Client Data */
369 TCPSocketState
, /* SocketState */
370 TCPPacketSend
, /* PacketSend */
371 TCPFindInterface
, /* FindInterface */
372 TCPMalloc
, /* Malloc */
374 TCPSleep
, /* Sleep */
375 TCPWakeup
/* Wakeup */
378 static KEVENT TimerLoopEvent
;
379 static HANDLE TimerThreadHandle
;
382 * We are running 2 timers here, one with a 200ms interval (fast) and the other
383 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
384 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
385 * "slow" events at 500 and 1000.
388 TimerThread(PVOID Context
)
390 LARGE_INTEGER Timeout
;
392 unsigned Current
, NextFast
, NextSlow
, Next
;
399 if (Next
== NextFast
) {
402 if (Next
== NextSlow
) {
405 Next
= min(NextFast
, NextSlow
);
406 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
407 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
409 if (STATUS_SUCCESS
== Status
) {
410 PsTerminateSystemThread(STATUS_SUCCESS
);
412 ASSERT(STATUS_TIMEOUT
== Status
);
414 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
415 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
416 if (Next
== NextSlow
) {
419 TcpipRecursiveMutexLeave( &TCPLock
);
434 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
435 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
440 NTSTATUS
TCPStartup(VOID
)
442 * FUNCTION: Initializes the TCP subsystem
444 * Status of operation
449 TcpipRecursiveMutexInit( &TCPLock
);
450 ExInitializeFastMutex( &SleepingThreadsLock
);
451 InitializeListHead( &SleepingThreadsList
);
452 InitializeListHead( &SignalledConnections
);
453 Status
= TCPMemStartup();
454 if ( ! NT_SUCCESS(Status
) ) {
458 PortsStartup( &TCPPorts
, 1, 0xfffe );
460 RegisterOskitTCPEventHandlers( &EventHandlers
);
463 /* Register this protocol with IP layer */
464 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
466 ExInitializeNPagedLookasideList(
467 &TCPSegmentList
, /* Lookaside list */
468 NULL
, /* Allocate routine */
469 NULL
, /* Free routine */
471 sizeof(TCP_SEGMENT
), /* Size of each entry */
472 TAG('T','C','P','S'), /* Tag */
477 TCPInitialized
= TRUE
;
479 return STATUS_SUCCESS
;
483 NTSTATUS
TCPShutdown(VOID
)
485 * FUNCTION: Shuts down the TCP subsystem
487 * Status of operation
490 LARGE_INTEGER WaitForThread
;
493 return STATUS_SUCCESS
;
495 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
496 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
497 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
499 /* Deregister this protocol with IP layer */
500 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
502 ExDeleteNPagedLookasideList(&TCPSegmentList
);
504 TCPInitialized
= FALSE
;
508 PortsShutdown( &TCPPorts
);
512 return STATUS_SUCCESS
;
515 NTSTATUS
TCPTranslateError( int OskitError
) {
516 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
518 switch( OskitError
) {
519 case 0: Status
= STATUS_SUCCESS
; break;
520 case OSK_EADDRNOTAVAIL
:
521 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
522 case OSK_ECONNREFUSED
:
523 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
524 case OSK_EINPROGRESS
:
525 case OSK_EAGAIN
: Status
= STATUS_PENDING
; break;
526 default: Status
= STATUS_INVALID_CONNECTION
; break;
529 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
534 ( PCONNECTION_ENDPOINT Connection
,
535 PTDI_CONNECTION_INFORMATION ConnInfo
,
536 PTDI_CONNECTION_INFORMATION ReturnInfo
,
537 PTCP_COMPLETION_ROUTINE Complete
,
540 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
541 IP_ADDRESS RemoteAddress
;
545 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
547 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
548 if( !Bucket
) return STATUS_NO_MEMORY
;
550 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
552 /* Freed in TCPSocketState */
553 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
554 Bucket
->Request
.RequestContext
= Context
;
556 InsertHeadList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
558 Status
= AddrBuildAddress
559 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
563 TI_DbgPrint(DEBUG_TCP
,
564 ("Connecting to address %x:%x\n",
565 RemoteAddress
.Address
.IPv4Address
,
568 if (!NT_SUCCESS(Status
)) {
569 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
570 TcpipRecursiveMutexLeave( &TCPLock
);
574 AddressToConnect
.sin_family
= AF_INET
;
575 AddressToBind
= AddressToConnect
;
577 OskitTCPBind( Connection
->SocketContext
,
580 sizeof(AddressToBind
) );
582 memcpy( &AddressToConnect
.sin_addr
,
583 &RemoteAddress
.Address
.IPv4Address
,
584 sizeof(AddressToConnect
.sin_addr
) );
585 AddressToConnect
.sin_port
= RemotePort
;
587 Status
= TCPTranslateError
588 ( OskitTCPConnect( Connection
->SocketContext
,
591 sizeof(AddressToConnect
) ) );
593 TcpipRecursiveMutexLeave( &TCPLock
);
598 NTSTATUS TCPDisconnect
599 ( PCONNECTION_ENDPOINT Connection
,
601 PTDI_CONNECTION_INFORMATION ConnInfo
,
602 PTDI_CONNECTION_INFORMATION ReturnInfo
,
603 PTCP_COMPLETION_ROUTINE Complete
,
607 TI_DbgPrint(DEBUG_TCP
,("started\n"));
609 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
611 switch( Flags
& (TDI_DISCONNECT_ABORT
| TDI_DISCONNECT_RELEASE
) ) {
613 case TDI_DISCONNECT_ABORT
:
617 case TDI_DISCONNECT_ABORT
| TDI_DISCONNECT_RELEASE
:
621 case TDI_DISCONNECT_RELEASE
:
626 Status
= TCPTranslateError
627 ( OskitTCPShutdown( Connection
->SocketContext
, Flags
) );
629 TcpipRecursiveMutexLeave( &TCPLock
);
631 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
637 ( PCONNECTION_ENDPOINT Connection
) {
640 TI_DbgPrint(DEBUG_TCP
,("TCPClose started\n"));
642 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
644 Status
= TCPTranslateError( OskitTCPClose( Connection
->SocketContext
) );
646 /* Make our code remove all pending IRPs */
647 Connection
->State
|= SEL_FIN
;
650 TcpipRecursiveMutexLeave( &TCPLock
);
652 TI_DbgPrint(DEBUG_TCP
,("TCPClose finished %x\n", Status
));
657 NTSTATUS TCPReceiveData
658 ( PCONNECTION_ENDPOINT Connection
,
661 PULONG BytesReceived
,
663 PTCP_COMPLETION_ROUTINE Complete
,
665 OSK_PCHAR DataBuffer
;
666 UINT DataLen
, Received
= 0;
670 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
671 ReceiveLength
, Connection
->SocketContext
));
673 ASSERT_KM_POINTER(Connection
->SocketContext
);
675 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
677 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
679 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
681 Status
= TCPTranslateError
683 ( Connection
->SocketContext
,
689 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
691 /* Keep this request around ... there was no data yet */
692 if( Status
== STATUS_PENDING
) {
693 /* Freed in TCPSocketState */
694 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
696 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
697 TcpipRecursiveMutexLeave( &TCPLock
);
698 return STATUS_NO_MEMORY
;
701 Bucket
->Request
.RequestNotifyObject
= Complete
;
702 Bucket
->Request
.RequestContext
= Context
;
705 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
706 Status
= STATUS_PENDING
;
707 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
709 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
710 *BytesReceived
= Received
;
713 TcpipRecursiveMutexLeave( &TCPLock
);
715 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
721 ( PCONNECTION_ENDPOINT Connection
,
726 PTCP_COMPLETION_ROUTINE Complete
,
732 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
733 SendLength
, Connection
->SocketContext
));
735 ASSERT_KM_POINTER(Connection
->SocketContext
);
737 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
739 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
740 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
741 Connection
->SocketContext
));
743 Status
= TCPTranslateError
744 ( OskitTCPSend( Connection
->SocketContext
,
745 (OSK_PCHAR
)BufferData
, SendLength
,
748 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
750 /* Keep this request around ... there was no data yet */
751 if( Status
== STATUS_PENDING
) {
752 /* Freed in TCPSocketState */
753 Bucket
= ExAllocatePool( NonPagedPool
, sizeof(*Bucket
) );
755 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
756 TcpipRecursiveMutexLeave( &TCPLock
);
757 return STATUS_NO_MEMORY
;
760 Bucket
->Request
.RequestNotifyObject
= Complete
;
761 Bucket
->Request
.RequestContext
= Context
;
764 InsertHeadList( &Connection
->SendRequest
, &Bucket
->Entry
);
765 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
767 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
771 TcpipRecursiveMutexLeave( &TCPLock
);
773 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
778 VOID
TCPTimeout(VOID
) {
779 /* Now handled by TimerThread */
782 UINT
TCPAllocatePort( UINT HintPort
) {
784 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
787 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
790 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
793 VOID
TCPFreePort( UINT Port
) {
794 DeallocatePort( &TCPPorts
, Port
);
797 NTSTATUS TCPGetPeerAddress
798 ( PCONNECTION_ENDPOINT Connection
,
799 PTRANSPORT_ADDRESS Address
) {
800 OSK_UINT LocalAddress
, RemoteAddress
;
801 OSK_UI16 LocalPort
, RemotePort
;
802 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
804 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
807 ( Connection
->SocketContext
,
808 &LocalAddress
, &LocalPort
,
809 &RemoteAddress
, &RemotePort
);
811 AddressIP
->TAAddressCount
= 1;
812 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
813 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
814 AddressIP
->Address
[0].Address
[0].sin_port
= RemotePort
;
815 AddressIP
->Address
[0].Address
[0].in_addr
= RemoteAddress
;
817 TcpipRecursiveMutexLeave( &TCPLock
);
819 return STATUS_SUCCESS
;
822 VOID
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
824 PLIST_ENTRY ListHead
[4];
829 ListHead
[0] = &Endpoint
->SendRequest
;
830 ListHead
[1] = &Endpoint
->ReceiveRequest
;
831 ListHead
[2] = &Endpoint
->ConnectRequest
;
832 ListHead
[3] = &Endpoint
->ListenRequest
;
834 TcpipAcquireSpinLock( &Endpoint
->Lock
, &OldIrql
);
836 for( i
= 0; i
< sizeof( ListHead
) / sizeof( ListHead
[0] ); i
++ ) {
837 for( Entry
= ListHead
[i
]->Flink
;
838 Entry
!= ListHead
[i
];
839 Entry
= Entry
->Flink
) {
840 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
842 if( Bucket
->Request
.RequestContext
== Irp
) {
843 RemoveEntryList( &Bucket
->Entry
);
844 PoolFreeBuffer( Bucket
);
850 TcpipReleaseSpinLock( &Endpoint
->Lock
, OldIrql
);