00f8e7537df2166d13e853481900f4b2c19004a7
[reactos.git] / reactos / 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 #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 UNREFERENCED_PARAMETER(DeviceExt);
20
21 if( !SocketAcquireStateLock( FCB ) )
22 return LostSocket( Irp );
23
24 /* Transfer the connection to the new socket, launch the opening read */
25 AFD_DbgPrint(MID_TRACE,("Completing a real accept (FCB %p)\n", FCB));
26
27 FCB->Connection = Qelt->Object;
28
29 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
30 FCB->RemoteAddress =
31 TaCopyTransportAddress( Qelt->ConnInfo->RemoteAddress );
32
33 if( !FCB->RemoteAddress )
34 Status = STATUS_NO_MEMORY;
35 else
36 Status = MakeSocketIntoConnection( FCB );
37
38 if (NT_SUCCESS(Status))
39 Status = TdiBuildConnectionInfo(&FCB->ConnectCallInfo, FCB->RemoteAddress);
40
41 if (NT_SUCCESS(Status))
42 Status = TdiBuildConnectionInfo(&FCB->ConnectReturnInfo, FCB->RemoteAddress);
43
44 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
45 }
46
47 static NTSTATUS SatisfyPreAccept( PIRP Irp, PAFD_TDI_OBJECT_QELT Qelt ) {
48 PAFD_RECEIVED_ACCEPT_DATA ListenReceive =
49 (PAFD_RECEIVED_ACCEPT_DATA)Irp->AssociatedIrp.SystemBuffer;
50 PTA_IP_ADDRESS IPAddr;
51
52 ListenReceive->SequenceNumber = Qelt->Seq;
53
54 AFD_DbgPrint(MID_TRACE,("Giving SEQ %u to userland\n", Qelt->Seq));
55 AFD_DbgPrint(MID_TRACE,("Socket Address (K) %p (U) %p\n",
56 &ListenReceive->Address,
57 Qelt->ConnInfo->RemoteAddress));
58
59 TaCopyTransportAddressInPlace( &ListenReceive->Address,
60 Qelt->ConnInfo->RemoteAddress );
61
62 IPAddr = (PTA_IP_ADDRESS)&ListenReceive->Address;
63
64 AFD_DbgPrint(MID_TRACE,("IPAddr->TAAddressCount %d\n",
65 IPAddr->TAAddressCount));
66 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressType %u\n",
67 IPAddr->Address[0].AddressType));
68 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].AddressLength %u\n",
69 IPAddr->Address[0].AddressLength));
70 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_port %x\n",
71 IPAddr->Address[0].Address[0].sin_port));
72 AFD_DbgPrint(MID_TRACE,("IPAddr->Address[0].Address[0].sin_addr %x\n",
73 IPAddr->Address[0].Address[0].in_addr));
74
75 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
76
77 Irp->IoStatus.Information = ((PCHAR)&IPAddr[1]) - ((PCHAR)ListenReceive);
78 Irp->IoStatus.Status = STATUS_SUCCESS;
79 (void)IoSetCancelRoutine(Irp, NULL);
80 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
81 return STATUS_SUCCESS;
82 }
83
84 static IO_COMPLETION_ROUTINE ListenComplete;
85 static NTSTATUS NTAPI ListenComplete( PDEVICE_OBJECT DeviceObject,
86 PIRP Irp,
87 PVOID Context ) {
88 NTSTATUS Status = STATUS_SUCCESS;
89 PAFD_FCB FCB = (PAFD_FCB)Context;
90 PAFD_TDI_OBJECT_QELT Qelt;
91 PLIST_ENTRY NextIrpEntry;
92 PIRP NextIrp;
93
94 UNREFERENCED_PARAMETER(DeviceObject);
95
96 if( !SocketAcquireStateLock( FCB ) )
97 return STATUS_FILE_CLOSED;
98
99 ASSERT(FCB->ListenIrp.InFlightRequest == Irp);
100 FCB->ListenIrp.InFlightRequest = NULL;
101
102 if( FCB->State == SOCKET_STATE_CLOSED ) {
103 /* Cleanup our IRP queue because the FCB is being destroyed */
104 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) ) {
105 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_PREACCEPT]);
106 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
107 NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
108 NextIrp->IoStatus.Information = 0;
109 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
110 (void)IoSetCancelRoutine(NextIrp, NULL);
111 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
112 }
113
114 /* Free ConnectionReturnInfo and ConnectionCallInfo */
115 if (FCB->ListenIrp.ConnectionReturnInfo)
116 {
117 ExFreePool(FCB->ListenIrp.ConnectionReturnInfo);
118 FCB->ListenIrp.ConnectionReturnInfo = NULL;
119 }
120
121 if (FCB->ListenIrp.ConnectionCallInfo)
122 {
123 ExFreePool(FCB->ListenIrp.ConnectionCallInfo);
124 FCB->ListenIrp.ConnectionCallInfo = NULL;
125 }
126
127 SocketStateUnlock( FCB );
128 return STATUS_FILE_CLOSED;
129 }
130
131 AFD_DbgPrint(MID_TRACE,("Completing listen request.\n"));
132 AFD_DbgPrint(MID_TRACE,("IoStatus was %x\n", Irp->IoStatus.Status));
133
134 if (Irp->IoStatus.Status != STATUS_SUCCESS)
135 {
136 SocketStateUnlock(FCB);
137 return Irp->IoStatus.Status;
138 }
139
140 Qelt = ExAllocatePool( NonPagedPool, sizeof(*Qelt) );
141 if( !Qelt ) {
142 Status = STATUS_NO_MEMORY;
143 } else {
144 UINT AddressType =
145 FCB->LocalAddress->Address[0].AddressType;
146
147 Qelt->Object = FCB->Connection;
148 Qelt->Seq = FCB->ConnSeq++;
149 AFD_DbgPrint(MID_TRACE,("Address Type: %u (RA %p)\n",
150 AddressType,
151 FCB->ListenIrp.
152 ConnectionReturnInfo->RemoteAddress));
153
154 Status = TdiBuildNullConnectionInfo( &Qelt->ConnInfo, AddressType );
155 if( NT_SUCCESS(Status) ) {
156 TaCopyTransportAddressInPlace
157 ( Qelt->ConnInfo->RemoteAddress,
158 FCB->ListenIrp.ConnectionReturnInfo->RemoteAddress );
159 InsertTailList( &FCB->PendingConnections, &Qelt->ListEntry );
160 }
161 }
162
163 /* Satisfy a pre-accept request if one is available */
164 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_PREACCEPT] ) &&
165 !IsListEmpty( &FCB->PendingConnections ) ) {
166 PLIST_ENTRY PendingIrp =
167 RemoveHeadList( &FCB->PendingIrpList[FUNCTION_PREACCEPT] );
168 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
169 SatisfyPreAccept
170 ( CONTAINING_RECORD( PendingIrp, IRP,
171 Tail.Overlay.ListEntry ),
172 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT,
173 ListEntry ) );
174 }
175
176 /* Launch new accept socket */
177 Status = WarmSocketForConnection( FCB );
178
179 if (NT_SUCCESS(Status))
180 {
181 Status = TdiBuildNullConnectionInfoInPlace(FCB->ListenIrp.ConnectionCallInfo,
182 FCB->LocalAddress->Address[0].AddressType);
183 ASSERT(Status == STATUS_SUCCESS);
184
185 Status = TdiBuildNullConnectionInfoInPlace(FCB->ListenIrp.ConnectionReturnInfo,
186 FCB->LocalAddress->Address[0].AddressType);
187 ASSERT(Status == STATUS_SUCCESS);
188
189 Status = TdiListen( &FCB->ListenIrp.InFlightRequest,
190 FCB->Connection.Object,
191 &FCB->ListenIrp.ConnectionCallInfo,
192 &FCB->ListenIrp.ConnectionReturnInfo,
193 &FCB->ListenIrp.Iosb,
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 &FCB->ListenIrp.Iosb,
271 ListenComplete,
272 FCB );
273
274 if( Status == STATUS_PENDING )
275 Status = STATUS_SUCCESS;
276
277 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
278 return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
279 }
280
281 NTSTATUS AfdWaitForListen( PDEVICE_OBJECT DeviceObject, PIRP Irp,
282 PIO_STACK_LOCATION IrpSp ) {
283 PFILE_OBJECT FileObject = IrpSp->FileObject;
284 PAFD_FCB FCB = FileObject->FsContext;
285 NTSTATUS Status;
286
287 UNREFERENCED_PARAMETER(DeviceObject);
288
289 AFD_DbgPrint(MID_TRACE,("Called\n"));
290
291 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
292
293 if( !IsListEmpty( &FCB->PendingConnections ) ) {
294 PLIST_ENTRY PendingConn = FCB->PendingConnections.Flink;
295
296 /* We have a pending connection ... complete this irp right away */
297 Status = SatisfyPreAccept
298 ( Irp,
299 CONTAINING_RECORD
300 ( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry ) );
301
302 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
303
304 if ( !IsListEmpty( &FCB->PendingConnections ) )
305 {
306 FCB->PollState |= AFD_EVENT_ACCEPT;
307 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
308 PollReeval( FCB->DeviceExt, FCB->FileObject );
309 } else
310 FCB->PollState &= ~AFD_EVENT_ACCEPT;
311
312 SocketStateUnlock( FCB );
313 return Status;
314 } else if (FCB->NonBlocking) {
315 AFD_DbgPrint(MIN_TRACE,("No connection ready on a non-blocking socket\n"));
316
317 return UnlockAndMaybeComplete(FCB, STATUS_CANT_WAIT, Irp, 0);
318 } else {
319 AFD_DbgPrint(MID_TRACE,("Holding\n"));
320
321 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_PREACCEPT );
322 }
323 }
324
325 NTSTATUS AfdAccept( PDEVICE_OBJECT DeviceObject, PIRP Irp,
326 PIO_STACK_LOCATION IrpSp ) {
327 NTSTATUS Status = STATUS_SUCCESS;
328 PFILE_OBJECT FileObject = IrpSp->FileObject;
329 PAFD_DEVICE_EXTENSION DeviceExt =
330 (PAFD_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
331 PAFD_FCB FCB = FileObject->FsContext;
332 PAFD_ACCEPT_DATA AcceptData = Irp->AssociatedIrp.SystemBuffer;
333 PLIST_ENTRY PendingConn;
334
335 AFD_DbgPrint(MID_TRACE,("Called\n"));
336
337 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
338
339 FCB->EventSelectDisabled &= ~AFD_EVENT_ACCEPT;
340
341 for( PendingConn = FCB->PendingConnections.Flink;
342 PendingConn != &FCB->PendingConnections;
343 PendingConn = PendingConn->Flink ) {
344 PAFD_TDI_OBJECT_QELT PendingConnObj =
345 CONTAINING_RECORD( PendingConn, AFD_TDI_OBJECT_QELT, ListEntry );
346
347 AFD_DbgPrint(MID_TRACE,("Comparing Seq %u to Q %u\n",
348 AcceptData->SequenceNumber,
349 PendingConnObj->Seq));
350
351 if( PendingConnObj->Seq == AcceptData->SequenceNumber ) {
352 PFILE_OBJECT NewFileObject = NULL;
353
354 RemoveEntryList( PendingConn );
355
356 Status = ObReferenceObjectByHandle
357 ( AcceptData->ListenHandle,
358 FILE_ALL_ACCESS,
359 NULL,
360 KernelMode,
361 (PVOID *)&NewFileObject,
362 NULL );
363
364 if( !NT_SUCCESS(Status) ) return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
365
366 ASSERT(NewFileObject != FileObject);
367 ASSERT(NewFileObject->FsContext != FCB);
368
369 /* We have a pending connection ... complete this irp right away */
370 Status = SatisfyAccept( DeviceExt, Irp, NewFileObject, PendingConnObj );
371
372 ObDereferenceObject( NewFileObject );
373
374 AFD_DbgPrint(MID_TRACE,("Completed a wait for accept\n"));
375
376 ExFreePool( PendingConnObj );
377
378 if( !IsListEmpty( &FCB->PendingConnections ) )
379 {
380 FCB->PollState |= AFD_EVENT_ACCEPT;
381 FCB->PollStatus[FD_ACCEPT_BIT] = STATUS_SUCCESS;
382 PollReeval( FCB->DeviceExt, FCB->FileObject );
383 } else
384 FCB->PollState &= ~AFD_EVENT_ACCEPT;
385
386 SocketStateUnlock( FCB );
387 return Status;
388 }
389 }
390
391 AFD_DbgPrint(MIN_TRACE,("No connection waiting\n"));
392
393 return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL, Irp, 0 );
394 }