1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        transport/tcp/accept.c
5  * PURPOSE:     Transmission Control Protocol Listen/Accept code
6  * PROGRAMMERS: Art Yerkes (arty@users.sf.net)
7  * REVISIONS:
8  *   arty 12/21/2004 Created
9  */
10 
11 #include "precomp.h"
12 
13 #include <lwip_glue/lwip_glue.h>
14 
15 extern NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
16 
17 NTSTATUS TCPCheckPeerForAccept(PVOID Context,
18                                PTDI_REQUEST_KERNEL Request)
19 {
20     struct tcp_pcb *newpcb = (struct tcp_pcb*)Context;
21     NTSTATUS Status;
22     PTDI_CONNECTION_INFORMATION WhoIsConnecting;
23     PTA_IP_ADDRESS RemoteAddress;
24     struct ip_addr ipaddr;
25 
26     if (Request->RequestFlags & TDI_QUERY_ACCEPT)
27         DbgPrint("TDI_QUERY_ACCEPT NOT SUPPORTED!!!\n");
28 
29     WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)Request->ReturnConnectionInformation;
30     RemoteAddress = (PTA_IP_ADDRESS)WhoIsConnecting->RemoteAddress;
31 
32     RemoteAddress->TAAddressCount = 1;
33     RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
34     RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
35 
36     Status = TCPTranslateError(LibTCPGetPeerName(newpcb,
37                                                  &ipaddr,
38                                                  &RemoteAddress->Address[0].Address[0].sin_port));
39 
40     RemoteAddress->Address[0].Address[0].in_addr = ipaddr.addr;
41 
42     return Status;
43 }
44 
45 /* This listen is on a socket we keep as internal.  That socket has the same
46  * lifetime as the address file */
47 NTSTATUS TCPListen(PCONNECTION_ENDPOINT Connection, UINT Backlog)
48 {
49     NTSTATUS Status = STATUS_SUCCESS;
50     struct ip_addr AddressToBind;
51     TA_IP_ADDRESS LocalAddress;
52 
53     ASSERT(Connection);
54 
55     LockObject(Connection);
56 
57     ASSERT_KM_POINTER(Connection->AddressFile);
58 
59     TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Called\n"));
60 
61     TI_DbgPrint(DEBUG_TCP, ("Connection->SocketContext %x\n",
62         Connection->SocketContext));
63 
64     AddressToBind.addr = Connection->AddressFile->Address.Address.IPv4Address;
65 
66     Status = TCPTranslateError(LibTCPBind(Connection,
67                                           &AddressToBind,
68                                           Connection->AddressFile->Port));
69 
70     if (NT_SUCCESS(Status))
71     {
72         /* Check if we had an unspecified port */
73         if (!Connection->AddressFile->Port)
74         {
75             /* We did, so we need to copy back the port */
76             Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
77             if (NT_SUCCESS(Status))
78             {
79                 /* Allocate the port in the port bitmap */
80                 UINT AllocatedPort = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
81                 /* This should never fail unless all ports are in use */
82                 if (AllocatedPort == (UINT) -1)
83                 {
84                     DbgPrint("ERR: No more ports available.\n");
85                     UnlockObject(Connection);
86                     return STATUS_TOO_MANY_ADDRESSES;
87                 }
88                 Connection->AddressFile->Port = AllocatedPort;
89             }
90         }
91     }
92 
93     if (NT_SUCCESS(Status))
94     {
95         Connection->SocketContext = LibTCPListen(Connection, Backlog);
96         if (!Connection->SocketContext)
97             Status = STATUS_UNSUCCESSFUL;
98     }
99 
100     UnlockObject(Connection);
101 
102     TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Leaving. Status = %x\n", Status));
103 
104     return Status;
105 }
106 
107 BOOLEAN TCPAbortListenForSocket
108 (   PCONNECTION_ENDPOINT Listener,
109     PCONNECTION_ENDPOINT Connection)
110 {
111     PLIST_ENTRY ListEntry;
112     PTDI_BUCKET Bucket;
113     BOOLEAN Found = FALSE;
114 
115     LockObject(Listener);
116 
117     ListEntry = Listener->ListenRequest.Flink;
118     while (ListEntry != &Listener->ListenRequest)
119     {
120         Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
121 
122         if (Bucket->AssociatedEndpoint == Connection)
123         {
124             DereferenceObject(Bucket->AssociatedEndpoint);
125             RemoveEntryList( &Bucket->Entry );
126             ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
127             Found = TRUE;
128             break;
129         }
130 
131         ListEntry = ListEntry->Flink;
132     }
133 
134     UnlockObject(Listener);
135 
136     return Found;
137 }
138 
139 NTSTATUS TCPAccept ( PTDI_REQUEST Request,
140                      PCONNECTION_ENDPOINT Listener,
141                      PCONNECTION_ENDPOINT Connection,
142                      PTCP_COMPLETION_ROUTINE Complete,
143                      PVOID Context )
144 {
145     NTSTATUS Status;
146     PTDI_BUCKET Bucket;
147 
148     LockObject(Listener);
149 
150     Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
151 
152     if (Bucket)
153     {
154         Bucket->AssociatedEndpoint = Connection;
155         ReferenceObject(Bucket->AssociatedEndpoint);
156 
157         Bucket->Request.RequestNotifyObject = Complete;
158         Bucket->Request.RequestContext = Context;
159         InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
160         Status = STATUS_PENDING;
161     }
162     else
163         Status = STATUS_NO_MEMORY;
164 
165     UnlockObject(Listener);
166 
167     return Status;
168 }
169