2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/select.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
11 #include "tdi_proto.h"
15 static VOID
PrintEvents( ULONG Events
) {
17 char *events_list
[] = { "AFD_EVENT_RECEIVE",
18 "AFD_EVENT_OOB_RECEIVE",
20 "AFD_EVENT_DISCONNECT",
25 "AFD_EVENT_CONNECT_FAIL",
27 "AFD_EVENT_GROUP_QOS",
31 for( i
= 0; events_list
[i
]; i
++ )
32 if( Events
& (1 << i
) ) AFD_DbgPrint(MID_TRACE
,("%s ", events_list
[i
] ));
36 static VOID
CopyBackStatus( PAFD_HANDLE HandleArray
,
40 for( i
= 0; i
< HandleCount
; i
++ ) {
41 HandleArray
[i
].Events
= HandleArray
[i
].Status
;
42 HandleArray
[i
].Status
= 0;
46 static VOID
ZeroEvents( PAFD_HANDLE HandleArray
,
50 for( i
= 0; i
< HandleCount
; i
++ ) {
51 HandleArray
[i
].Status
= 0;
52 HandleArray
[i
].Events
= 0;
57 /* you must pass either Poll OR Irp */
58 static VOID
SignalSocket(
59 PAFD_ACTIVE_POLL Poll OPTIONAL
,
61 PAFD_POLL_INFO PollReq
,
66 PIRP Irp
= _Irp
? _Irp
: Poll
->Irp
;
67 AFD_DbgPrint(MID_TRACE
,("Called (Status %x)\n", Status
));
71 KeCancelTimer( &Poll
->Timer
);
72 RemoveEntryList( &Poll
->ListEntry
);
76 Irp
->IoStatus
.Status
= Status
;
77 Irp
->IoStatus
.Information
=
78 FIELD_OFFSET(AFD_POLL_INFO
, Handles
) + sizeof(AFD_HANDLE
) * PollReq
->HandleCount
;
79 CopyBackStatus( PollReq
->Handles
,
80 PollReq
->HandleCount
);
81 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
84 ("Handle(%x): Got %x,%x\n",
85 PollReq
->Handles
[i
].Handle
,
86 PollReq
->Handles
[i
].Events
,
87 PollReq
->Handles
[i
].Status
));
89 UnlockHandles( AFD_HANDLES(PollReq
), PollReq
->HandleCount
);
90 if( Irp
->MdlAddress
) UnlockRequest( Irp
, IoGetCurrentIrpStackLocation( Irp
) );
91 AFD_DbgPrint(MID_TRACE
,("Completing\n"));
92 IoCompleteRequest( Irp
, IO_NETWORK_INCREMENT
);
93 AFD_DbgPrint(MID_TRACE
,("Done\n"));
96 static VOID
SelectTimeout( PKDPC Dpc
,
97 PVOID DeferredContext
,
98 PVOID SystemArgument1
,
99 PVOID SystemArgument2
) {
100 PAFD_ACTIVE_POLL Poll
= DeferredContext
;
101 PAFD_POLL_INFO PollReq
;
104 PAFD_DEVICE_EXTENSION DeviceExt
;
106 AFD_DbgPrint(MID_TRACE
,("Called\n"));
109 DeviceExt
= Poll
->DeviceExt
;
110 PollReq
= Irp
->AssociatedIrp
.SystemBuffer
;
112 ZeroEvents( PollReq
->Handles
, PollReq
->HandleCount
);
114 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
115 SignalSocket( Poll
, NULL
, PollReq
, STATUS_TIMEOUT
);
116 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
118 AFD_DbgPrint(MID_TRACE
,("Timeout\n"));
121 VOID
KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt
,
122 PFILE_OBJECT FileObject
,
123 BOOLEAN OnlyExclusive
) {
125 PLIST_ENTRY ListEntry
;
126 PAFD_ACTIVE_POLL Poll
;
128 PAFD_POLL_INFO PollReq
;
129 PAFD_HANDLE HandleArray
;
132 AFD_DbgPrint(MID_TRACE
,("Killing selects that refer to %x\n", FileObject
));
134 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
136 ListEntry
= DeviceExt
->Polls
.Flink
;
137 while ( ListEntry
!= &DeviceExt
->Polls
) {
138 Poll
= CONTAINING_RECORD(ListEntry
, AFD_ACTIVE_POLL
, ListEntry
);
139 ListEntry
= ListEntry
->Flink
;
141 PollReq
= Irp
->AssociatedIrp
.SystemBuffer
;
142 HandleArray
= AFD_HANDLES(PollReq
);
144 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
145 AFD_DbgPrint(MAX_TRACE
,("Req: %x, This %x\n",
146 HandleArray
[i
].Handle
, FileObject
));
147 if( (PVOID
)HandleArray
[i
].Handle
== FileObject
&&
148 (!OnlyExclusive
|| (OnlyExclusive
&& Poll
->Exclusive
)) ) {
149 ZeroEvents( PollReq
->Handles
, PollReq
->HandleCount
);
150 SignalSocket( Poll
, NULL
, PollReq
, STATUS_CANCELLED
);
155 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
157 AFD_DbgPrint(MID_TRACE
,("Done\n"));
161 AfdSelect( PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
162 PIO_STACK_LOCATION IrpSp
) {
163 NTSTATUS Status
= STATUS_NO_MEMORY
;
165 PFILE_OBJECT FileObject
;
166 PAFD_POLL_INFO PollReq
= Irp
->AssociatedIrp
.SystemBuffer
;
167 PAFD_DEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
168 UINT CopySize
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
170 CopySize
+ sizeof(AFD_ACTIVE_POLL
) - sizeof(AFD_POLL_INFO
);
172 UINT i
, Signalled
= 0;
173 ULONG Exclusive
= PollReq
->Exclusive
;
175 AFD_DbgPrint(MID_TRACE
,("Called (HandleCount %d Timeout %d)\n",
176 PollReq
->HandleCount
,
177 (INT
)(PollReq
->Timeout
.QuadPart
)));
179 SET_AFD_HANDLES(PollReq
,
180 LockHandles( PollReq
->Handles
, PollReq
->HandleCount
));
182 if( !AFD_HANDLES(PollReq
) ) {
183 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
184 Irp
->IoStatus
.Information
= 0;
185 IoCompleteRequest( Irp
, IO_NETWORK_INCREMENT
);
186 return STATUS_NO_MEMORY
;
190 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
191 if( !AFD_HANDLES(PollReq
)[i
].Handle
) continue;
193 KillSelectsForFCB( DeviceExt
,
194 (PFILE_OBJECT
)AFD_HANDLES(PollReq
)[i
].Handle
,
199 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
201 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
202 if( !AFD_HANDLES(PollReq
)[i
].Handle
) continue;
204 FileObject
= (PFILE_OBJECT
)AFD_HANDLES(PollReq
)[i
].Handle
;
205 FCB
= FileObject
->FsContext
;
207 AFD_DbgPrint(MID_TRACE
, ("AFD: Select Events: "));
208 PrintEvents( PollReq
->Handles
[i
].Events
);
209 AFD_DbgPrint(MID_TRACE
,("\n"));
211 PollReq
->Handles
[i
].Status
=
212 PollReq
->Handles
[i
].Events
& FCB
->PollState
;
213 if( PollReq
->Handles
[i
].Status
) {
214 AFD_DbgPrint(MID_TRACE
,("Signalling %x with %x\n",
215 FCB
, FCB
->PollState
));
221 Status
= STATUS_SUCCESS
;
222 Irp
->IoStatus
.Status
= Status
;
223 SignalSocket( NULL
, Irp
, PollReq
, Status
);
226 PAFD_ACTIVE_POLL Poll
= NULL
;
228 Poll
= ExAllocatePool( NonPagedPool
, AllocSize
);
232 Poll
->DeviceExt
= DeviceExt
;
233 Poll
->Exclusive
= Exclusive
;
235 KeInitializeTimerEx( &Poll
->Timer
, NotificationTimer
);
237 KeInitializeDpc( (PRKDPC
)&Poll
->TimeoutDpc
,
238 (PKDEFERRED_ROUTINE
)SelectTimeout
,
241 InsertTailList( &DeviceExt
->Polls
, &Poll
->ListEntry
);
243 KeSetTimer( &Poll
->Timer
, PollReq
->Timeout
, &Poll
->TimeoutDpc
);
245 Status
= STATUS_PENDING
;
246 IoMarkIrpPending( Irp
);
248 AFD_DbgPrint(MAX_TRACE
, ("FIXME: do something with the IRP!\n"));
249 Status
= STATUS_NO_MEMORY
;
253 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
255 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
261 AfdEventSelect( PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
262 PIO_STACK_LOCATION IrpSp
) {
263 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
264 NTSTATUS Status
= STATUS_NO_MEMORY
;
265 PAFD_EVENT_SELECT_INFO EventSelectInfo
=
266 (PAFD_EVENT_SELECT_INFO
)LockRequest( Irp
, IrpSp
);
267 PAFD_FCB FCB
= FileObject
->FsContext
;
269 if( !SocketAcquireStateLock( FCB
) ) {
270 return LostSocket( Irp
);
273 if ( !EventSelectInfo
) {
274 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
,
277 AFD_DbgPrint(MID_TRACE
,("Called (Event %x Triggers %x)\n",
278 EventSelectInfo
->EventObject
,
279 EventSelectInfo
->Events
));
281 if( FCB
->EventSelect
) ObDereferenceObject( FCB
->EventSelect
);
282 FCB
->EventSelect
= NULL
;
284 if( EventSelectInfo
->EventObject
&& EventSelectInfo
->Events
) {
285 Status
= ObReferenceObjectByHandle( (PVOID
)EventSelectInfo
->
290 (PVOID
*)&FCB
->EventSelect
,
293 if( !NT_SUCCESS(Status
) )
294 FCB
->EventSelect
= NULL
;
296 FCB
->EventSelectTriggers
= EventSelectInfo
->Events
;
298 Status
= STATUS_INVALID_PARAMETER
;
300 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
302 return UnlockAndMaybeComplete( FCB
, Status
, Irp
,
307 AfdEnumEvents( PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
308 PIO_STACK_LOCATION IrpSp
) {
309 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
310 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq
=
311 (PAFD_ENUM_NETWORK_EVENTS_INFO
)LockRequest( Irp
, IrpSp
);
312 PAFD_FCB FCB
= FileObject
->FsContext
;
314 AFD_DbgPrint(MID_TRACE
,("Called (FCB %x)\n", FCB
));
316 if( !SocketAcquireStateLock( FCB
) ) {
317 return LostSocket( Irp
);
321 return UnlockAndMaybeComplete( FCB
, STATUS_NO_MEMORY
, Irp
,
325 EnumReq
->PollEvents
= FCB
->PollState
;
326 RtlZeroMemory( EnumReq
->EventStatus
, sizeof(EnumReq
->EventStatus
) );
328 return UnlockAndMaybeComplete( FCB
, STATUS_SUCCESS
, Irp
,
332 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
333 static BOOLEAN
UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll
, PFILE_OBJECT FileObject
) {
337 PAFD_POLL_INFO PollReq
= Poll
->Irp
->AssociatedIrp
.SystemBuffer
;
339 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL
);
341 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
342 if( !AFD_HANDLES(PollReq
)[i
].Handle
) continue;
344 FileObject
= (PFILE_OBJECT
)AFD_HANDLES(PollReq
)[i
].Handle
;
345 FCB
= FileObject
->FsContext
;
347 PollReq
->Handles
[i
].Status
= PollReq
->Handles
[i
].Events
& FCB
->PollState
;
348 if( PollReq
->Handles
[i
].Status
) {
349 AFD_DbgPrint(MID_TRACE
,("Signalling %x with %x\n",
350 FCB
, FCB
->PollState
));
355 return Signalled
? 1 : 0;
358 VOID
PollReeval( PAFD_DEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
) {
359 PAFD_ACTIVE_POLL Poll
= NULL
;
360 PLIST_ENTRY ThePollEnt
= NULL
;
363 PAFD_POLL_INFO PollReq
;
365 AFD_DbgPrint(MID_TRACE
,("Called: DeviceExt %x FileObject %x\n",
366 DeviceExt
, FileObject
));
368 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
370 /* Take care of any event select signalling */
371 FCB
= (PAFD_FCB
)FileObject
->FsContext
;
374 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
378 /* Now signal normal select irps */
379 ThePollEnt
= DeviceExt
->Polls
.Flink
;
381 while( ThePollEnt
!= &DeviceExt
->Polls
) {
382 Poll
= CONTAINING_RECORD( ThePollEnt
, AFD_ACTIVE_POLL
, ListEntry
);
383 PollReq
= Poll
->Irp
->AssociatedIrp
.SystemBuffer
;
384 AFD_DbgPrint(MID_TRACE
,("Checking poll %x\n", Poll
));
386 if( UpdatePollWithFCB( Poll
, FileObject
) ) {
387 ThePollEnt
= ThePollEnt
->Flink
;
388 AFD_DbgPrint(MID_TRACE
,("Signalling socket\n"));
389 SignalSocket( Poll
, NULL
, PollReq
, STATUS_SUCCESS
);
391 ThePollEnt
= ThePollEnt
->Flink
;
394 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
396 if( FCB
->EventSelect
&& (FCB
->PollState
& FCB
->EventSelectTriggers
) ) {
397 AFD_DbgPrint(MID_TRACE
,("Setting event %x\n", FCB
->EventSelect
));
398 KeSetEvent( FCB
->EventSelect
, IO_NETWORK_INCREMENT
, FALSE
);
401 AFD_DbgPrint(MID_TRACE
,("Leaving\n"));