1 /*
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)
8  * REVISIONS:
9  *   CSH 01/08-2000  Created
10  *   arty 12/21/2004 Added accept
11  */
12 
13 #include "precomp.h"
14 
15 LONG TCP_IPIdentification = 0;
16 static BOOLEAN TCPInitialized = FALSE;
17 PORT_SET TCPPorts;
18 
19 #include "lwip/pbuf.h"
20 #include "lwip/ip.h"
21 #include "lwip/init.h"
22 #include "lwip/arch.h"
23 
24 #include <lwip_glue/lwip_glue.h>
25 
26 NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
27 
28 static
29 IO_WORKITEM_ROUTINE
30 DisconnectWorker;
31 
32 _Use_decl_annotations_
33 VOID
34 NTAPI
DisconnectWorker(_Unreferenced_parameter_ PDEVICE_OBJECT DeviceObject,_In_ PVOID Context)35 DisconnectWorker(
36     _Unreferenced_parameter_ PDEVICE_OBJECT DeviceObject,
37     _In_ PVOID Context
38 )
39 {
40     PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Context;
41     PLIST_ENTRY Entry;
42     PTDI_BUCKET Bucket;
43 
44     /* We timed out waiting for pending sends so force it to shutdown */
45     TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
46 
47     LockObject(Connection);
48 
49     while (!IsListEmpty(&Connection->SendRequest))
50     {
51         Entry = RemoveHeadList(&Connection->SendRequest);
52 
53         Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
54 
55         Bucket->Information = 0;
56         Bucket->Status = STATUS_FILE_CLOSED;
57 
58         CompleteBucket(Connection, Bucket, FALSE);
59     }
60 
61     while (!IsListEmpty(&Connection->ShutdownRequest))
62     {
63         Entry = RemoveHeadList( &Connection->ShutdownRequest );
64 
65         Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
66 
67         Bucket->Status = STATUS_TIMEOUT;
68         Bucket->Information = 0;
69 
70         CompleteBucket(Connection, Bucket, FALSE);
71     }
72 
73     UnlockObject(Connection);
74 
75     DereferenceObject(Connection);
76 }
77 
78 VOID
79 NTAPI
DisconnectTimeoutDpc(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)80 DisconnectTimeoutDpc(PKDPC Dpc,
81                      PVOID DeferredContext,
82                      PVOID SystemArgument1,
83                      PVOID SystemArgument2)
84 {
85     PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext;
86 
87     IoQueueWorkItem(Connection->DisconnectWorkItem, DisconnectWorker, DelayedWorkQueue, Connection);
88 }
89 
ConnectionFree(PVOID Object)90 VOID ConnectionFree(PVOID Object)
91 {
92     PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object;
93     KIRQL OldIrql;
94 
95     TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
96 
97     TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
98     RemoveEntryList(&Connection->ListEntry);
99     TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
100 
101     ExDeleteResourceLite(&Connection->Resource);
102     IoFreeWorkItem(Connection->DisconnectWorkItem);
103 
104     ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
105 }
106 
TCPAllocateConnectionEndpoint(PVOID ClientContext)107 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext )
108 {
109     PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)
110         ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT), CONN_ENDPT_TAG);
111 
112     if (!Connection)
113         return Connection;
114 
115     TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
116 
117     RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
118 
119     /* Initialize spin lock that protects the connection endpoint file object */
120     ExInitializeResourceLite(&Connection->Resource);
121     InitializeListHead(&Connection->ConnectRequest);
122     InitializeListHead(&Connection->ListenRequest);
123     InitializeListHead(&Connection->ReceiveRequest);
124     InitializeListHead(&Connection->SendRequest);
125     InitializeListHead(&Connection->ShutdownRequest);
126     InitializeListHead(&Connection->PacketQueue);
127 
128     /* Initialize disconnect timer */
129     KeInitializeTimer(&Connection->DisconnectTimer);
130     KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection);
131     Connection->DisconnectWorkItem = IoAllocateWorkItem(TCPDeviceObject);
132     if (!Connection->DisconnectWorkItem)
133     {
134         ExDeleteResourceLite(&Connection->Resource);
135         ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
136         return NULL;
137     }
138 
139     /* Save client context pointer */
140     Connection->ClientContext = ClientContext;
141 
142     Connection->RefCount = 1;
143     Connection->Free = ConnectionFree;
144 
145     /* Add connection endpoint to global list */
146     ExInterlockedInsertTailList(&ConnectionEndpointListHead,
147                                 &Connection->ListEntry,
148                                 &ConnectionEndpointListLock);
149 
150     return Connection;
151 }
152 
TCPSocket(PCONNECTION_ENDPOINT Connection,UINT Family,UINT Type,UINT Proto)153 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
154                     UINT Family, UINT Type, UINT Proto )
155 {
156     NTSTATUS Status;
157 
158     LockObject(Connection);
159 
160     TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Called: Connection %x, Family %d, Type %d, "
161                            "Proto %d, sizeof(CONNECTION_ENDPOINT) = %d\n",
162                            Connection, Family, Type, Proto, sizeof(CONNECTION_ENDPOINT)));
163 
164     Connection->SocketContext = LibTCPSocket(Connection);
165     if (Connection->SocketContext)
166         Status = STATUS_SUCCESS;
167     else
168         Status = STATUS_INSUFFICIENT_RESOURCES;
169 
170     UnlockObject(Connection);
171 
172     TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Leaving. Status = 0x%x\n", Status));
173 
174     return Status;
175 }
176 
TCPClose(PCONNECTION_ENDPOINT Connection)177 NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection )
178 {
179     LockObject(Connection);
180 
181     FlushAllQueues(Connection, STATUS_CANCELLED);
182 
183     UnlockObject(Connection);
184 
185     LibTCPClose(Connection, FALSE, TRUE);
186 
187     DereferenceObject(Connection);
188 
189     return STATUS_SUCCESS;
190 }
191 
TCPReceive(PIP_INTERFACE Interface,PIP_PACKET IPPacket)192 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
193 /*
194  * FUNCTION: Receives and queues TCP data
195  * ARGUMENTS:
196  *     IPPacket = Pointer to an IP packet that was received
197  * NOTES:
198  *     This is the low level interface for receiving TCP data
199  */
200 {
201     TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n",
202                            IPPacket->TotalSize,
203                            IPPacket->HeaderSize));
204 
205     LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize);
206 }
207 
TCPStartup(VOID)208 NTSTATUS TCPStartup(VOID)
209 /*
210  * FUNCTION: Initializes the TCP subsystem
211  * RETURNS:
212  *     Status of operation
213  */
214 {
215     NTSTATUS Status;
216 
217     Status = PortsStartup(&TCPPorts, 1, 0xffff);
218     if (!NT_SUCCESS(Status))
219     {
220         return Status;
221     }
222 
223     ExInitializeNPagedLookasideList(&TdiBucketLookasideList,
224                                     NULL,
225                                     NULL,
226                                     0,
227                                     sizeof(TDI_BUCKET),
228                                     TDI_BUCKET_TAG,
229                                     0);
230 
231     /* Initialize our IP library */
232     LibIPInitialize();
233 
234     /* Register this protocol with IP layer */
235     IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
236 
237     TCPInitialized = TRUE;
238 
239     return STATUS_SUCCESS;
240 }
241 
242 
TCPShutdown(VOID)243 NTSTATUS TCPShutdown(VOID)
244 /*
245  * FUNCTION: Shuts down the TCP subsystem
246  * RETURNS:
247  *     Status of operation
248  */
249 {
250     if (!TCPInitialized)
251         return STATUS_SUCCESS;
252 
253     ExDeleteNPagedLookasideList(&TdiBucketLookasideList);
254 
255     LibIPShutdown();
256 
257     /* Deregister this protocol with IP layer */
258     IPRegisterProtocol(IPPROTO_TCP, NULL);
259 
260     TCPInitialized = FALSE;
261 
262     PortsShutdown( &TCPPorts );
263 
264     return STATUS_SUCCESS;
265 }
266 
TCPTranslateError(const err_t err)267 NTSTATUS TCPTranslateError(const err_t err)
268 {
269     NTSTATUS Status;
270 
271     switch (err)
272     {
273         case ERR_OK: Status = STATUS_SUCCESS; return Status; //0
274         case ERR_MEM: Status = STATUS_INSUFFICIENT_RESOURCES; break; //-1
275         case ERR_BUF: Status = STATUS_BUFFER_TOO_SMALL; break; //-2
276         case ERR_TIMEOUT: Status = STATUS_TIMEOUT; break; // -3
277         case ERR_RTE: Status = STATUS_NETWORK_UNREACHABLE; break; //-4
278         case ERR_INPROGRESS: Status = STATUS_PENDING; return Status; //-5
279         case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-6
280         case ERR_WOULDBLOCK: Status = STATUS_CANT_WAIT; break; //-7
281         case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-8
282         case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-9 (FIXME)
283         case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-10
284         case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-11
285         case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-12
286         case ERR_CONN: Status = STATUS_INVALID_CONNECTION; break; //-13
287         case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-14
288         case ERR_IF: Status = STATUS_UNEXPECTED_NETWORK_ERROR; break; //-15
289         default:
290             DbgPrint("Invalid error value: %d\n", err);
291             ASSERT(FALSE);
292             Status = STATUS_UNSUCCESSFUL;
293             break;
294     }
295 
296     TI_DbgPrint(DEBUG_TCP,("TCP operation failed: 0x%x (%d)\n", Status, err));
297 
298     return Status;
299 }
300 
TCPConnect(PCONNECTION_ENDPOINT Connection,PTDI_CONNECTION_INFORMATION ConnInfo,PTDI_CONNECTION_INFORMATION ReturnInfo,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)301 NTSTATUS TCPConnect
302 ( PCONNECTION_ENDPOINT Connection,
303   PTDI_CONNECTION_INFORMATION ConnInfo,
304   PTDI_CONNECTION_INFORMATION ReturnInfo,
305   PTCP_COMPLETION_ROUTINE Complete,
306   PVOID Context )
307 {
308     NTSTATUS Status;
309     ip_addr_t bindaddr, connaddr;
310     IP_ADDRESS RemoteAddress;
311     USHORT RemotePort;
312     TA_IP_ADDRESS LocalAddress;
313     PTDI_BUCKET Bucket;
314     PNEIGHBOR_CACHE_ENTRY NCE;
315 
316     TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n"));
317 
318     Status = AddrBuildAddress
319         ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
320          &RemoteAddress,
321          &RemotePort);
322 
323     if (!NT_SUCCESS(Status))
324     {
325         TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
326         return Status;
327     }
328 
329     /* Freed in TCPSocketState */
330     TI_DbgPrint(DEBUG_TCP,
331                 ("Connecting to address %x:%x\n",
332                  RemoteAddress.Address.IPv4Address,
333                  RemotePort));
334 
335     LockObject(Connection);
336 
337     if (!Connection->AddressFile)
338     {
339         UnlockObject(Connection);
340         return STATUS_INVALID_PARAMETER;
341     }
342 
343     if (AddrIsUnspecified(&Connection->AddressFile->Address))
344     {
345         if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
346         {
347             UnlockObject(Connection);
348             return STATUS_NETWORK_UNREACHABLE;
349         }
350 
351         bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address;
352     }
353     else
354     {
355         bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address;
356     }
357 
358     Status = TCPTranslateError(LibTCPBind(Connection,
359                                           &bindaddr,
360                                           Connection->AddressFile->Port));
361 
362     if (!NT_SUCCESS(Status))
363     {
364         UnlockObject(Connection);
365         return Status;
366     }
367 
368     /* Copy bind address into connection */
369     Connection->AddressFile->Address.Address.IPv4Address = bindaddr.addr;
370     /* Check if we had an unspecified port */
371     if (!Connection->AddressFile->Port)
372     {
373         UINT AllocatedPort;
374 
375         /* We did, so we need to copy back the port */
376         Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
377         if (!NT_SUCCESS(Status))
378         {
379             UnlockObject(Connection);
380             return Status;
381         }
382 
383         /* Allocate the port in the port bitmap */
384         AllocatedPort = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
385         /* This should never fail unless all ports are in use */
386         if (AllocatedPort == (UINT) -1)
387         {
388             DbgPrint("ERR: No more ports available.\n");
389             UnlockObject(Connection);
390             return STATUS_TOO_MANY_ADDRESSES;
391         }
392         Connection->AddressFile->Port = AllocatedPort;
393     }
394 
395     connaddr.addr = RemoteAddress.Address.IPv4Address;
396 
397     Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
398     if (!Bucket)
399     {
400         UnlockObject(Connection);
401         return STATUS_NO_MEMORY;
402     }
403 
404     Bucket->Request.RequestNotifyObject = (PVOID)Complete;
405     Bucket->Request.RequestContext = Context;
406 
407     InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
408 
409     UnlockObject(Connection);
410 
411     Status = TCPTranslateError(LibTCPConnect(Connection,
412                                                 &connaddr,
413                                                 RemotePort));
414     if (!NT_SUCCESS(Status))
415     {
416         LockObject(Connection);
417         RemoveEntryList(&Bucket->Entry);
418         UnlockObject(Connection);
419         ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
420     }
421     TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status));
422 
423     return Status;
424 }
425 
TCPDisconnect(PCONNECTION_ENDPOINT Connection,UINT Flags,PLARGE_INTEGER Timeout,PTDI_CONNECTION_INFORMATION ConnInfo,PTDI_CONNECTION_INFORMATION ReturnInfo,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)426 NTSTATUS TCPDisconnect
427 ( PCONNECTION_ENDPOINT Connection,
428   UINT Flags,
429   PLARGE_INTEGER Timeout,
430   PTDI_CONNECTION_INFORMATION ConnInfo,
431   PTDI_CONNECTION_INFORMATION ReturnInfo,
432   PTCP_COMPLETION_ROUTINE Complete,
433   PVOID Context )
434 {
435     NTSTATUS Status = STATUS_INVALID_PARAMETER;
436     PTDI_BUCKET Bucket;
437     LARGE_INTEGER ActualTimeout;
438 
439     TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));
440 
441     LockObject(Connection);
442 
443     if (Connection->SocketContext)
444     {
445         if (Flags & TDI_DISCONNECT_RELEASE)
446         {
447             if (IsListEmpty(&Connection->SendRequest))
448             {
449                 ReferenceObject(Connection);
450                 UnlockObject(Connection);
451                 Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
452                 LockObject(Connection);
453                 DereferenceObject(Connection);
454             }
455             else if (Timeout && Timeout->QuadPart == 0)
456             {
457                 FlushSendQueue(Connection, STATUS_FILE_CLOSED);
458                 ReferenceObject(Connection);
459                 UnlockObject(Connection);
460                 LibTCPShutdown(Connection, 0, 1);
461                 LockObject(Connection);
462                 DereferenceObject(Connection);
463                 Status = STATUS_TIMEOUT;
464             }
465             else
466             {
467                 /* Use the timeout specified or 1 second if none was specified */
468                 if (Timeout)
469                 {
470                     ActualTimeout = *Timeout;
471                 }
472                 else
473                 {
474                     ActualTimeout.QuadPart = -1000000;
475                 }
476 
477                 /* We couldn't complete the request now because we need to wait for outstanding I/O */
478                 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
479                 if (!Bucket)
480                 {
481                     UnlockObject(Connection);
482                     return STATUS_NO_MEMORY;
483                 }
484 
485                 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
486                 Bucket->Request.RequestContext = Context;
487 
488                 InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry);
489 
490                 ReferenceObject(Connection);
491                 if (KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc))
492                 {
493                     /* Timer was already in the queue. */
494                     DereferenceObject(Connection);
495                 }
496 
497                 Status = STATUS_PENDING;
498             }
499         }
500 
501         if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
502         {
503             FlushReceiveQueue(Connection, STATUS_FILE_CLOSED);
504             FlushSendQueue(Connection, STATUS_FILE_CLOSED);
505             FlushShutdownQueue(Connection, STATUS_FILE_CLOSED);
506             ReferenceObject(Connection);
507             UnlockObject(Connection);
508             Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
509             DereferenceObject(Connection);
510         }
511         else
512         {
513             UnlockObject(Connection);
514         }
515     }
516     else
517     {
518         UnlockObject(Connection);
519         /* We already got closed by the other side so just return success */
520         Status = STATUS_SUCCESS;
521     }
522 
523     TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));
524 
525     return Status;
526 }
527 
TCPReceiveData(PCONNECTION_ENDPOINT Connection,PNDIS_BUFFER Buffer,ULONG ReceiveLength,PULONG BytesReceived,ULONG ReceiveFlags,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)528 NTSTATUS TCPReceiveData
529 ( PCONNECTION_ENDPOINT Connection,
530   PNDIS_BUFFER Buffer,
531   ULONG ReceiveLength,
532   PULONG BytesReceived,
533   ULONG ReceiveFlags,
534   PTCP_COMPLETION_ROUTINE Complete,
535   PVOID Context )
536 {
537     PTDI_BUCKET Bucket;
538     PUCHAR DataBuffer;
539     UINT DataLen, Received;
540     NTSTATUS Status;
541 
542     TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n",
543                            ReceiveLength, Connection->SocketContext));
544 
545     NdisQueryBuffer(Buffer, &DataBuffer, &DataLen);
546 
547     Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received);
548 
549     if (Status == STATUS_PENDING)
550     {
551         Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
552         if (!Bucket)
553         {
554             TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Failed to allocate bucket\n"));
555 
556             return STATUS_NO_MEMORY;
557         }
558 
559         Bucket->Request.RequestNotifyObject = Complete;
560         Bucket->Request.RequestContext = Context;
561 
562         LockObject(Connection);
563         InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
564         UnlockObject(Connection);
565         TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n"));
566 
567         TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n"));
568 
569         (*BytesReceived) = 0;
570     }
571     else
572     {
573         (*BytesReceived) = Received;
574     }
575 
576     return Status;
577 }
578 
TCPSendData(PCONNECTION_ENDPOINT Connection,PCHAR BufferData,ULONG SendLength,PULONG BytesSent,ULONG Flags,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)579 NTSTATUS TCPSendData
580 ( PCONNECTION_ENDPOINT Connection,
581   PCHAR BufferData,
582   ULONG SendLength,
583   PULONG BytesSent,
584   ULONG Flags,
585   PTCP_COMPLETION_ROUTINE Complete,
586   PVOID Context )
587 {
588     NTSTATUS Status;
589     PTDI_BUCKET Bucket;
590 
591     ReferenceObject(Connection);
592 
593     TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n",
594                            SendLength, Connection->SocketContext));
595 
596     TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection));
597     TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n",
598                            Connection->SocketContext));
599 
600     Status = TCPTranslateError(LibTCPSend(Connection,
601                                           BufferData,
602                                           SendLength,
603                                           BytesSent,
604                                           FALSE));
605 
606     TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength));
607 
608     /* Keep this request around ... there was no data yet */
609     if (Status == STATUS_PENDING)
610     {
611         /* Freed in TCPSocketState */
612         Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
613         if (!Bucket)
614         {
615             DereferenceObject(Connection);
616             TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n"));
617             return STATUS_NO_MEMORY;
618         }
619 
620         Bucket->Request.RequestNotifyObject = Complete;
621         Bucket->Request.RequestContext = Context;
622 
623         LockObject(Connection);
624         InsertTailList( &Connection->SendRequest, &Bucket->Entry );
625         TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
626         UnlockObject(Connection);
627     }
628 
629 
630     TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status));
631     DereferenceObject(Connection);
632 
633     return Status;
634 }
635 
TCPAllocatePort(const UINT HintPort)636 UINT TCPAllocatePort(const UINT HintPort)
637 {
638     if (HintPort)
639     {
640         if (AllocatePort(&TCPPorts, HintPort))
641             return HintPort;
642         else
643         {
644             TI_DbgPrint(MID_TRACE,("We got a hint port but couldn't allocate it\n"));
645             return (UINT)-1;
646         }
647     }
648     else
649         return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
650 }
651 
TCPFreePort(const UINT Port)652 VOID TCPFreePort(const UINT Port)
653 {
654     DeallocatePort(&TCPPorts, Port);
655 }
656 
TCPGetSockAddress(PCONNECTION_ENDPOINT Connection,PTRANSPORT_ADDRESS Address,BOOLEAN GetRemote)657 NTSTATUS TCPGetSockAddress
658 ( PCONNECTION_ENDPOINT Connection,
659   PTRANSPORT_ADDRESS Address,
660   BOOLEAN GetRemote )
661 {
662     PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
663     ip_addr_t ipaddr;
664     NTSTATUS Status;
665 
666     AddressIP->TAAddressCount = 1;
667     AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
668     AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
669 
670     LockObject(Connection);
671 
672     if (GetRemote)
673     {
674         Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext,
675                                     &ipaddr,
676                                     &AddressIP->Address[0].Address[0].sin_port));
677     }
678     else
679     {
680         Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext,
681                                     &ipaddr,
682                                     &AddressIP->Address[0].Address[0].sin_port));
683     }
684 
685     UnlockObject(Connection);
686 
687     AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
688 
689     RtlZeroMemory(&AddressIP->Address[0].Address[0].sin_zero,
690                   sizeof(AddressIP->Address[0].Address[0].sin_zero));
691 
692     return Status;
693 }
694 
TCPRemoveIRP(PCONNECTION_ENDPOINT Endpoint,PIRP Irp)695 BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
696 {
697     PLIST_ENTRY Entry;
698     PLIST_ENTRY ListHead[5];
699     PTDI_BUCKET Bucket;
700     UINT i = 0;
701     BOOLEAN Found = FALSE;
702 
703     ListHead[0] = &Endpoint->SendRequest;
704     ListHead[1] = &Endpoint->ReceiveRequest;
705     ListHead[2] = &Endpoint->ConnectRequest;
706     ListHead[3] = &Endpoint->ListenRequest;
707     ListHead[4] = &Endpoint->ShutdownRequest;
708 
709     LockObject(Endpoint);
710 
711     for( i = 0; i < 5; i++ )
712     {
713         for( Entry = ListHead[i]->Flink;
714              Entry != ListHead[i];
715              Entry = Entry->Flink )
716         {
717             Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
718             if( Bucket->Request.RequestContext == Irp )
719             {
720                 RemoveEntryList( &Bucket->Entry );
721                 ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
722                 Found = TRUE;
723                 break;
724             }
725         }
726     }
727 
728     UnlockObject(Endpoint);
729 
730     return Found;
731 }
732 
733 NTSTATUS
TCPSetNoDelay(PCONNECTION_ENDPOINT Connection,BOOLEAN Set)734 TCPSetNoDelay(
735     PCONNECTION_ENDPOINT Connection,
736     BOOLEAN Set)
737 {
738     if (!Connection)
739         return STATUS_UNSUCCESSFUL;
740 
741     if (Connection->SocketContext == NULL)
742         return STATUS_UNSUCCESSFUL;
743 
744     LibTCPSetNoDelay(Connection->SocketContext, Set);
745     return STATUS_SUCCESS;
746 }
747 
748 NTSTATUS
TCPGetSocketStatus(PCONNECTION_ENDPOINT Connection,PULONG State)749 TCPGetSocketStatus(
750     PCONNECTION_ENDPOINT Connection,
751     PULONG State)
752 {
753     if (!Connection)
754         return STATUS_UNSUCCESSFUL;
755 
756     if (Connection->SocketContext == NULL)
757         return STATUS_UNSUCCESSFUL;
758 
759     LibTCPGetSocketStatus(Connection->SocketContext, State);
760     return STATUS_SUCCESS;
761 }
762 
763 /* EOF */
764