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
)
29 PTCP_COMPLETION_ROUTINE Complete
;
31 if (ClientInfo
.Unlocked
)
32 LockObjectAtDpcLevel(Connection
);
34 TI_DbgPrint(MID_TRACE
,("Handling signalled state on %x (%x)\n",
35 Connection
, Connection
->SocketContext
));
37 /* Things that can happen when we try the initial connection */
38 if( Connection
->SignalState
& (SEL_CONNECT
| SEL_FIN
) ) {
39 while (!IsListEmpty(&Connection
->ConnectRequest
)) {
40 Entry
= RemoveHeadList( &Connection
->ConnectRequest
);
42 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
44 Bucket
->Status
= (Connection
->SignalState
& SEL_CONNECT
) ? STATUS_SUCCESS
: STATUS_CANCELLED
;
45 Bucket
->Information
= 0;
47 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
51 if( Connection
->SignalState
& (SEL_ACCEPT
| SEL_FIN
) ) {
52 /* Handle readable on a listening socket --
53 * TODO: Implement filtering
55 TI_DbgPrint(DEBUG_TCP
,("Accepting new connection on %x (Queue: %s)\n",
57 IsListEmpty(&Connection
->ListenRequest
) ?
58 "empty" : "nonempty"));
60 while (!IsListEmpty(&Connection
->ListenRequest
)) {
61 PIO_STACK_LOCATION IrpSp
;
63 Entry
= RemoveHeadList( &Connection
->ListenRequest
);
65 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
67 Irp
= Bucket
->Request
.RequestContext
;
68 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
70 TI_DbgPrint(DEBUG_TCP
,("Getting the socket\n"));
72 Status
= TCPServiceListeningSocket
73 ( Connection
->AddressFile
->Listener
,
74 Bucket
->AssociatedEndpoint
,
75 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
77 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n"));
79 if( Status
== STATUS_PENDING
&& !(Connection
->SignalState
& SEL_FIN
) ) {
80 InsertHeadList( &Connection
->ListenRequest
, &Bucket
->Entry
);
83 Bucket
->Status
= (Status
== STATUS_PENDING
) ? STATUS_CANCELLED
: Status
;
84 Bucket
->Information
= 0;
85 DereferenceObject(Bucket
->AssociatedEndpoint
);
87 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
92 /* Things that happen after we're connected */
93 if( Connection
->SignalState
& (SEL_READ
| SEL_FIN
) ) {
94 TI_DbgPrint(DEBUG_TCP
,("Readable: irp list %s\n",
95 IsListEmpty(&Connection
->ReceiveRequest
) ?
96 "empty" : "nonempty"));
98 while (!IsListEmpty(&Connection
->ReceiveRequest
)) {
99 OSK_UINT RecvLen
= 0, Received
= 0;
100 PVOID RecvBuffer
= 0;
102 Entry
= RemoveHeadList( &Connection
->ReceiveRequest
);
104 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
106 Irp
= Bucket
->Request
.RequestContext
;
107 Mdl
= Irp
->MdlAddress
;
109 TI_DbgPrint(DEBUG_TCP
,
110 ("Getting the user buffer from %x\n", Mdl
));
112 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
114 TI_DbgPrint(DEBUG_TCP
,
115 ("Reading %d bytes to %x\n", RecvLen
, RecvBuffer
));
117 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
120 ("Connection->SocketContext: %x\n",
121 Connection
->SocketContext
));
122 TI_DbgPrint(DEBUG_TCP
, ("RecvBuffer: %x\n", RecvBuffer
));
124 Status
= TCPTranslateError
125 ( OskitTCPRecv( Connection
->SocketContext
,
131 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Received
));
133 if( Status
== STATUS_PENDING
&& !(Connection
->SignalState
& SEL_FIN
) ) {
134 InsertHeadList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
137 TI_DbgPrint(DEBUG_TCP
,
138 ("Completing Receive request: %x %x\n",
139 Bucket
->Request
, Status
));
141 Bucket
->Status
= (Status
== STATUS_PENDING
) ? STATUS_CANCELLED
: Status
;
142 Bucket
->Information
= (Bucket
->Status
== STATUS_SUCCESS
) ? Received
: 0;
144 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
148 if( Connection
->SignalState
& (SEL_WRITE
| SEL_FIN
) ) {
149 TI_DbgPrint(DEBUG_TCP
,("Writeable: irp list %s\n",
150 IsListEmpty(&Connection
->SendRequest
) ?
151 "empty" : "nonempty"));
153 while (!IsListEmpty(&Connection
->SendRequest
)) {
154 OSK_UINT SendLen
= 0, Sent
= 0;
155 PVOID SendBuffer
= 0;
157 Entry
= RemoveHeadList( &Connection
->SendRequest
);
159 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
161 Irp
= Bucket
->Request
.RequestContext
;
162 Mdl
= Irp
->MdlAddress
;
164 TI_DbgPrint(DEBUG_TCP
,
165 ("Getting the user buffer from %x\n", Mdl
));
167 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
169 TI_DbgPrint(DEBUG_TCP
,
170 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
172 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
175 ("Connection->SocketContext: %x\n",
176 Connection
->SocketContext
));
178 Status
= TCPTranslateError
179 ( OskitTCPSend( Connection
->SocketContext
,
185 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", Sent
));
187 if( Status
== STATUS_PENDING
&& !(Connection
->SignalState
& SEL_FIN
) ) {
188 InsertHeadList( &Connection
->SendRequest
, &Bucket
->Entry
);
191 TI_DbgPrint(DEBUG_TCP
,
192 ("Completing Send request: %x %x\n",
193 Bucket
->Request
, Status
));
195 Bucket
->Status
= (Status
== STATUS_PENDING
) ? STATUS_CANCELLED
: Status
;
196 Bucket
->Information
= (Bucket
->Status
== STATUS_SUCCESS
) ? Sent
: 0;
198 InsertTailList(&Connection
->CompletionQueue
, &Bucket
->Entry
);
203 ReferenceObject(Connection
);
204 if (ClientInfo
.Unlocked
)
206 UnlockObjectFromDpcLevel(Connection
);
207 KeReleaseSpinLock(&ClientInfo
.Lock
, ClientInfo
.OldIrql
);
211 UnlockObject(Connection
, Connection
->OldIrql
);
214 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->CompletionQueue
,
217 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
218 Complete
= Bucket
->Request
.RequestNotifyObject
;
220 Complete(Bucket
->Request
.RequestContext
, Bucket
->Status
, Bucket
->Information
);
222 ExFreePoolWithTag(Bucket
, TDI_BUCKET_TAG
);
225 if (!ClientInfo
.Unlocked
)
227 LockObject(Connection
, &OldIrql
);
231 KeAcquireSpinLock(&ClientInfo
.Lock
, &ClientInfo
.OldIrql
);
233 DereferenceObject(Connection
);
235 /* If the socket is dead, remove the reference we added for oskit */
236 if (Connection
->SignalState
& SEL_FIN
)
238 Connection
->SocketContext
= NULL
;
239 DereferenceObject(Connection
);
243 VOID
ConnectionFree(PVOID Object
) {
244 PCONNECTION_ENDPOINT Connection
= Object
;
247 TI_DbgPrint(DEBUG_TCP
, ("Freeing TCP Endpoint\n"));
249 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
250 RemoveEntryList(&Connection
->ListEntry
);
251 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
253 ExFreePoolWithTag( Connection
, CONN_ENDPT_TAG
);
256 PCONNECTION_ENDPOINT
TCPAllocateConnectionEndpoint( PVOID ClientContext
) {
257 PCONNECTION_ENDPOINT Connection
=
258 ExAllocatePoolWithTag(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
),
263 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
265 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
267 /* Initialize spin lock that protects the connection endpoint file object */
268 KeInitializeSpinLock(&Connection
->Lock
);
269 InitializeListHead(&Connection
->ConnectRequest
);
270 InitializeListHead(&Connection
->ListenRequest
);
271 InitializeListHead(&Connection
->ReceiveRequest
);
272 InitializeListHead(&Connection
->SendRequest
);
273 InitializeListHead(&Connection
->CompletionQueue
);
275 /* Save client context pointer */
276 Connection
->ClientContext
= ClientContext
;
278 /* Add an extra reference for oskit */
279 Connection
->RefCount
= 2;
280 Connection
->Free
= ConnectionFree
;
282 /* Add connection endpoint to global list */
283 ExInterlockedInsertTailList(&ConnectionEndpointListHead
,
284 &Connection
->ListEntry
,
285 &ConnectionEndpointListLock
);
290 NTSTATUS
TCPSocket( PCONNECTION_ENDPOINT Connection
,
291 UINT Family
, UINT Type
, UINT Proto
) {
295 LockObject(Connection
, &OldIrql
);
297 TI_DbgPrint(DEBUG_TCP
,("Called: Connection %x, Family %d, Type %d, "
299 Connection
, Family
, Type
, Proto
));
301 Status
= TCPTranslateError( OskitTCPSocket( Connection
,
302 &Connection
->SocketContext
,
307 ASSERT_KM_POINTER(Connection
->SocketContext
);
309 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext %x\n",
310 Connection
->SocketContext
));
312 UnlockObject(Connection
, OldIrql
);
317 VOID
TCPReceive(PIP_INTERFACE Interface
, PIP_PACKET IPPacket
)
319 * FUNCTION: Receives and queues TCP data
321 * IPPacket = Pointer to an IP packet that was received
323 * This is the low level interface for receiving TCP data
328 TI_DbgPrint(DEBUG_TCP
,("Sending packet %d (%d) to oskit\n",
330 IPPacket
->HeaderSize
));
332 KeAcquireSpinLock(&ClientInfo
.Lock
, &OldIrql
);
333 ClientInfo
.Unlocked
= TRUE
;
334 ClientInfo
.OldIrql
= OldIrql
;
336 OskitTCPReceiveDatagram( IPPacket
->Header
,
338 IPPacket
->HeaderSize
);
340 ClientInfo
.Unlocked
= FALSE
;
341 KeReleaseSpinLock(&ClientInfo
.Lock
, OldIrql
);
345 int TCPSocketState( void *ClientData
,
347 void *WhichConnection
,
350 int TCPPacketSend( void *ClientData
,
354 POSK_IFADDR
TCPFindInterface( void *ClientData
,
357 OSK_SOCKADDR
*ReqAddr
);
359 NTSTATUS
TCPMemStartup( void );
360 void *TCPMalloc( void *ClientData
,
361 OSK_UINT bytes
, OSK_PCHAR file
, OSK_UINT line
);
362 void TCPFree( void *ClientData
,
363 void *data
, OSK_PCHAR file
, OSK_UINT line
);
364 void TCPMemShutdown( void );
366 OSKITTCP_EVENT_HANDLERS EventHandlers
= {
367 NULL
, /* Client Data */
368 TCPSocketState
, /* SocketState */
369 TCPPacketSend
, /* PacketSend */
370 TCPFindInterface
, /* FindInterface */
371 TCPMalloc
, /* Malloc */
377 static KEVENT TimerLoopEvent
;
378 static HANDLE TimerThreadHandle
;
381 * We are running 2 timers here, one with a 200ms interval (fast) and the other
382 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
383 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
384 * "slow" events at 500 and 1000.
387 TimerThread(PVOID Context
)
389 LARGE_INTEGER Timeout
;
391 unsigned Current
, NextFast
, NextSlow
, Next
;
398 if (Next
== NextFast
) {
401 if (Next
== NextSlow
) {
404 Next
= min(NextFast
, NextSlow
);
405 Timeout
.QuadPart
= (LONGLONG
) (Next
- Current
) * -1000000; /* 100 ms */
406 Status
= KeWaitForSingleObject(&TimerLoopEvent
, Executive
, KernelMode
,
408 if (Status
!= STATUS_TIMEOUT
) {
409 PsTerminateSystemThread(Status
);
412 TimerOskitTCP( Next
== NextFast
, Next
== NextSlow
);
427 KeInitializeEvent(&TimerLoopEvent
, NotificationEvent
, FALSE
);
428 PsCreateSystemThread(&TimerThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0,
432 NTSTATUS
TCPStartup(VOID
)
434 * FUNCTION: Initializes the TCP subsystem
436 * Status of operation
441 Status
= TCPMemStartup();
442 if ( ! NT_SUCCESS(Status
) ) {
446 Status
= PortsStartup( &TCPPorts
, 1, 0xfffe );
447 if( !NT_SUCCESS(Status
) ) {
452 KeInitializeSpinLock(&ClientInfo
.Lock
);
453 ClientInfo
.Unlocked
= FALSE
;
455 RegisterOskitTCPEventHandlers( &EventHandlers
);
458 /* Register this protocol with IP layer */
459 IPRegisterProtocol(IPPROTO_TCP
, TCPReceive
);
461 ExInitializeNPagedLookasideList(
462 &TCPSegmentList
, /* Lookaside list */
463 NULL
, /* Allocate routine */
464 NULL
, /* Free routine */
466 sizeof(TCP_SEGMENT
), /* Size of each entry */
472 TCPInitialized
= TRUE
;
474 return STATUS_SUCCESS
;
478 NTSTATUS
TCPShutdown(VOID
)
480 * FUNCTION: Shuts down the TCP subsystem
482 * Status of operation
485 LARGE_INTEGER WaitForThread
;
488 return STATUS_SUCCESS
;
490 WaitForThread
.QuadPart
= -2500000; /* 250 ms */
491 KeSetEvent(&TimerLoopEvent
, IO_NO_INCREMENT
, FALSE
);
492 ZwWaitForSingleObject(TimerThreadHandle
, FALSE
, &WaitForThread
);
494 /* Deregister this protocol with IP layer */
495 IPRegisterProtocol(IPPROTO_TCP
, NULL
);
497 ExDeleteNPagedLookasideList(&TCPSegmentList
);
499 TCPInitialized
= FALSE
;
503 PortsShutdown( &TCPPorts
);
507 return STATUS_SUCCESS
;
510 NTSTATUS
TCPTranslateError( int OskitError
) {
513 switch( OskitError
) {
514 case 0: Status
= STATUS_SUCCESS
; break;
515 case OSK_EADDRNOTAVAIL
: Status
= STATUS_INVALID_ADDRESS
; break;
516 case OSK_EADDRINUSE
: Status
= STATUS_ADDRESS_ALREADY_EXISTS
; break;
517 case OSK_EAFNOSUPPORT
: Status
= STATUS_INVALID_CONNECTION
; break;
518 case OSK_ECONNREFUSED
: Status
= STATUS_REMOTE_NOT_LISTENING
; break;
519 case OSK_ECONNRESET
: Status
= STATUS_REMOTE_DISCONNECT
; break;
520 case OSK_ECONNABORTED
: Status
= STATUS_LOCAL_DISCONNECT
; break;
521 case OSK_EWOULDBLOCK
:
522 case OSK_EINPROGRESS
: Status
= STATUS_PENDING
; break;
523 case OSK_EINVAL
: Status
= STATUS_INVALID_PARAMETER
; break;
525 case OSK_ENOBUFS
: Status
= STATUS_INSUFFICIENT_RESOURCES
; break;
526 case OSK_ESHUTDOWN
: Status
= STATUS_FILE_CLOSED
; break;
527 case OSK_EMSGSIZE
: Status
= STATUS_BUFFER_TOO_SMALL
; break;
528 case OSK_ETIMEDOUT
: Status
= STATUS_TIMEOUT
; break;
529 case OSK_ENETUNREACH
: Status
= STATUS_NETWORK_UNREACHABLE
; break;
530 case OSK_EFAULT
: Status
= STATUS_ACCESS_VIOLATION
; break;
532 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError
);
533 Status
= STATUS_INVALID_CONNECTION
;
537 TI_DbgPrint(DEBUG_TCP
,("Error %d -> %x\n", OskitError
, Status
));
542 ( PCONNECTION_ENDPOINT Connection
,
543 PTDI_CONNECTION_INFORMATION ConnInfo
,
544 PTDI_CONNECTION_INFORMATION ReturnInfo
,
545 PTCP_COMPLETION_ROUTINE Complete
,
548 SOCKADDR_IN AddressToConnect
= { 0 }, AddressToBind
= { 0 };
549 IP_ADDRESS RemoteAddress
;
552 PNEIGHBOR_CACHE_ENTRY NCE
;
555 TI_DbgPrint(DEBUG_TCP
,("TCPConnect: Called\n"));
557 Status
= AddrBuildAddress
558 ((PTRANSPORT_ADDRESS
)ConnInfo
->RemoteAddress
,
562 if (!NT_SUCCESS(Status
)) {
563 TI_DbgPrint(DEBUG_TCP
, ("Could not AddrBuildAddress in TCPConnect\n"));
567 /* Freed in TCPSocketState */
568 TI_DbgPrint(DEBUG_TCP
,
569 ("Connecting to address %x:%x\n",
570 RemoteAddress
.Address
.IPv4Address
,
573 AddressToConnect
.sin_family
= AF_INET
;
574 AddressToBind
= AddressToConnect
;
576 LockObject(Connection
, &OldIrql
);
578 if (!Connection
->AddressFile
)
580 UnlockObject(Connection
, OldIrql
);
581 return STATUS_INVALID_PARAMETER
;
584 if (AddrIsUnspecified(&Connection
->AddressFile
->Address
))
586 if (!(NCE
= RouteGetRouteToDestination(&RemoteAddress
)))
588 UnlockObject(Connection
, OldIrql
);
589 return STATUS_NETWORK_UNREACHABLE
;
592 AddressToBind
.sin_addr
.s_addr
= NCE
->Interface
->Unicast
.Address
.IPv4Address
;
596 AddressToBind
.sin_addr
.s_addr
= Connection
->AddressFile
->Address
.Address
.IPv4Address
;
599 Status
= TCPTranslateError
600 ( OskitTCPBind( Connection
->SocketContext
,
602 sizeof(AddressToBind
) ) );
604 if (NT_SUCCESS(Status
)) {
605 memcpy( &AddressToConnect
.sin_addr
,
606 &RemoteAddress
.Address
.IPv4Address
,
607 sizeof(AddressToConnect
.sin_addr
) );
608 AddressToConnect
.sin_port
= RemotePort
;
610 Status
= TCPTranslateError
611 ( OskitTCPConnect( Connection
->SocketContext
,
613 sizeof(AddressToConnect
) ) );
615 if (Status
== STATUS_PENDING
)
617 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
620 UnlockObject(Connection
, OldIrql
);
621 return STATUS_NO_MEMORY
;
624 Bucket
->Request
.RequestNotifyObject
= (PVOID
)Complete
;
625 Bucket
->Request
.RequestContext
= Context
;
627 InsertTailList( &Connection
->ConnectRequest
, &Bucket
->Entry
);
631 UnlockObject(Connection
, OldIrql
);
636 NTSTATUS TCPDisconnect
637 ( PCONNECTION_ENDPOINT Connection
,
639 PTDI_CONNECTION_INFORMATION ConnInfo
,
640 PTDI_CONNECTION_INFORMATION ReturnInfo
,
641 PTCP_COMPLETION_ROUTINE Complete
,
643 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
646 TI_DbgPrint(DEBUG_TCP
,("started\n"));
648 LockObject(Connection
, &OldIrql
);
650 if (Flags
& TDI_DISCONNECT_RELEASE
)
651 Status
= TCPTranslateError(OskitTCPDisconnect(Connection
->SocketContext
));
653 if ((Flags
& TDI_DISCONNECT_ABORT
) || !Flags
)
654 Status
= TCPTranslateError(OskitTCPShutdown(Connection
->SocketContext
, FWRITE
| FREAD
));
656 UnlockObject(Connection
, OldIrql
);
658 TI_DbgPrint(DEBUG_TCP
,("finished %x\n", Status
));
664 ( PCONNECTION_ENDPOINT Connection
)
669 PADDRESS_FILE AddressFile
= NULL
;
670 PCONNECTION_ENDPOINT AddressConnection
= NULL
;
672 LockObject(Connection
, &OldIrql
);
673 Socket
= Connection
->SocketContext
;
674 Connection
->SocketContext
= NULL
;
676 /* Don't try to close again if the other side closed us already */
679 /* We need to close here otherwise oskit will never indicate
680 * SEL_FIN and we will never fully close the connection */
681 Status
= TCPTranslateError( OskitTCPClose( Socket
) );
683 if (!NT_SUCCESS(Status
))
685 Connection
->SocketContext
= Socket
;
686 UnlockObject(Connection
, OldIrql
);
692 /* We are already closed by the other end so return success */
693 Status
= STATUS_SUCCESS
;
696 if (Connection
->AddressFile
)
698 LockObjectAtDpcLevel(Connection
->AddressFile
);
699 if (Connection
->AddressFile
->Connection
== Connection
)
701 AddressConnection
= Connection
->AddressFile
->Connection
;
702 Connection
->AddressFile
->Connection
= NULL
;
704 UnlockObjectFromDpcLevel(Connection
->AddressFile
);
706 AddressFile
= Connection
->AddressFile
;
707 Connection
->AddressFile
= NULL
;
710 UnlockObject(Connection
, OldIrql
);
712 DereferenceObject(Connection
);
713 if (AddressConnection
)
714 DereferenceObject(AddressConnection
);
716 DereferenceObject(AddressFile
);
721 NTSTATUS TCPReceiveData
722 ( PCONNECTION_ENDPOINT Connection
,
725 PULONG BytesReceived
,
727 PTCP_COMPLETION_ROUTINE Complete
,
730 UINT DataLen
, Received
= 0;
735 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
736 ReceiveLength
, Connection
->SocketContext
));
738 NdisQueryBuffer( Buffer
, &DataBuffer
, &DataLen
);
740 TI_DbgPrint(DEBUG_TCP
,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer
, DataBuffer
, DataLen
));
742 LockObject(Connection
, &OldIrql
);
744 Status
= TCPTranslateError
746 ( Connection
->SocketContext
,
752 TI_DbgPrint(DEBUG_TCP
,("OskitTCPReceive: %x, %d\n", Status
, Received
));
754 /* Keep this request around ... there was no data yet */
755 if( Status
== STATUS_PENDING
) {
756 /* Freed in TCPSocketState */
757 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
759 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
760 UnlockObject(Connection
, OldIrql
);
761 return STATUS_NO_MEMORY
;
764 Bucket
->Request
.RequestNotifyObject
= Complete
;
765 Bucket
->Request
.RequestContext
= Context
;
768 InsertTailList( &Connection
->ReceiveRequest
, &Bucket
->Entry
);
769 TI_DbgPrint(DEBUG_TCP
,("Queued read irp\n"));
771 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Received
));
772 *BytesReceived
= Received
;
775 UnlockObject(Connection
, OldIrql
);
777 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
783 ( PCONNECTION_ENDPOINT Connection
,
788 PTCP_COMPLETION_ROUTINE Complete
,
795 LockObject(Connection
, &OldIrql
);
797 TI_DbgPrint(DEBUG_TCP
,("Called for %d bytes (on socket %x)\n",
798 SendLength
, Connection
->SocketContext
));
800 TI_DbgPrint(DEBUG_TCP
,("Connection = %x\n", Connection
));
801 TI_DbgPrint(DEBUG_TCP
,("Connection->SocketContext = %x\n",
802 Connection
->SocketContext
));
804 Status
= TCPTranslateError
805 ( OskitTCPSend( Connection
->SocketContext
,
806 (OSK_PCHAR
)BufferData
, SendLength
,
809 TI_DbgPrint(DEBUG_TCP
,("OskitTCPSend: %x, %d\n", Status
, Sent
));
811 /* Keep this request around ... there was no data yet */
812 if( Status
== STATUS_PENDING
) {
813 /* Freed in TCPSocketState */
814 Bucket
= ExAllocatePoolWithTag( NonPagedPool
, sizeof(*Bucket
), TDI_BUCKET_TAG
);
816 UnlockObject(Connection
, OldIrql
);
817 TI_DbgPrint(DEBUG_TCP
,("Failed to allocate bucket\n"));
818 return STATUS_NO_MEMORY
;
821 Bucket
->Request
.RequestNotifyObject
= Complete
;
822 Bucket
->Request
.RequestContext
= Context
;
825 InsertTailList( &Connection
->SendRequest
, &Bucket
->Entry
);
826 TI_DbgPrint(DEBUG_TCP
,("Queued write irp\n"));
828 TI_DbgPrint(DEBUG_TCP
,("Got status %x, bytes %d\n", Status
, Sent
));
832 UnlockObject(Connection
, OldIrql
);
834 TI_DbgPrint(DEBUG_TCP
,("Status %x\n", Status
));
839 UINT
TCPAllocatePort( UINT HintPort
) {
841 if( AllocatePort( &TCPPorts
, HintPort
) ) return HintPort
;
844 (MID_TRACE
,("We got a hint port but couldn't allocate it\n"));
847 } else return AllocatePortFromRange( &TCPPorts
, 1024, 5000 );
850 VOID
TCPFreePort( UINT Port
) {
851 DeallocatePort( &TCPPorts
, Port
);
854 NTSTATUS TCPGetSockAddress
855 ( PCONNECTION_ENDPOINT Connection
,
856 PTRANSPORT_ADDRESS Address
,
857 BOOLEAN GetRemote
) {
858 OSK_UINT LocalAddress
, RemoteAddress
;
859 OSK_UI16 LocalPort
, RemotePort
;
860 PTA_IP_ADDRESS AddressIP
= (PTA_IP_ADDRESS
)Address
;
864 LockObject(Connection
, &OldIrql
);
866 Status
= TCPTranslateError(OskitTCPGetAddress(Connection
->SocketContext
,
867 &LocalAddress
, &LocalPort
,
868 &RemoteAddress
, &RemotePort
));
870 UnlockObject(Connection
, OldIrql
);
872 if (!NT_SUCCESS(Status
))
875 AddressIP
->TAAddressCount
= 1;
876 AddressIP
->Address
[0].AddressLength
= TDI_ADDRESS_LENGTH_IP
;
877 AddressIP
->Address
[0].AddressType
= TDI_ADDRESS_TYPE_IP
;
878 AddressIP
->Address
[0].Address
[0].sin_port
= GetRemote
? RemotePort
: LocalPort
;
879 AddressIP
->Address
[0].Address
[0].in_addr
= GetRemote
? RemoteAddress
: LocalAddress
;
884 BOOLEAN
TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint
, PIRP Irp
) {
886 PLIST_ENTRY ListHead
[4];
890 BOOLEAN Found
= FALSE
;
892 ListHead
[0] = &Endpoint
->SendRequest
;
893 ListHead
[1] = &Endpoint
->ReceiveRequest
;
894 ListHead
[2] = &Endpoint
->ConnectRequest
;
895 ListHead
[3] = &Endpoint
->ListenRequest
;
897 LockObject(Endpoint
, &OldIrql
);
899 for( i
= 0; i
< 4; i
++ )
901 for( Entry
= ListHead
[i
]->Flink
;
902 Entry
!= ListHead
[i
];
903 Entry
= Entry
->Flink
)
905 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
906 if( Bucket
->Request
.RequestContext
== Irp
)
908 RemoveEntryList( &Bucket
->Entry
);
909 ExFreePoolWithTag( Bucket
, TDI_BUCKET_TAG
);
916 UnlockObject(Endpoint
, OldIrql
);