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 VOID
CopyBackStatus( PAFD_HANDLE HandleArray
,
19 for( i
= 0; i
< HandleCount
; i
++ ) {
20 HandleArray
[i
].Events
= HandleArray
[i
].Status
;
21 HandleArray
[i
].Status
= 0;
25 VOID
ZeroEvents( PAFD_HANDLE HandleArray
,
29 for( i
= 0; i
< HandleCount
; i
++ )
30 HandleArray
[i
].Status
= 0;
33 VOID
RemoveSelect( PAFD_ACTIVE_POLL Poll
) {
34 AFD_DbgPrint(MID_TRACE
,("Called\n"));
36 RemoveEntryList( &Poll
->ListEntry
);
37 KeCancelTimer( &Poll
->Timer
);
41 AFD_DbgPrint(MID_TRACE
,("Done\n"));
44 VOID
SignalSocket( PAFD_ACTIVE_POLL Poll
, PAFD_POLL_INFO PollReq
,
47 AFD_DbgPrint(MID_TRACE
,("Called (Status %x)\n", Status
));
48 Poll
->Irp
->IoStatus
.Status
= Status
;
49 Poll
->Irp
->IoStatus
.Information
=
50 FIELD_OFFSET(AFD_POLL_INFO
, Handles
) + sizeof(AFD_HANDLE
) * PollReq
->HandleCount
;
51 CopyBackStatus( PollReq
->Handles
,
52 PollReq
->HandleCount
);
53 UnlockHandles( AFD_HANDLES(PollReq
), PollReq
->HandleCount
);
54 AFD_DbgPrint(MID_TRACE
,("Completing\n"));
55 IoCompleteRequest( Irp
, IO_NETWORK_INCREMENT
);
56 RemoveEntryList( &Poll
->ListEntry
);
58 AFD_DbgPrint(MID_TRACE
,("Done\n"));
61 VOID
SelectTimeout( PKDPC Dpc
,
62 PVOID DeferredContext
,
63 PVOID SystemArgument1
,
64 PVOID SystemArgument2
) {
65 PAFD_ACTIVE_POLL Poll
= DeferredContext
;
66 PAFD_POLL_INFO PollReq
;
69 PAFD_DEVICE_EXTENSION DeviceExt
;
71 AFD_DbgPrint(MID_TRACE
,("Called\n"));
74 DeviceExt
= Poll
->DeviceExt
;
75 PollReq
= Irp
->AssociatedIrp
.SystemBuffer
;
77 ZeroEvents( PollReq
->Handles
, PollReq
->HandleCount
);
79 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
80 SignalSocket( Poll
, PollReq
, STATUS_TIMEOUT
);
81 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
83 AFD_DbgPrint(MID_TRACE
,("Timeout\n"));
86 VOID
KillExclusiveSelects( PAFD_DEVICE_EXTENSION DeviceExt
) {
88 PLIST_ENTRY ListEntry
;
89 PAFD_ACTIVE_POLL Poll
;
91 PAFD_POLL_INFO PollReq
;
93 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
95 ListEntry
= DeviceExt
->Polls
.Flink
;
96 while ( ListEntry
!= &DeviceExt
->Polls
) {
97 Poll
= CONTAINING_RECORD(ListEntry
, AFD_ACTIVE_POLL
, ListEntry
);
98 ListEntry
= ListEntry
->Flink
;
99 if( Poll
->Exclusive
) {
101 PollReq
= Irp
->AssociatedIrp
.SystemBuffer
;
102 ZeroEvents( PollReq
->Handles
, PollReq
->HandleCount
);
103 SignalSocket( Poll
, PollReq
, STATUS_CANCELLED
);
107 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
111 AfdSelect( PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
112 PIO_STACK_LOCATION IrpSp
) {
113 NTSTATUS Status
= STATUS_NO_MEMORY
;
115 PFILE_OBJECT FileObject
;
116 PAFD_POLL_INFO PollReq
= Irp
->AssociatedIrp
.SystemBuffer
;
117 PAFD_DEVICE_EXTENSION DeviceExt
= DeviceObject
->DeviceExtension
;
118 PAFD_ACTIVE_POLL Poll
= NULL
;
119 UINT CopySize
= IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
;
121 CopySize
+ sizeof(AFD_ACTIVE_POLL
) - sizeof(AFD_POLL_INFO
);
123 UINT i
, Signalled
= 0;
124 ULONG Exclusive
= PollReq
->Exclusive
;
126 AFD_DbgPrint(MID_TRACE
,("Called (HandleCount %d Timeout %d)\n",
127 PollReq
->HandleCount
,
128 (INT
)(PollReq
->Timeout
.QuadPart
)));
130 SET_AFD_HANDLES(PollReq
,
131 LockHandles( PollReq
->Handles
, PollReq
->HandleCount
));
133 if( Exclusive
) KillExclusiveSelects( DeviceExt
);
136 if( !AFD_HANDLES(PollReq
) ) {
137 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
138 Irp
->IoStatus
.Information
= 0;
139 IoCompleteRequest( Irp
, IO_NETWORK_INCREMENT
);
140 return Irp
->IoStatus
.Status
;
143 ZeroEvents( PollReq
->Handles
,
144 PollReq
->HandleCount
);
146 Poll
= ExAllocatePool( NonPagedPool
, AllocSize
);
150 Poll
->DeviceExt
= DeviceExt
;
151 Poll
->Exclusive
= Exclusive
;
153 KeInitializeTimerEx( &Poll
->Timer
, NotificationTimer
);
154 KeSetTimer( &Poll
->Timer
, PollReq
->Timeout
, &Poll
->TimeoutDpc
);
156 KeInitializeDpc( (PRKDPC
)&Poll
->TimeoutDpc
,
157 (PKDEFERRED_ROUTINE
)SelectTimeout
,
160 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
161 InsertTailList( &DeviceExt
->Polls
, &Poll
->ListEntry
);
163 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
164 if( !AFD_HANDLES(PollReq
)[i
].Handle
) continue;
166 FileObject
= (PFILE_OBJECT
)AFD_HANDLES(PollReq
)[i
].Handle
;
167 FCB
= FileObject
->FsContext
;
169 if( (FCB
->PollState
& AFD_EVENT_CLOSE
) ||
170 (PollReq
->Handles
[i
].Status
& AFD_EVENT_CLOSE
) ) {
171 AFD_HANDLES(PollReq
)[i
].Handle
= 0;
172 PollReq
->Handles
[i
].Events
= 0;
173 PollReq
->Handles
[i
].Status
= AFD_EVENT_CLOSE
;
176 PollReq
->Handles
[i
].Status
=
177 PollReq
->Handles
[i
].Events
& FCB
->PollState
;
178 if( PollReq
->Handles
[i
].Status
) {
179 AFD_DbgPrint(MID_TRACE
,("Signalling %x with %x\n",
180 FCB
, FCB
->PollState
));
187 Status
= STATUS_SUCCESS
;
188 Irp
->IoStatus
.Status
= Status
;
189 SignalSocket( Poll
, PollReq
, Status
);
191 Status
= STATUS_PENDING
;
192 IoMarkIrpPending( Irp
);
195 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
196 } else Status
= STATUS_NO_MEMORY
;
198 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
204 AfdEventSelect( PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
205 PIO_STACK_LOCATION IrpSp
) {
206 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
207 NTSTATUS Status
= STATUS_NO_MEMORY
;
208 PAFD_EVENT_SELECT_INFO EventSelectInfo
=
209 (PAFD_EVENT_SELECT_INFO
)LockRequest( Irp
, IrpSp
);
210 PAFD_FCB FCB
= FileObject
->FsContext
;
212 AFD_DbgPrint(MID_TRACE
,("Called (Event %x Triggers %x)\n",
213 EventSelectInfo
->EventObject
,
214 EventSelectInfo
->Events
));
216 if( !SocketAcquireStateLock( FCB
) ) {
217 UnlockRequest( Irp
, IrpSp
);
218 return LostSocket( Irp
, FALSE
);
221 FCB
->EventSelectTriggers
= FCB
->EventsFired
= 0;
222 if( FCB
->EventSelect
) ObDereferenceObject( FCB
->EventSelect
);
223 FCB
->EventSelect
= NULL
;
225 if( EventSelectInfo
->EventObject
&& EventSelectInfo
->Events
) {
226 Status
= ObReferenceObjectByHandle( (PVOID
)EventSelectInfo
->
231 (PVOID
*)&FCB
->EventSelect
,
234 if( !NT_SUCCESS(Status
) )
235 FCB
->EventSelect
= NULL
;
237 FCB
->EventSelectTriggers
= EventSelectInfo
->Events
;
238 } else /* Work done, cancelling select */
239 Status
= STATUS_SUCCESS
;
241 AFD_DbgPrint(MID_TRACE
,("Returning %x\n", Status
));
243 return UnlockAndMaybeComplete( FCB
, STATUS_SUCCESS
, Irp
,
248 AfdEnumEvents( PDEVICE_OBJECT DeviceObject
, PIRP Irp
,
249 PIO_STACK_LOCATION IrpSp
) {
250 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
251 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq
=
252 (PAFD_ENUM_NETWORK_EVENTS_INFO
)LockRequest( Irp
, IrpSp
);
253 PAFD_FCB FCB
= FileObject
->FsContext
;
255 AFD_DbgPrint(MID_TRACE
,("Called (FCB %x)\n", FCB
));
257 if( !SocketAcquireStateLock( FCB
) ) {
258 UnlockRequest( Irp
, IrpSp
);
259 return LostSocket( Irp
, FALSE
);
262 EnumReq
->PollEvents
= FCB
->PollState
;
263 RtlZeroMemory( EnumReq
->EventStatus
, sizeof(EnumReq
->EventStatus
) );
265 return UnlockAndMaybeComplete( FCB
, STATUS_SUCCESS
, Irp
,
269 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
270 BOOLEAN
UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll
, PFILE_OBJECT FileObject
) {
274 PAFD_POLL_INFO PollReq
= Poll
->Irp
->AssociatedIrp
.SystemBuffer
;
276 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL
);
278 for( i
= 0; i
< PollReq
->HandleCount
; i
++ ) {
279 if( !AFD_HANDLES(PollReq
)[i
].Handle
) continue;
281 FileObject
= (PFILE_OBJECT
)AFD_HANDLES(PollReq
)[i
].Handle
;
282 FCB
= FileObject
->FsContext
;
284 if( (FCB
->PollState
& AFD_EVENT_CLOSE
) ||
285 (PollReq
->Handles
[i
].Status
& AFD_EVENT_CLOSE
) ) {
286 AFD_HANDLES(PollReq
)[i
].Handle
= 0;
287 PollReq
->Handles
[i
].Events
= 0;
288 PollReq
->Handles
[i
].Status
= AFD_EVENT_CLOSE
;
291 PollReq
->Handles
[i
].Status
=
292 PollReq
->Handles
[i
].Events
& FCB
->PollState
;
293 if( PollReq
->Handles
[i
].Status
) {
294 AFD_DbgPrint(MID_TRACE
,("Signalling %x with %x\n",
295 FCB
, FCB
->PollState
));
301 return Signalled
? 1 : 0;
304 VOID
PollReeval( PAFD_DEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
) {
305 PAFD_ACTIVE_POLL Poll
= NULL
;
306 PLIST_ENTRY ThePollEnt
= NULL
;
309 PAFD_POLL_INFO PollReq
;
310 PKEVENT EventSelect
= NULL
;
312 AFD_DbgPrint(MID_TRACE
,("Called: DeviceExt %x FileObject %x\n",
313 DeviceExt
, FileObject
));
315 KeAcquireSpinLock( &DeviceExt
->Lock
, &OldIrql
);
317 /* Take care of any event select signalling */
318 FCB
= (PAFD_FCB
)FileObject
->FsContext
;
320 /* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
321 AFD_DbgPrint(MID_TRACE
,("Current State: %x, Events Fired: %x, "
322 "Select Triggers %x\n",
323 FCB
->PollState
, FCB
->EventsFired
,
324 FCB
->EventSelectTriggers
));
325 if( FCB
->PollState
& ~FCB
->EventsFired
& FCB
->EventSelectTriggers
) {
326 FCB
->EventsFired
|= FCB
->PollState
;
327 EventSelect
= FCB
->EventSelect
;
331 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
335 /* Now signal normal select irps */
336 ThePollEnt
= DeviceExt
->Polls
.Flink
;
338 while( ThePollEnt
!= &DeviceExt
->Polls
) {
339 Poll
= CONTAINING_RECORD( ThePollEnt
, AFD_ACTIVE_POLL
, ListEntry
);
340 PollReq
= Poll
->Irp
->AssociatedIrp
.SystemBuffer
;
341 AFD_DbgPrint(MID_TRACE
,("Checking poll %x\n", Poll
));
343 if( UpdatePollWithFCB( Poll
, FileObject
) ) {
344 ThePollEnt
= ThePollEnt
->Flink
;
345 AFD_DbgPrint(MID_TRACE
,("Signalling socket\n"));
346 SignalSocket( Poll
, PollReq
, STATUS_SUCCESS
);
348 ThePollEnt
= ThePollEnt
->Flink
;
351 KeReleaseSpinLock( &DeviceExt
->Lock
, OldIrql
);
353 AFD_DbgPrint(MID_TRACE
,("Setting event %x\n", EventSelect
));
354 if( EventSelect
) KeSetEvent( EventSelect
, IO_NETWORK_INCREMENT
, FALSE
);
356 AFD_DbgPrint(MID_TRACE
,("Leaving\n"));