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