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