[CLT2012]
[reactos.git] / drivers / network / afd / afd / listen.c
1 /* $Id$
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/listen.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 */
10 #include "afd.h"
11
12 static NTSTATUS SatisfyAccept( PAFD_DEVICE_EXTENSION DeviceExt,
13 PIRP Irp,
14 PFILE_OBJECT NewFileObject,
15 PAFD_TDI_OBJECT_QELT Qelt ) {
16 PAFD_FCB FCB = NewFileObject->FsContext;
17 NTSTATUS Status;
18
19 if( !SocketAcquireStateLock( FCB ) )
20 return LostSocket( Irp );
21
22 /* Transfer the connection to the new socket, launch the opening read */
23 AFD_DbgPrint(MID_TRACE,("Completing a real accept (FCB %x)\n", FCB));
24
25 FCB->Connection = Qelt->Object;
26
27 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
28 FCB->RemoteAddress =
29 TaCopyTransportAddress( Qelt->ConnInfo->RemoteAddress );
30
31 if( !FCB->RemoteAddress )
32 Status = STATUS_NO_MEMORY;
33 else
34 Status = MakeSocketIntoConnection( FCB );
35
36 if (NT_SUCCESS(Status))
37 Status = TdiBuildConnectionInfo(&FCB->ConnectCallInfo, FCB->RemoteAddress);
38
39 if (NT_SUCCESS(Status))
40 Status = TdiBuildConnectionInfo(&FCB->ConnectReturnInfo, FCB->RemoteAddress);
41
42 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
43 }
44
45 static NTSTATUS SatisfyPreAccept( PIRP Irp, PAFD_TDI_OBJECT_QELT Qelt ) {
46 PAFD_RECEIVED_ACCEPT_DATA ListenReceive =
47 (PAFD_RECEIVED_ACCEPT_DATA)Irp->AssociatedIrp.SystemBuffer;
48 PTA_IP_ADDRESS IPAddr;
49
50 ListenReceive->SequenceNumber = Qelt->Seq;
51
52 AFD_DbgPrint(MID_TRACE,("Giving SEQ %d to userland\n", Qelt->Seq));
53 AFD_DbgPrint(MID_TRACE,("Socket Address (K) %x (U) %x\n",
54 &ListenReceive->Address,
55 Qelt->ConnInfo->RemoteAddress));
56
57 TaCopyTransportAddressInPlace( &ListenReceive->Address,
58 Qelt->ConnInfo->RemoteAddress );
59
60 IPAddr = (PTA_IP_ADDRESS)&ListenReceive->Address;
61
62 AFD_DbgPrint(MID_TRACE,("IPAddr->TAAddressCount %d\n",
63 IPAddr->TAAddressCount));
64 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressType %d\n",
65 IPAddr->Address[0].AddressType));
66 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressLength %d\n",
67 IPAddr->Address[0].AddressLength));
68 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_port %x\n",
69 IPAddr->Address[0].Address[0].sin_port));
70 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_addr %x\n",
71 IPAddr->Address[0].Address[0].in_addr));
72
73 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
74
75 Irp->IoStatus.Information = ((PCHAR)&IPAddr[1]) - ((PCHAR)ListenReceive);
76 Irp->IoStatus.Status = STATUS_SUCCESS;
77 (void)IoSetCancelRoutine(Irp, NULL);
78 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
79 return STATUS_SUCCESS;
80 }
81
82 static NTSTATUS NTAPI ListenComplete
83 ( PDEVICE_OBJECT DeviceObject,
84 PIRP Irp,
85 PVOID Context ) {
86 NTSTATUS Status = STATUS_SUCCESS;
87 PAFD_FCB FCB = (PAFD_FCB)Context;
88 PAFD_TDI_OBJECT_QELT Qelt;
89 PLIST_ENTRY NextIrpEntry;
90 PIRP NextIrp;
91
92 if( !SocketAcquireStateLock( FCB ) )
93 return STATUS_FILE_CLOSED;
94
95 ASSERT(FCB->ListenIrp.InFlightRequest == Irp);
96 FCB->ListenIrp.InFlightRequest = NULL;
97
98 if( FCB->State == SOCKET_STATE_CLOSED ) {
99 /* Cleanup our IRP queue because the FCB is being destroyed */
100 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) ) {
101 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_PREACCEPT]);
102 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
103 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
104 NextIrp->IoStatus.Information = 0;
105 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
106 (void)IoSetCancelRoutine(NextIrp, NULL);
107 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
108 }
109
110 /* Free ConnectionReturnInfo and ConnectionCallInfo */
111 if (FCB->ListenIrp.ConnectionReturnInfo)
112 {
113 ExFreePool(FCB->ListenIrp.ConnectionReturnInfo);
114 FCB->ListenIrp.ConnectionReturnInfo = NULL;
115 }
116
117 if (FCB->ListenIrp.ConnectionCallInfo)
118 {
119 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
120 FCB->ListenIrp.ConnectionCallInfo = NULL;
121 }
122
123 SocketStateUnlock( FCB );
124 return STATUS_FILE_CLOSED;
125 }
126
127 AFD_DbgPrint(MID_TRACE,("Completing listen request.\n"));
128 AFD_DbgPrint(MID_TRACE,("IoStatus was %x\n", Irp->IoStatus.Status));
129
130 if (Irp->IoStatus.Status != STATUS_SUCCESS)
131 {
132 SocketStateUnlock(FCB);
133 return Irp->IoStatus.Status;
134 }
135
136 Qelt = ExAllocatePool( NonPagedPool, sizeof(*Qelt) );
137 if( !Qelt ) {
138 Status = STATUS_NO_MEMORY;
139 } else {
140 UINT AddressType =
141 FCB->LocalAddress->Address[0].AddressType;
142
143 Qelt->Object = FCB->Connection;
144 Qelt->Seq = FCB->ConnSeq++;
145 AFD_DbgPrint(MID_TRACE,("Address Type: %d (RA %x)\n",
146 AddressType,
147 FCB->ListenIrp.
148 ConnectionReturnInfo->RemoteAddress));
149
150 Status = TdiBuildNullConnectionInfo( &Qelt->ConnInfo, AddressType );
151 if( NT_SUCCESS(Status) ) {
152 TaCopyTransportAddressInPlace
153 ( Qelt->ConnInfo->RemoteAddress,
154 FCB->ListenIrp.ConnectionReturnInfo->RemoteAddress );
155 InsertTailList( &FCB->PendingConnections, &Qelt->ListEntry );
156 }
157 }
158
159 /* Satisfy a pre-accept request if one is available */
160 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) &&
161 !IsListEmpty( &FCB->PendingConnections ) ) {
162 PLIST_ENTRY PendingIrp =
163 RemoveHeadList( &FCB->PendingIrpList[FUNCTION_PREACCEPT] );
164 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
165 SatisfyPreAccept
166 ( CONTAINING_RECORD( PendingIrp, IRP,
167 Tail.Overlay.ListEntry ),
168 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT,
169 ListEntry ) );
170 }
171
172 /* Launch new accept socket */
173 Status = WarmSocketForConnection( FCB );
174
175 if (NT_SUCCESS(Status))
176 {
177 Status = TdiBuildNullConnectionInfoInPlace(FCB->ListenIrp.ConnectionCallInfo,
178 FCB->LocalAddress->Address[0].AddressType);
179 ASSERT(Status == STATUS_SUCCESS);
180
181 Status = TdiBuildNullConnectionInfoInPlace(FCB->ListenIrp.ConnectionReturnInfo,
182 FCB->LocalAddress->Address[0].AddressType);
183 ASSERT(Status == STATUS_SUCCESS);
184
185 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
186 FCB->Connection.Object,
187 &FCB->ListenIrp.ConnectionCallInfo,
188 &FCB->ListenIrp.ConnectionReturnInfo,
189 &FCB->ListenIrp.Iosb,
190 ListenComplete,
191 FCB );
192
193 if (Status == STATUS_PENDING)
194 Status = STATUS_SUCCESS;
195 }
196
197 /* Trigger a select return if appropriate */
198 if( !IsListEmpty( &FCB->PendingConnections ) ) {
199 FCB->PollState |= AFD_EVENT_ACCEPT;
200 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
201 PollReeval( FCB->DeviceExt, FCB->FileObject );
202 } else
203 FCB->PollState &= ~AFD_EVENT_ACCEPT;
204
205 SocketStateUnlock( FCB );
206
207 return Status;
208 }
209
210 NTSTATUS AfdListenSocket(PDEVICE_OBJECT DeviceObject, PIRP Irp,
211 PIO_STACK_LOCATION IrpSp) {
212 NTSTATUS Status = STATUS_SUCCESS;
213 PFILE_OBJECT FileObject = IrpSp->FileObject;
214 PAFD_FCB FCB = FileObject->FsContext;
215 PAFD_LISTEN_DATA ListenReq;
216
217 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
218
219 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
220
221 if( !(ListenReq = LockRequest( Irp, IrpSp )) )
222 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
223 0 );
224
225 if( FCB->State != SOCKET_STATE_BOUND ) {
226 Status = STATUS_INVALID_PARAMETER;
227 AFD_DbgPrint(MIN_TRACE,("Could not listen an unbound socket\n"));
228 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
229 }
230
231 FCB->DelayedAccept = ListenReq->UseDelayedAcceptance;
232
233 AFD_DbgPrint(MID_TRACE,("ADDRESSFILE: %x\n", FCB->AddressFile.Handle));
234
235 Status = WarmSocketForConnection( FCB );
236
237 AFD_DbgPrint(MID_TRACE,("Status from warmsocket %x\n", Status));
238
239 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
240
241 Status = TdiBuildNullConnectionInfo
242 ( &FCB->ListenIrp.ConnectionCallInfo,
243 FCB->LocalAddress->Address[0].AddressType );
244
245 if (!NT_SUCCESS(Status)) return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
246
247 Status = TdiBuildNullConnectionInfo
248 ( &FCB->ListenIrp.ConnectionReturnInfo,
249 FCB->LocalAddress->Address[0].AddressType );
250
251 if (!NT_SUCCESS(Status))
252 {
253 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
254 FCB->ListenIrp.ConnectionCallInfo = NULL;
255 return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
256 }
257
258 FCB->State = SOCKET_STATE_LISTENING;
259
260 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
261 FCB->Connection.Object,
262 &FCB->ListenIrp.ConnectionCallInfo,
263 &FCB->ListenIrp.ConnectionReturnInfo,
264 &FCB->ListenIrp.Iosb,
265 ListenComplete,
266 FCB );
267
268 if( Status == STATUS_PENDING )
269 Status = STATUS_SUCCESS;
270
271 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
272 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
273 }
274
275 NTSTATUS AfdWaitForListen( PDEVICE_OBJECT DeviceObject, PIRP Irp,
276 PIO_STACK_LOCATION IrpSp ) {
277 PFILE_OBJECT FileObject = IrpSp->FileObject;
278 PAFD_FCB FCB = FileObject->FsContext;
279 NTSTATUS Status;
280
281 AFD_DbgPrint(MID_TRACE,("Called\n"));
282
283 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
284
285 if( !IsListEmpty( &FCB->PendingConnections ) ) {
286 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
287
288 /* We have a pending connection ... complete this irp right away */
289 Status = SatisfyPreAccept
290 ( Irp,
291 CONTAINING_RECORD
292 ( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry ) );
293
294 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
295
296 if ( !IsListEmpty( &FCB->PendingConnections ) )
297 {
298 FCB->PollState |= AFD_EVENT_ACCEPT;
299 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
300 PollReeval( FCB->DeviceExt, FCB->FileObject );
301 } else
302 FCB->PollState &= ~AFD_EVENT_ACCEPT;
303
304 SocketStateUnlock( FCB );
305 return Status;
306 } else if (FCB->NonBlocking) {
307 AFD_DbgPrint(MIN_TRACE,("No connection ready on a non-blocking socket\n"));
308
309 return UnlockAndMaybeComplete(FCB, STATUS_CANT_WAIT, Irp, 0);
310 } else {
311 AFD_DbgPrint(MID_TRACE,("Holding\n"));
312
313 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_PREACCEPT );
314 }
315 }
316
317 NTSTATUS AfdAccept( PDEVICE_OBJECT DeviceObject, PIRP Irp,
318 PIO_STACK_LOCATION IrpSp ) {
319 NTSTATUS Status = STATUS_SUCCESS;
320 PFILE_OBJECT FileObject = IrpSp->FileObject;
321 PAFD_DEVICE_EXTENSION DeviceExt =
322 (PAFD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
323 PAFD_FCB FCB = FileObject->FsContext;
324 PAFD_ACCEPT_DATA AcceptData = Irp->AssociatedIrp.SystemBuffer;
325 PLIST_ENTRY PendingConn;
326
327 AFD_DbgPrint(MID_TRACE,("Called\n"));
328
329 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
330
331 for( PendingConn = FCB->PendingConnections.Flink;
332 PendingConn != &FCB->PendingConnections;
333 PendingConn = PendingConn->Flink ) {
334 PAFD_TDI_OBJECT_QELT PendingConnObj =
335 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry );
336
337 AFD_DbgPrint(MID_TRACE,("Comparing Seq %d to Q %d\n",
338 AcceptData->SequenceNumber,
339 PendingConnObj->Seq));
340
341 if( PendingConnObj->Seq == AcceptData->SequenceNumber ) {
342 PFILE_OBJECT NewFileObject = NULL;
343
344 RemoveEntryList( PendingConn );
345
346 Status = ObReferenceObjectByHandle
347 ( AcceptData->ListenHandle,
348 FILE_ALL_ACCESS,
349 NULL,
350 KernelMode,
351 (PVOID *)&NewFileObject,
352 NULL );
353
354 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
355
356 ASSERT(NewFileObject != FileObject);
357 ASSERT(NewFileObject->FsContext != FCB);
358
359 /* We have a pending connection ... complete this irp right away */
360 Status = SatisfyAccept( DeviceExt, Irp, NewFileObject, PendingConnObj );
361
362 ObDereferenceObject( NewFileObject );
363
364 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
365
366 ExFreePool( PendingConnObj );
367
368 FCB->EventSelectDisabled &= ~AFD_EVENT_ACCEPT;
369
370 if( !IsListEmpty( &FCB->PendingConnections ) )
371 {
372 FCB->PollState |= AFD_EVENT_ACCEPT;
373 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
374 PollReeval( FCB->DeviceExt, FCB->FileObject );
375 } else
376 FCB->PollState &= ~AFD_EVENT_ACCEPT;
377
378 SocketStateUnlock( FCB );
379 return Status;
380 }
381 }
382
383 AFD_DbgPrint(MIN_TRACE,("No connection waiting\n"));
384
385 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp, 0 );
386 }