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