d16550e47e43978f5e982b2ffa0793298a95bbfd
[reactos.git] / reactos / 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 #include "tdi_proto.h"
12 #include "tdiconn.h"
13 #include "debug.h"
14
15 static NTSTATUS SatisfyAccept( PAFD_DEVICE_EXTENSION DeviceExt,
16 PIRP Irp,
17 PFILE_OBJECT NewFileObject,
18 PAFD_TDI_OBJECT_QELT Qelt ) {
19 PAFD_FCB FCB = NewFileObject->FsContext;
20 NTSTATUS Status;
21
22 if( !SocketAcquireStateLock( FCB ) )
23 return LostSocket( Irp );
24
25 /* Transfer the connection to the new socket, launch the opening read */
26 AFD_DbgPrint(MID_TRACE,("Completing a real accept (FCB %x)\n", FCB));
27
28 FCB->Connection = Qelt->Object;
29
30 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
31 FCB->RemoteAddress =
32 TaCopyTransportAddress( Qelt->ConnInfo->RemoteAddress );
33
34 if( !FCB->RemoteAddress )
35 Status = STATUS_NO_MEMORY;
36 else
37 Status = MakeSocketIntoConnection( FCB );
38
39 if (NT_SUCCESS(Status))
40 Status = TdiBuildConnectionInfo(&FCB->ConnectInfo, 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 if( !IPAddr ) {
63 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
64 Irp->IoStatus.Status = STATUS_NO_MEMORY;
65 Irp->IoStatus.Information = 0;
66 (void)IoSetCancelRoutine(Irp, NULL);
67 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
68 return STATUS_NO_MEMORY;
69 }
70
71 AFD_DbgPrint(MID_TRACE,("IPAddr->TAAddressCount %d\n",
72 IPAddr->TAAddressCount));
73 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressType %d\n",
74 IPAddr->Address[0].AddressType));
75 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressLength %d\n",
76 IPAddr->Address[0].AddressLength));
77 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_port %x\n",
78 IPAddr->Address[0].Address[0].sin_port));
79 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_addr %x\n",
80 IPAddr->Address[0].Address[0].in_addr));
81
82 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
83
84 Irp->IoStatus.Information = ((PCHAR)&IPAddr[1]) - ((PCHAR)ListenReceive);
85 Irp->IoStatus.Status = STATUS_SUCCESS;
86 (void)IoSetCancelRoutine(Irp, NULL);
87 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
88 return STATUS_SUCCESS;
89 }
90
91 static NTSTATUS NTAPI ListenComplete
92 ( PDEVICE_OBJECT DeviceObject,
93 PIRP Irp,
94 PVOID Context ) {
95 NTSTATUS Status = STATUS_SUCCESS;
96 PAFD_FCB FCB = (PAFD_FCB)Context;
97 PAFD_TDI_OBJECT_QELT Qelt;
98 PLIST_ENTRY NextIrpEntry, QeltEntry;
99 PIRP NextIrp;
100
101 if( !SocketAcquireStateLock( FCB ) )
102 return STATUS_FILE_CLOSED;
103
104 FCB->ListenIrp.InFlightRequest = NULL;
105
106 if( FCB->State == SOCKET_STATE_CLOSED ) {
107 /* Cleanup our IRP queue because the FCB is being destroyed */
108 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) ) {
109 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_PREACCEPT]);
110 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
111 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
112 NextIrp->IoStatus.Information = 0;
113 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
114 (void)IoSetCancelRoutine(NextIrp, NULL);
115 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
116 }
117
118 /* Free all pending connections */
119 while( !IsListEmpty( &FCB->PendingConnections ) ) {
120 QeltEntry = RemoveHeadList(&FCB->PendingConnections);
121 Qelt = CONTAINING_RECORD(QeltEntry, AFD_TDI_OBJECT_QELT, ListEntry);
122 ExFreePool(Qelt);
123 }
124
125 /* Free ConnectionReturnInfo and ConnectionCallInfo */
126 if (FCB->ListenIrp.ConnectionReturnInfo)
127 {
128 ExFreePool(FCB->ListenIrp.ConnectionReturnInfo);
129 FCB->ListenIrp.ConnectionReturnInfo = NULL;
130 }
131
132 if (FCB->ListenIrp.ConnectionCallInfo)
133 {
134 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
135 FCB->ListenIrp.ConnectionCallInfo = NULL;
136 }
137
138 SocketStateUnlock( FCB );
139 return STATUS_FILE_CLOSED;
140 }
141
142 AFD_DbgPrint(MID_TRACE,("Completing listen request.\n"));
143 AFD_DbgPrint(MID_TRACE,("IoStatus was %x\n", FCB->ListenIrp.Iosb.Status));
144
145 Qelt = ExAllocatePool( NonPagedPool, sizeof(*Qelt) );
146 if( !Qelt ) {
147 Status = STATUS_NO_MEMORY;
148 } else {
149 UINT AddressType =
150 FCB->LocalAddress->Address[0].AddressType;
151
152 Qelt->Object = FCB->Connection;
153 Qelt->Seq = FCB->ConnSeq++;
154 AFD_DbgPrint(MID_TRACE,("Address Type: %d (RA %x)\n",
155 AddressType,
156 FCB->ListenIrp.
157 ConnectionReturnInfo->RemoteAddress));
158
159 TdiBuildNullConnectionInfo( &Qelt->ConnInfo, AddressType );
160 if( Qelt->ConnInfo ) {
161 TaCopyTransportAddressInPlace
162 ( Qelt->ConnInfo->RemoteAddress,
163 FCB->ListenIrp.ConnectionReturnInfo->RemoteAddress );
164 InsertTailList( &FCB->PendingConnections, &Qelt->ListEntry );
165 } else Status = STATUS_NO_MEMORY;
166 }
167
168 /* Satisfy a pre-accept request if one is available */
169 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) &&
170 !IsListEmpty( &FCB->PendingConnections ) ) {
171 PLIST_ENTRY PendingIrp =
172 RemoveHeadList( &FCB->PendingIrpList[FUNCTION_PREACCEPT] );
173 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
174 SatisfyPreAccept
175 ( CONTAINING_RECORD( PendingIrp, IRP,
176 Tail.Overlay.ListEntry ),
177 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT,
178 ListEntry ) );
179 }
180
181 if( FCB->ListenIrp.ConnectionCallInfo ) {
182 ExFreePool( FCB->ListenIrp.ConnectionCallInfo );
183 FCB->ListenIrp.ConnectionCallInfo = NULL;
184 }
185
186 if( FCB->ListenIrp.ConnectionReturnInfo ) {
187 ExFreePool( FCB->ListenIrp.ConnectionReturnInfo );
188 FCB->ListenIrp.ConnectionReturnInfo = NULL;
189 }
190
191 FCB->NeedsNewListen = TRUE;
192
193 /* Trigger a select return if appropriate */
194 if( !IsListEmpty( &FCB->PendingConnections ) ) {
195 FCB->PollState |= AFD_EVENT_ACCEPT;
196 } else {
197 FCB->PollState &= ~AFD_EVENT_ACCEPT;
198 }
199
200 PollReeval( FCB->DeviceExt, FCB->FileObject );
201
202 SocketStateUnlock( FCB );
203
204 return Status;
205 }
206
207 NTSTATUS AfdListenSocket(PDEVICE_OBJECT DeviceObject, PIRP Irp,
208 PIO_STACK_LOCATION IrpSp) {
209 NTSTATUS Status = STATUS_SUCCESS;
210 PFILE_OBJECT FileObject = IrpSp->FileObject;
211 PAFD_FCB FCB = FileObject->FsContext;
212 PAFD_LISTEN_DATA ListenReq;
213
214 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
215
216 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
217
218 if( !(ListenReq = LockRequest( Irp, IrpSp )) )
219 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
220 0 );
221
222 if( FCB->State != SOCKET_STATE_BOUND ) {
223 Status = STATUS_INVALID_PARAMETER;
224 AFD_DbgPrint(MID_TRACE,("Could not listen an unbound socket\n"));
225 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
226 }
227
228 FCB->DelayedAccept = ListenReq->UseDelayedAcceptance;
229
230 AFD_DbgPrint(MID_TRACE,("ADDRESSFILE: %x\n", FCB->AddressFile.Handle));
231
232 Status = WarmSocketForConnection( FCB );
233
234 AFD_DbgPrint(MID_TRACE,("Status from warmsocket %x\n", Status));
235
236 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
237
238 TdiBuildNullConnectionInfo
239 ( &FCB->ListenIrp.ConnectionCallInfo,
240 FCB->LocalAddress->Address[0].AddressType );
241 TdiBuildNullConnectionInfo
242 ( &FCB->ListenIrp.ConnectionReturnInfo,
243 FCB->LocalAddress->Address[0].AddressType );
244
245 if( !FCB->ListenIrp.ConnectionReturnInfo || !FCB->ListenIrp.ConnectionCallInfo )
246 {
247 if (FCB->ListenIrp.ConnectionReturnInfo)
248 {
249 ExFreePool(FCB->ListenIrp.ConnectionReturnInfo);
250 FCB->ListenIrp.ConnectionReturnInfo = NULL;
251 }
252
253 if (FCB->ListenIrp.ConnectionCallInfo)
254 {
255 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
256 FCB->ListenIrp.ConnectionCallInfo = NULL;
257 }
258
259 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
260 }
261
262 FCB->State = SOCKET_STATE_LISTENING;
263
264 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
265 FCB->Connection.Object,
266 &FCB->ListenIrp.ConnectionCallInfo,
267 &FCB->ListenIrp.ConnectionReturnInfo,
268 &FCB->ListenIrp.Iosb,
269 ListenComplete,
270 FCB );
271
272 if( Status == STATUS_PENDING )
273 Status = STATUS_SUCCESS;
274
275 if (NT_SUCCESS(Status))
276 FCB->NeedsNewListen = FALSE;
277
278 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
279 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
280 }
281
282 NTSTATUS AfdWaitForListen( PDEVICE_OBJECT DeviceObject, PIRP Irp,
283 PIO_STACK_LOCATION IrpSp ) {
284 PFILE_OBJECT FileObject = IrpSp->FileObject;
285 PAFD_FCB FCB = FileObject->FsContext;
286 NTSTATUS Status;
287
288 AFD_DbgPrint(MID_TRACE,("Called\n"));
289
290 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
291
292 if( !IsListEmpty( &FCB->PendingConnections ) ) {
293 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
294
295 /* We have a pending connection ... complete this irp right away */
296 Status = SatisfyPreAccept
297 ( Irp,
298 CONTAINING_RECORD
299 ( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry ) );
300
301 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
302
303 if ( IsListEmpty( &FCB->PendingConnections ) )
304 FCB->PollState &= ~AFD_EVENT_ACCEPT;
305 else
306 FCB->PollState |= AFD_EVENT_ACCEPT;
307
308 PollReeval( FCB->DeviceExt, FCB->FileObject );
309
310 SocketStateUnlock( FCB );
311 return Status;
312 } else {
313 AFD_DbgPrint(MID_TRACE,("Holding\n"));
314
315 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_PREACCEPT );
316 }
317 }
318
319 NTSTATUS AfdAccept( PDEVICE_OBJECT DeviceObject, PIRP Irp,
320 PIO_STACK_LOCATION IrpSp ) {
321 NTSTATUS Status = STATUS_SUCCESS;
322 PFILE_OBJECT FileObject = IrpSp->FileObject;
323 PAFD_DEVICE_EXTENSION DeviceExt =
324 (PAFD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
325 PAFD_FCB FCB = FileObject->FsContext;
326 PAFD_ACCEPT_DATA AcceptData = Irp->AssociatedIrp.SystemBuffer;
327 PLIST_ENTRY PendingConn;
328
329 AFD_DbgPrint(MID_TRACE,("Called\n"));
330
331 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
332
333 if( FCB->NeedsNewListen ) {
334 AFD_DbgPrint(MID_TRACE,("ADDRESSFILE: %x\n", FCB->AddressFile.Handle));
335
336 /* Launch new accept socket */
337 Status = WarmSocketForConnection( FCB );
338
339 if( Status == STATUS_SUCCESS ) {
340 TdiBuildNullConnectionInfo
341 ( &FCB->ListenIrp.ConnectionCallInfo,
342 FCB->LocalAddress->Address[0].AddressType );
343 TdiBuildNullConnectionInfo
344 ( &FCB->ListenIrp.ConnectionReturnInfo,
345 FCB->LocalAddress->Address[0].AddressType );
346
347 if( !FCB->ListenIrp.ConnectionReturnInfo || !FCB->ListenIrp.ConnectionCallInfo )
348 {
349 if (FCB->ListenIrp.ConnectionReturnInfo)
350 {
351 ExFreePool(FCB->ListenIrp.ConnectionReturnInfo);
352 FCB->ListenIrp.ConnectionReturnInfo = NULL;
353 }
354
355 if (FCB->ListenIrp.ConnectionCallInfo)
356 {
357 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
358 FCB->ListenIrp.ConnectionCallInfo = NULL;
359 }
360
361 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
362 }
363
364 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
365 FCB->Connection.Object,
366 &FCB->ListenIrp.ConnectionCallInfo,
367 &FCB->ListenIrp.ConnectionReturnInfo,
368 &FCB->ListenIrp.Iosb,
369 ListenComplete,
370 FCB );
371
372 if( Status == STATUS_PENDING )
373 Status = STATUS_SUCCESS;
374
375 if( !NT_SUCCESS(Status) )
376 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
377
378 FCB->NeedsNewListen = FALSE;
379 } else return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
380 }
381
382 for( PendingConn = FCB->PendingConnections.Flink;
383 PendingConn != &FCB->PendingConnections;
384 PendingConn = PendingConn->Flink ) {
385 PAFD_TDI_OBJECT_QELT PendingConnObj =
386 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry );
387
388 AFD_DbgPrint(MID_TRACE,("Comparing Seq %d to Q %d\n",
389 AcceptData->SequenceNumber,
390 PendingConnObj->Seq));
391
392 if( PendingConnObj->Seq == AcceptData->SequenceNumber ) {
393 PFILE_OBJECT NewFileObject = NULL;
394
395 RemoveEntryList( PendingConn );
396
397 Status = ObReferenceObjectByHandle
398 ( AcceptData->ListenHandle,
399 FILE_ALL_ACCESS,
400 NULL,
401 KernelMode,
402 (PVOID *)&NewFileObject,
403 NULL );
404
405 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
406
407 ASSERT(NewFileObject != FileObject);
408 ASSERT(NewFileObject->FsContext != FCB);
409
410 /* We have a pending connection ... complete this irp right away */
411 Status = SatisfyAccept( DeviceExt, Irp, NewFileObject, PendingConnObj );
412
413 ObDereferenceObject( NewFileObject );
414
415 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
416
417 ExFreePool( PendingConnObj );
418
419 if( IsListEmpty( &FCB->PendingConnections ) ) {
420 FCB->PollState &= ~AFD_EVENT_ACCEPT;
421 } else {
422 FCB->PollState |= AFD_EVENT_ACCEPT;
423 }
424
425 PollReeval( FCB->DeviceExt, FCB->FileObject );
426
427 SocketStateUnlock( FCB );
428 return Status;
429 }
430 }
431
432 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp, 0 );
433 }