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)
11 #include "tdi_proto.h"
15 static NTSTATUS
SatisfyAccept( PAFD_DEVICE_EXTENSION DeviceExt
,
17 PFILE_OBJECT NewFileObject
,
18 PAFD_TDI_OBJECT_QELT Qelt
) {
19 PAFD_FCB FCB
= NewFileObject
->FsContext
;
22 if( !SocketAcquireStateLock( FCB
) )
23 return LostSocket( Irp
);
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
));
28 FCB
->Connection
= Qelt
->Object
;
30 if( FCB
->RemoteAddress
) ExFreePool( FCB
->RemoteAddress
);
32 TaCopyTransportAddress( Qelt
->ConnInfo
->RemoteAddress
);
34 if( !FCB
->RemoteAddress
)
35 Status
= STATUS_NO_MEMORY
;
37 Status
= MakeSocketIntoConnection( FCB
);
39 if (NT_SUCCESS(Status
))
40 Status
= TdiBuildConnectionInfo(&FCB
->ConnectInfo
, FCB
->RemoteAddress
);
42 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
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
;
50 ListenReceive
->SequenceNumber
= Qelt
->Seq
;
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
));
57 TaCopyTransportAddressInPlace( &ListenReceive
->Address
,
58 Qelt
->ConnInfo
->RemoteAddress
);
60 IPAddr
= (PTA_IP_ADDRESS
)&ListenReceive
->Address
;
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
;
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
));
82 if( Irp
->MdlAddress
) UnlockRequest( Irp
, IoGetCurrentIrpStackLocation( Irp
) );
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
;
91 static NTSTATUS NTAPI ListenComplete
92 ( PDEVICE_OBJECT DeviceObject
,
95 NTSTATUS Status
= STATUS_SUCCESS
;
96 PAFD_FCB FCB
= (PAFD_FCB
)Context
;
97 PAFD_TDI_OBJECT_QELT Qelt
;
98 PLIST_ENTRY NextIrpEntry
, QeltEntry
;
101 if( !SocketAcquireStateLock( FCB
) )
102 return STATUS_FILE_CLOSED
;
104 FCB
->ListenIrp
.InFlightRequest
= NULL
;
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
);
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
);
125 /* Free ConnectionReturnInfo and ConnectionCallInfo */
126 if (FCB
->ListenIrp
.ConnectionReturnInfo
)
128 ExFreePool(FCB
->ListenIrp
.ConnectionReturnInfo
);
129 FCB
->ListenIrp
.ConnectionReturnInfo
= NULL
;
132 if (FCB
->ListenIrp
.ConnectionCallInfo
)
134 ExFreePool(FCB
->ListenIrp
.ConnectionCallInfo
);
135 FCB
->ListenIrp
.ConnectionCallInfo
= NULL
;
138 SocketStateUnlock( FCB
);
139 return STATUS_FILE_CLOSED
;
142 AFD_DbgPrint(MID_TRACE
,("Completing listen request.\n"));
143 AFD_DbgPrint(MID_TRACE
,("IoStatus was %x\n", FCB
->ListenIrp
.Iosb
.Status
));
145 Qelt
= ExAllocatePool( NonPagedPool
, sizeof(*Qelt
) );
147 Status
= STATUS_NO_MEMORY
;
150 FCB
->LocalAddress
->Address
[0].AddressType
;
152 Qelt
->Object
= FCB
->Connection
;
153 Qelt
->Seq
= FCB
->ConnSeq
++;
154 AFD_DbgPrint(MID_TRACE
,("Address Type: %d (RA %x)\n",
157 ConnectionReturnInfo
->RemoteAddress
));
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
;
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
;
175 ( CONTAINING_RECORD( PendingIrp
, IRP
,
176 Tail
.Overlay
.ListEntry
),
177 CONTAINING_RECORD( PendingConn
, AFD_TDI_OBJECT_QELT
,
181 if( FCB
->ListenIrp
.ConnectionCallInfo
) {
182 ExFreePool( FCB
->ListenIrp
.ConnectionCallInfo
);
183 FCB
->ListenIrp
.ConnectionCallInfo
= NULL
;
186 if( FCB
->ListenIrp
.ConnectionReturnInfo
) {
187 ExFreePool( FCB
->ListenIrp
.ConnectionReturnInfo
);
188 FCB
->ListenIrp
.ConnectionReturnInfo
= NULL
;
191 FCB
->NeedsNewListen
= TRUE
;
193 /* Trigger a select return if appropriate */
194 if( !IsListEmpty( &FCB
->PendingConnections
) ) {
195 FCB
->PollState
|= AFD_EVENT_ACCEPT
;
197 FCB
->PollState
&= ~AFD_EVENT_ACCEPT
;
200 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
202 SocketStateUnlock( FCB
);
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
;
214 AFD_DbgPrint(MID_TRACE
,("Called on %x\n", FCB
));
216 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
218 if( !(ListenReq
= LockRequest( Irp
, IrpSp
)) )
219 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
,
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 );
228 FCB
->DelayedAccept
= ListenReq
->UseDelayedAcceptance
;
230 AFD_DbgPrint(MID_TRACE
,("ADDRESSFILE: %x\n", FCB
->AddressFile
.Handle
));
232 Status
= WarmSocketForConnection( FCB
);
234 AFD_DbgPrint(MID_TRACE
,("Status from warmsocket %x\n", Status
));
236 if( !NT_SUCCESS(Status
) ) return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
238 TdiBuildNullConnectionInfo
239 ( &FCB
->ListenIrp
.ConnectionCallInfo
,
240 FCB
->LocalAddress
->Address
[0].AddressType
);
241 TdiBuildNullConnectionInfo
242 ( &FCB
->ListenIrp
.ConnectionReturnInfo
,
243 FCB
->LocalAddress
->Address
[0].AddressType
);
245 if( !FCB
->ListenIrp
.ConnectionReturnInfo
|| !FCB
->ListenIrp
.ConnectionCallInfo
)
247 if (FCB
->ListenIrp
.ConnectionReturnInfo
)
249 ExFreePool(FCB
->ListenIrp
.ConnectionReturnInfo
);
250 FCB
->ListenIrp
.ConnectionReturnInfo
= NULL
;
253 if (FCB
->ListenIrp
.ConnectionCallInfo
)
255 ExFreePool(FCB
->ListenIrp
.ConnectionCallInfo
);
256 FCB
->ListenIrp
.ConnectionCallInfo
= NULL
;
259 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
262 FCB
->State
= SOCKET_STATE_LISTENING
;
264 Status
= TdiListen( &FCB
->ListenIrp
.InFlightRequest
,
265 FCB
->Connection
.Object
,
266 &FCB
->ListenIrp
.ConnectionCallInfo
,
267 &FCB
->ListenIrp
.ConnectionReturnInfo
,
268 &FCB
->ListenIrp
.Iosb
,
272 if( Status
== STATUS_PENDING
)
273 Status
= STATUS_SUCCESS
;
275 if (NT_SUCCESS(Status
))
276 FCB
->NeedsNewListen
= FALSE
;
278 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
279 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
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
;
288 AFD_DbgPrint(MID_TRACE
,("Called\n"));
290 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
292 if( !IsListEmpty( &FCB
->PendingConnections
) ) {
293 PLIST_ENTRY PendingConn
= FCB
->PendingConnections
.Flink
;
295 /* We have a pending connection ... complete this irp right away */
296 Status
= SatisfyPreAccept
299 ( PendingConn
, AFD_TDI_OBJECT_QELT
, ListEntry
) );
301 AFD_DbgPrint(MID_TRACE
,("Completed a wait for accept\n"));
303 if ( IsListEmpty( &FCB
->PendingConnections
) )
304 FCB
->PollState
&= ~AFD_EVENT_ACCEPT
;
306 FCB
->PollState
|= AFD_EVENT_ACCEPT
;
308 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
310 SocketStateUnlock( FCB
);
313 AFD_DbgPrint(MID_TRACE
,("Holding\n"));
315 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_PREACCEPT
);
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
;
329 AFD_DbgPrint(MID_TRACE
,("Called\n"));
331 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
333 if( FCB
->NeedsNewListen
) {
334 AFD_DbgPrint(MID_TRACE
,("ADDRESSFILE: %x\n", FCB
->AddressFile
.Handle
));
336 /* Launch new accept socket */
337 Status
= WarmSocketForConnection( FCB
);
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
);
347 if( !FCB
->ListenIrp
.ConnectionReturnInfo
|| !FCB
->ListenIrp
.ConnectionCallInfo
)
349 if (FCB
->ListenIrp
.ConnectionReturnInfo
)
351 ExFreePool(FCB
->ListenIrp
.ConnectionReturnInfo
);
352 FCB
->ListenIrp
.ConnectionReturnInfo
= NULL
;
355 if (FCB
->ListenIrp
.ConnectionCallInfo
)
357 ExFreePool(FCB
->ListenIrp
.ConnectionCallInfo
);
358 FCB
->ListenIrp
.ConnectionCallInfo
= NULL
;
361 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
, 0 );
364 Status
= TdiListen( &FCB
->ListenIrp
.InFlightRequest
,
365 FCB
->Connection
.Object
,
366 &FCB
->ListenIrp
.ConnectionCallInfo
,
367 &FCB
->ListenIrp
.ConnectionReturnInfo
,
368 &FCB
->ListenIrp
.Iosb
,
372 if( Status
== STATUS_PENDING
)
373 Status
= STATUS_SUCCESS
;
375 if( !NT_SUCCESS(Status
) )
376 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
378 FCB
->NeedsNewListen
= FALSE
;
379 } else return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
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
);
388 AFD_DbgPrint(MID_TRACE
,("Comparing Seq %d to Q %d\n",
389 AcceptData
->SequenceNumber
,
390 PendingConnObj
->Seq
));
392 if( PendingConnObj
->Seq
== AcceptData
->SequenceNumber
) {
393 PFILE_OBJECT NewFileObject
= NULL
;
395 RemoveEntryList( PendingConn
);
397 Status
= ObReferenceObjectByHandle
398 ( AcceptData
->ListenHandle
,
402 (PVOID
*)&NewFileObject
,
405 if( !NT_SUCCESS(Status
) ) return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
407 ASSERT(NewFileObject
!= FileObject
);
408 ASSERT(NewFileObject
->FsContext
!= FCB
);
410 /* We have a pending connection ... complete this irp right away */
411 Status
= SatisfyAccept( DeviceExt
, Irp
, NewFileObject
, PendingConnObj
);
413 ObDereferenceObject( NewFileObject
);
415 AFD_DbgPrint(MID_TRACE
,("Completed a wait for accept\n"));
417 ExFreePool( PendingConnObj
);
419 if( IsListEmpty( &FCB
->PendingConnections
) ) {
420 FCB
->PollState
&= ~AFD_EVENT_ACCEPT
;
422 FCB
->PollState
|= AFD_EVENT_ACCEPT
;
425 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
427 SocketStateUnlock( FCB
);
432 return UnlockAndMaybeComplete( FCB
, STATUS_UNSUCCESSFUL
, Irp
, 0 );