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)
13 static NTSTATUS
SatisfyAccept( PAFD_DEVICE_EXTENSION DeviceExt
,
15 PFILE_OBJECT NewFileObject
,
16 PAFD_TDI_OBJECT_QELT Qelt
) {
17 PAFD_FCB FCB
= NewFileObject
->FsContext
;
20 UNREFERENCED_PARAMETER(DeviceExt
);
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 %p)\n", FCB
));
28 FCB
->Connection
= Qelt
->Object
;
30 if (FCB
->RemoteAddress
)
32 ExFreePoolWithTag(FCB
->RemoteAddress
, TAG_AFD_TRANSPORT_ADDRESS
);
36 TaCopyTransportAddress( Qelt
->ConnInfo
->RemoteAddress
);
38 if( !FCB
->RemoteAddress
)
39 Status
= STATUS_NO_MEMORY
;
41 Status
= MakeSocketIntoConnection( FCB
);
43 if (NT_SUCCESS(Status
))
44 Status
= TdiBuildConnectionInfo(&FCB
->ConnectCallInfo
, FCB
->RemoteAddress
);
46 if (NT_SUCCESS(Status
))
47 Status
= TdiBuildConnectionInfo(&FCB
->ConnectReturnInfo
, FCB
->RemoteAddress
);
49 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
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
;
57 ListenReceive
->SequenceNumber
= Qelt
->Seq
;
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
));
64 TaCopyTransportAddressInPlace( &ListenReceive
->Address
,
65 Qelt
->ConnInfo
->RemoteAddress
);
67 IPAddr
= (PTA_IP_ADDRESS
)&ListenReceive
->Address
;
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
));
80 if( Irp
->MdlAddress
) UnlockRequest( Irp
, IoGetCurrentIrpStackLocation( Irp
) );
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
;
89 static IO_COMPLETION_ROUTINE ListenComplete
;
90 static NTSTATUS NTAPI
ListenComplete( PDEVICE_OBJECT DeviceObject
,
93 NTSTATUS Status
= STATUS_SUCCESS
;
94 PAFD_FCB FCB
= (PAFD_FCB
)Context
;
95 PAFD_TDI_OBJECT_QELT Qelt
;
96 PLIST_ENTRY NextIrpEntry
;
99 UNREFERENCED_PARAMETER(DeviceObject
);
101 if( !SocketAcquireStateLock( FCB
) )
102 return STATUS_FILE_CLOSED
;
104 ASSERT(FCB
->ListenIrp
.InFlightRequest
== Irp
);
105 FCB
->ListenIrp
.InFlightRequest
= NULL
;
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
);
119 /* Free ConnectionReturnInfo and ConnectionCallInfo */
120 if (FCB
->ListenIrp
.ConnectionReturnInfo
)
122 ExFreePoolWithTag(FCB
->ListenIrp
.ConnectionReturnInfo
,
123 TAG_AFD_TDI_CONNECTION_INFORMATION
);
125 FCB
->ListenIrp
.ConnectionReturnInfo
= NULL
;
128 if (FCB
->ListenIrp
.ConnectionCallInfo
)
130 ExFreePoolWithTag(FCB
->ListenIrp
.ConnectionCallInfo
,
131 TAG_AFD_TDI_CONNECTION_INFORMATION
);
133 FCB
->ListenIrp
.ConnectionCallInfo
= NULL
;
136 SocketStateUnlock( FCB
);
137 return STATUS_FILE_CLOSED
;
140 AFD_DbgPrint(MID_TRACE
,("Completing listen request.\n"));
141 AFD_DbgPrint(MID_TRACE
,("IoStatus was %x\n", Irp
->IoStatus
.Status
));
143 if (Irp
->IoStatus
.Status
!= STATUS_SUCCESS
)
145 SocketStateUnlock(FCB
);
146 return Irp
->IoStatus
.Status
;
149 Qelt
= ExAllocatePoolWithTag(NonPagedPool
,
151 TAG_AFD_ACCEPT_QUEUE
);
154 Status
= STATUS_NO_MEMORY
;
157 FCB
->LocalAddress
->Address
[0].AddressType
;
159 Qelt
->Object
= FCB
->Connection
;
160 Qelt
->Seq
= FCB
->ConnSeq
++;
161 AFD_DbgPrint(MID_TRACE
,("Address Type: %u (RA %p)\n",
164 ConnectionReturnInfo
->RemoteAddress
));
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
);
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
;
182 ( CONTAINING_RECORD( PendingIrp
, IRP
,
183 Tail
.Overlay
.ListEntry
),
184 CONTAINING_RECORD( PendingConn
, AFD_TDI_OBJECT_QELT
,
188 /* Launch new accept socket */
189 Status
= WarmSocketForConnection( FCB
);
191 if (NT_SUCCESS(Status
))
193 Status
= TdiBuildNullConnectionInfoInPlace(FCB
->ListenIrp
.ConnectionCallInfo
,
194 FCB
->LocalAddress
->Address
[0].AddressType
);
195 ASSERT(Status
== STATUS_SUCCESS
);
197 Status
= TdiBuildNullConnectionInfoInPlace(FCB
->ListenIrp
.ConnectionReturnInfo
,
198 FCB
->LocalAddress
->Address
[0].AddressType
);
199 ASSERT(Status
== STATUS_SUCCESS
);
201 Status
= TdiListen( &FCB
->ListenIrp
.InFlightRequest
,
202 FCB
->Connection
.Object
,
203 &FCB
->ListenIrp
.ConnectionCallInfo
,
204 &FCB
->ListenIrp
.ConnectionReturnInfo
,
208 if (Status
== STATUS_PENDING
)
209 Status
= STATUS_SUCCESS
;
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
);
218 FCB
->PollState
&= ~AFD_EVENT_ACCEPT
;
220 SocketStateUnlock( FCB
);
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
;
232 UNREFERENCED_PARAMETER(DeviceObject
);
234 AFD_DbgPrint(MID_TRACE
,("Called on %p\n", FCB
));
236 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
238 if( !(ListenReq
= LockRequest( Irp
, IrpSp
, FALSE
, NULL
)) )
239 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
,
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 );
248 FCB
->DelayedAccept
= ListenReq
->UseDelayedAcceptance
;
250 AFD_DbgPrint(MID_TRACE
,("ADDRESSFILE: %p\n", FCB
->AddressFile
.Handle
));
252 Status
= WarmSocketForConnection( FCB
);
254 AFD_DbgPrint(MID_TRACE
,("Status from warmsocket %x\n", Status
));
256 if( !NT_SUCCESS(Status
) ) return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
258 Status
= TdiBuildNullConnectionInfo
259 ( &FCB
->ListenIrp
.ConnectionCallInfo
,
260 FCB
->LocalAddress
->Address
[0].AddressType
);
262 if (!NT_SUCCESS(Status
)) return UnlockAndMaybeComplete(FCB
, Status
, Irp
, 0);
264 Status
= TdiBuildNullConnectionInfo
265 ( &FCB
->ListenIrp
.ConnectionReturnInfo
,
266 FCB
->LocalAddress
->Address
[0].AddressType
);
268 if (!NT_SUCCESS(Status
))
270 ExFreePoolWithTag(FCB
->ListenIrp
.ConnectionCallInfo
,
271 TAG_AFD_TDI_CONNECTION_INFORMATION
);
273 FCB
->ListenIrp
.ConnectionCallInfo
= NULL
;
274 return UnlockAndMaybeComplete(FCB
, Status
, Irp
, 0);
277 FCB
->State
= SOCKET_STATE_LISTENING
;
279 Status
= TdiListen( &FCB
->ListenIrp
.InFlightRequest
,
280 FCB
->Connection
.Object
,
281 &FCB
->ListenIrp
.ConnectionCallInfo
,
282 &FCB
->ListenIrp
.ConnectionReturnInfo
,
286 if( Status
== STATUS_PENDING
)
287 Status
= STATUS_SUCCESS
;
289 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
290 return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
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
;
299 UNREFERENCED_PARAMETER(DeviceObject
);
301 AFD_DbgPrint(MID_TRACE
,("Called\n"));
303 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
305 if( !IsListEmpty( &FCB
->PendingConnections
) ) {
306 PLIST_ENTRY PendingConn
= FCB
->PendingConnections
.Flink
;
308 /* We have a pending connection ... complete this irp right away */
309 Status
= SatisfyPreAccept
312 ( PendingConn
, AFD_TDI_OBJECT_QELT
, ListEntry
) );
314 AFD_DbgPrint(MID_TRACE
,("Completed a wait for accept\n"));
316 if ( !IsListEmpty( &FCB
->PendingConnections
) )
318 FCB
->PollState
|= AFD_EVENT_ACCEPT
;
319 FCB
->PollStatus
[FD_ACCEPT_BIT
] = STATUS_SUCCESS
;
320 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
322 FCB
->PollState
&= ~AFD_EVENT_ACCEPT
;
324 SocketStateUnlock( FCB
);
326 } else if (FCB
->NonBlocking
) {
327 AFD_DbgPrint(MIN_TRACE
,("No connection ready on a non-blocking socket\n"));
329 return UnlockAndMaybeComplete(FCB
, STATUS_CANT_WAIT
, Irp
, 0);
331 AFD_DbgPrint(MID_TRACE
,("Holding\n"));
333 return LeaveIrpUntilLater( FCB
, Irp
, FUNCTION_PREACCEPT
);
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
;
347 AFD_DbgPrint(MID_TRACE
,("Called\n"));
349 if( !SocketAcquireStateLock( FCB
) ) return LostSocket( Irp
);
351 FCB
->EventSelectDisabled
&= ~AFD_EVENT_ACCEPT
;
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
);
359 AFD_DbgPrint(MID_TRACE
,("Comparing Seq %u to Q %u\n",
360 AcceptData
->SequenceNumber
,
361 PendingConnObj
->Seq
));
363 if( PendingConnObj
->Seq
== AcceptData
->SequenceNumber
) {
364 PFILE_OBJECT NewFileObject
= NULL
;
366 RemoveEntryList( PendingConn
);
368 Status
= ObReferenceObjectByHandle
369 ( AcceptData
->ListenHandle
,
373 (PVOID
*)&NewFileObject
,
376 if( !NT_SUCCESS(Status
) ) return UnlockAndMaybeComplete( FCB
, Status
, Irp
, 0 );
378 ASSERT(NewFileObject
!= FileObject
);
379 ASSERT(NewFileObject
->FsContext
!= FCB
);
381 /* We have a pending connection ... complete this irp right away */
382 Status
= SatisfyAccept( DeviceExt
, Irp
, NewFileObject
, PendingConnObj
);
384 ObDereferenceObject( NewFileObject
);
386 AFD_DbgPrint(MID_TRACE
,("Completed a wait for accept\n"));
388 ExFreePoolWithTag(PendingConnObj
, TAG_AFD_ACCEPT_QUEUE
);
390 if( !IsListEmpty( &FCB
->PendingConnections
) )
392 FCB
->PollState
|= AFD_EVENT_ACCEPT
;
393 FCB
->PollStatus
[FD_ACCEPT_BIT
] = STATUS_SUCCESS
;
394 PollReeval( FCB
->DeviceExt
, FCB
->FileObject
);
396 FCB
->PollState
&= ~AFD_EVENT_ACCEPT
;
398 SocketStateUnlock( FCB
);
403 AFD_DbgPrint(MIN_TRACE
,("No connection waiting\n"));
405 return UnlockAndMaybeComplete( FCB
, STATUS_UNSUCCESSFUL
, Irp
, 0 );