xref: /reactos/drivers/network/afd/afd/select.c (revision b8309397)
1 /*
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)
7  * UPDATE HISTORY:
8  * 20040708 Created
9  */
10 
11 #include "afd.h"
12 
PrintEvents(ULONG Events)13 static VOID PrintEvents( ULONG Events ) {
14 #if DBG
15     char *events_list[] = { "AFD_EVENT_RECEIVE",
16                             "AFD_EVENT_OOB_RECEIVE",
17                             "AFD_EVENT_SEND",
18                             "AFD_EVENT_DISCONNECT",
19                             "AFD_EVENT_ABORT",
20                             "AFD_EVENT_CLOSE",
21                             "AFD_EVENT_CONNECT",
22                             "AFD_EVENT_ACCEPT",
23                             "AFD_EVENT_CONNECT_FAIL",
24                             "AFD_EVENT_QOS",
25                             "AFD_EVENT_GROUP_QOS",
26                             NULL };
27     int i;
28 
29     for( i = 0; events_list[i]; i++ )
30         if( Events & (1 << i) ) AFD_DbgPrint(MID_TRACE,("%s ", events_list[i] ));
31 #endif
32 }
33 
CopyBackStatus(PAFD_HANDLE HandleArray,UINT HandleCount)34 static VOID CopyBackStatus( PAFD_HANDLE HandleArray,
35                             UINT HandleCount ) {
36     UINT i;
37 
38     for( i = 0; i < HandleCount; i++ ) {
39         HandleArray[i].Events = HandleArray[i].Status;
40         HandleArray[i].Status = 0;
41     }
42 }
43 
ZeroEvents(PAFD_HANDLE HandleArray,UINT HandleCount)44 VOID ZeroEvents( PAFD_HANDLE HandleArray,
45                  UINT HandleCount ) {
46     UINT i;
47 
48     for( i = 0; i < HandleCount; i++ ) {
49         HandleArray[i].Status = 0;
50         HandleArray[i].Events = 0;
51     }
52 }
53 
54 
55 /* you must pass either Poll OR Irp */
SignalSocket(PAFD_ACTIVE_POLL Poll OPTIONAL,PIRP _Irp OPTIONAL,PAFD_POLL_INFO PollReq,NTSTATUS Status)56 VOID SignalSocket(
57    PAFD_ACTIVE_POLL Poll OPTIONAL,
58    PIRP _Irp OPTIONAL,
59    PAFD_POLL_INFO PollReq,
60    NTSTATUS Status
61    )
62 {
63     UINT i;
64     PIRP Irp = _Irp ? _Irp : Poll->Irp;
65     AFD_DbgPrint(MID_TRACE,("Called (Status %x)\n", Status));
66 
67     if (Poll)
68     {
69         KeCancelTimer( &Poll->Timer );
70         RemoveEntryList( &Poll->ListEntry );
71         ExFreePoolWithTag(Poll, TAG_AFD_ACTIVE_POLL);
72     }
73 
74     Irp->IoStatus.Status = Status;
75     Irp->IoStatus.Information =
76         FIELD_OFFSET(AFD_POLL_INFO, Handles) + sizeof(AFD_HANDLE) * PollReq->HandleCount;
77     CopyBackStatus( PollReq->Handles,
78                     PollReq->HandleCount );
79     for( i = 0; i < PollReq->HandleCount; i++ ) {
80         AFD_DbgPrint
81             (MAX_TRACE,
82              ("Handle(%x): Got %x,%x\n",
83               PollReq->Handles[i].Handle,
84               PollReq->Handles[i].Events,
85               PollReq->Handles[i].Status));
86     }
87     UnlockHandles( AFD_HANDLES(PollReq), PollReq->HandleCount );
88     if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
89     AFD_DbgPrint(MID_TRACE,("Completing\n"));
90     (void)IoSetCancelRoutine(Irp, NULL);
91     IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
92     AFD_DbgPrint(MID_TRACE,("Done\n"));
93 }
94 
95 static KDEFERRED_ROUTINE SelectTimeout;
SelectTimeout(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)96 static VOID NTAPI SelectTimeout( PKDPC Dpc,
97                            PVOID DeferredContext,
98                            PVOID SystemArgument1,
99                            PVOID SystemArgument2 ) {
100     PAFD_ACTIVE_POLL Poll = DeferredContext;
101     PAFD_POLL_INFO PollReq;
102     PIRP Irp;
103     KIRQL OldIrql;
104     PAFD_DEVICE_EXTENSION DeviceExt;
105 
106     UNREFERENCED_PARAMETER(Dpc);
107     UNREFERENCED_PARAMETER(SystemArgument1);
108     UNREFERENCED_PARAMETER(SystemArgument2);
109 
110     AFD_DbgPrint(MID_TRACE,("Called\n"));
111 
112     Irp = Poll->Irp;
113     DeviceExt = Poll->DeviceExt;
114     PollReq = Irp->AssociatedIrp.SystemBuffer;
115 
116     ZeroEvents( PollReq->Handles, PollReq->HandleCount );
117 
118     KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
119     SignalSocket( Poll, NULL, PollReq, STATUS_TIMEOUT );
120     KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
121 
122     AFD_DbgPrint(MID_TRACE,("Timeout\n"));
123 }
124 
KillSelectsForFCB(PAFD_DEVICE_EXTENSION DeviceExt,PFILE_OBJECT FileObject,BOOLEAN OnlyExclusive)125 VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
126                         PFILE_OBJECT FileObject,
127                         BOOLEAN OnlyExclusive ) {
128     KIRQL OldIrql;
129     PLIST_ENTRY ListEntry;
130     PAFD_ACTIVE_POLL Poll;
131     PIRP Irp;
132     PAFD_POLL_INFO PollReq;
133     PAFD_HANDLE HandleArray;
134     UINT i;
135 
136     AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %p\n", FileObject));
137 
138     KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
139 
140     ListEntry = DeviceExt->Polls.Flink;
141     while ( ListEntry != &DeviceExt->Polls ) {
142         Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
143         ListEntry = ListEntry->Flink;
144         Irp = Poll->Irp;
145         PollReq = Irp->AssociatedIrp.SystemBuffer;
146         HandleArray = AFD_HANDLES(PollReq);
147 
148         for( i = 0; i < PollReq->HandleCount; i++ ) {
149             AFD_DbgPrint(MAX_TRACE,("Req: %u, This %p\n",
150                                     HandleArray[i].Handle, FileObject));
151             if( (PVOID)HandleArray[i].Handle == FileObject &&
152                 (!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
153                 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
154                 SignalSocket( Poll, NULL, PollReq, STATUS_CANCELLED );
155             }
156         }
157     }
158 
159     KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
160 
161     AFD_DbgPrint(MID_TRACE,("Done\n"));
162 }
163 
164 NTSTATUS NTAPI
AfdSelect(PDEVICE_OBJECT DeviceObject,PIRP Irp,PIO_STACK_LOCATION IrpSp)165 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
166            PIO_STACK_LOCATION IrpSp ) {
167     NTSTATUS Status = STATUS_NO_MEMORY;
168     PAFD_FCB FCB;
169     PFILE_OBJECT FileObject;
170     PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
171     PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
172     KIRQL OldIrql;
173     UINT i, Signalled = 0;
174     ULONG Exclusive = PollReq->Exclusive;
175 
176     UNREFERENCED_PARAMETER(IrpSp);
177 
178     AFD_DbgPrint(MID_TRACE,("Called (HandleCount %u Timeout %d)\n",
179                             PollReq->HandleCount,
180                             (INT)(PollReq->Timeout.QuadPart)));
181 
182     SET_AFD_HANDLES(PollReq,
183                     LockHandles( PollReq->Handles, PollReq->HandleCount ));
184 
185     if( !AFD_HANDLES(PollReq) ) {
186         Irp->IoStatus.Status = STATUS_NO_MEMORY;
187         Irp->IoStatus.Information = 0;
188         IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
189         return STATUS_NO_MEMORY;
190     }
191 
192     if( Exclusive ) {
193         for( i = 0; i < PollReq->HandleCount; i++ ) {
194             if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
195 
196             KillSelectsForFCB( DeviceExt,
197                                (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
198                                TRUE );
199         }
200     }
201 
202     KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
203 
204     for( i = 0; i < PollReq->HandleCount; i++ ) {
205         if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
206 
207         FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
208         FCB = FileObject->FsContext;
209 
210         AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
211         PrintEvents( PollReq->Handles[i].Events );
212         AFD_DbgPrint(MID_TRACE,("\n"));
213 
214         PollReq->Handles[i].Status =
215             PollReq->Handles[i].Events & FCB->PollState;
216         if( PollReq->Handles[i].Status ) {
217             AFD_DbgPrint(MID_TRACE,("Signalling %p with %x\n",
218                                     FCB, FCB->PollState));
219             Signalled++;
220         }
221     }
222 
223     if( Signalled ) {
224         Status = STATUS_SUCCESS;
225         Irp->IoStatus.Status = Status;
226         SignalSocket( NULL, Irp, PollReq, Status );
227     } else {
228 
229        PAFD_ACTIVE_POLL Poll = NULL;
230 
231        Poll = ExAllocatePoolWithTag(NonPagedPool,
232                                     sizeof(AFD_ACTIVE_POLL),
233                                     TAG_AFD_ACTIVE_POLL);
234 
235        if (Poll){
236           Poll->Irp = Irp;
237           Poll->DeviceExt = DeviceExt;
238           Poll->Exclusive = Exclusive;
239 
240           KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
241 
242           KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc, SelectTimeout, Poll );
243 
244           InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
245 
246           KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
247 
248           Status = STATUS_PENDING;
249           IoMarkIrpPending( Irp );
250           (void)IoSetCancelRoutine(Irp, AfdCancelHandler);
251        } else {
252           AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
253           Status = STATUS_NO_MEMORY;
254        }
255     }
256 
257     KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
258 
259     AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
260 
261     return Status;
262 }
263 
264 NTSTATUS NTAPI
AfdEventSelect(PDEVICE_OBJECT DeviceObject,PIRP Irp,PIO_STACK_LOCATION IrpSp)265 AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
266                 PIO_STACK_LOCATION IrpSp ) {
267     PFILE_OBJECT FileObject = IrpSp->FileObject;
268     NTSTATUS Status = STATUS_NO_MEMORY;
269     PAFD_EVENT_SELECT_INFO EventSelectInfo =
270         (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp, FALSE, NULL );
271     PAFD_FCB FCB = FileObject->FsContext;
272 
273     UNREFERENCED_PARAMETER(DeviceObject);
274 
275     if( !SocketAcquireStateLock( FCB ) ) {
276         return LostSocket( Irp );
277     }
278 
279     if ( !EventSelectInfo ) {
280          return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
281                                         0 );
282     }
283     AFD_DbgPrint(MID_TRACE,("Called (Event %p Triggers %u)\n",
284                             EventSelectInfo->EventObject,
285                             EventSelectInfo->Events));
286 
287     if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
288     FCB->EventSelect = NULL;
289 
290     if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
291         Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
292                                             EventObject,
293                                             EVENT_ALL_ACCESS,
294                                             *ExEventObjectType,
295                                             UserMode,
296                                             (PVOID *)&FCB->EventSelect,
297                                             NULL );
298 
299         if( !NT_SUCCESS(Status) )
300         {
301             AFD_DbgPrint(MIN_TRACE,("Failed reference event (0x%x)\n", Status));
302             FCB->EventSelect = NULL;
303         }
304         else
305             FCB->EventSelectTriggers = EventSelectInfo->Events;
306     } else {
307         FCB->EventSelect = NULL;
308         FCB->EventSelectTriggers = 0;
309         Status = STATUS_SUCCESS;
310     }
311 
312     if((FCB->EventSelect) &&
313        (FCB->PollState & (FCB->EventSelectTriggers & ~FCB->EventSelectDisabled)))
314     {
315         AFD_DbgPrint(MID_TRACE,("Setting event %p\n", FCB->EventSelect));
316 
317         /* Set the application's event */
318         KeSetEvent( FCB->EventSelect, IO_NETWORK_INCREMENT, FALSE );
319     }
320 
321     AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
322 
323     return UnlockAndMaybeComplete( FCB, Status, Irp,
324                                    0 );
325 }
326 
327 NTSTATUS NTAPI
AfdEnumEvents(PDEVICE_OBJECT DeviceObject,PIRP Irp,PIO_STACK_LOCATION IrpSp)328 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
329                PIO_STACK_LOCATION IrpSp ) {
330     PFILE_OBJECT FileObject = IrpSp->FileObject;
331     PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
332         (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp, TRUE, NULL );
333     PAFD_FCB FCB = FileObject->FsContext;
334     PKEVENT UserEvent;
335     NTSTATUS Status;
336 
337     UNREFERENCED_PARAMETER(DeviceObject);
338 
339     AFD_DbgPrint(MID_TRACE,("Called (FCB %p)\n", FCB));
340 
341     if( !SocketAcquireStateLock( FCB ) ) {
342         return LostSocket( Irp );
343     }
344 
345     if ( !EnumReq ) {
346          return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
347     }
348 
349     /* An event may optionally be provided for us to clear */
350     if (EnumReq->Event != NULL)
351     {
352         Status = ObReferenceObjectByHandle(EnumReq->Event,
353                                            EVENT_ALL_ACCESS,
354                                            *ExEventObjectType,
355                                            UserMode,
356                                            (PVOID *)&UserEvent,
357                                            NULL);
358         if (!NT_SUCCESS(Status))
359         {
360             AFD_DbgPrint(MIN_TRACE,("Unable to reference event %x\n", Status));
361             return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
362         }
363 
364         /* Clear the event */
365         KeClearEvent(UserEvent);
366         ObDereferenceObject(UserEvent);
367     }
368 
369     /* Copy the poll state, masking out disabled events */
370     EnumReq->PollEvents = (FCB->PollState & ~FCB->EventSelectDisabled);
371     RtlCopyMemory( EnumReq->EventStatus,
372                    FCB->PollStatus,
373                    sizeof(EnumReq->EventStatus) );
374 
375     /* Disable the events that triggered the select until the reenabling function is called */
376     FCB->EventSelectDisabled |= (FCB->PollState & FCB->EventSelectTriggers);
377 
378     return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp, 0 );
379 }
380 
381 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
UpdatePollWithFCB(PAFD_ACTIVE_POLL Poll,PFILE_OBJECT FileObject)382 static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
383     UINT i;
384     PAFD_FCB FCB;
385     UINT Signalled = 0;
386     PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
387 
388     ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
389 
390     for( i = 0; i < PollReq->HandleCount; i++ ) {
391         if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
392 
393         FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
394         FCB = FileObject->FsContext;
395 
396         PollReq->Handles[i].Status = PollReq->Handles[i].Events & FCB->PollState;
397         if( PollReq->Handles[i].Status ) {
398             AFD_DbgPrint(MID_TRACE,("Signalling %p with %x\n",
399                                     FCB, FCB->PollState));
400             Signalled++;
401         }
402     }
403 
404     return Signalled ? 1 : 0;
405 }
406 
PollReeval(PAFD_DEVICE_EXTENSION DeviceExt,PFILE_OBJECT FileObject)407 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
408     PAFD_ACTIVE_POLL Poll = NULL;
409     PLIST_ENTRY ThePollEnt = NULL;
410     PAFD_FCB FCB;
411     KIRQL OldIrql;
412     PAFD_POLL_INFO PollReq;
413 
414     AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %p FileObject %p\n",
415                             DeviceExt, FileObject));
416 
417     KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
418 
419     /* Take care of any event select signalling */
420     FCB = (PAFD_FCB)FileObject->FsContext;
421 
422     if( !FCB ) {
423         KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
424         return;
425     }
426 
427     /* Now signal normal select irps */
428     ThePollEnt = DeviceExt->Polls.Flink;
429 
430     while( ThePollEnt != &DeviceExt->Polls ) {
431         Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
432         PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
433         AFD_DbgPrint(MID_TRACE,("Checking poll %p\n", Poll));
434 
435         if( UpdatePollWithFCB( Poll, FileObject ) ) {
436             ThePollEnt = ThePollEnt->Flink;
437             AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
438             SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
439         } else
440             ThePollEnt = ThePollEnt->Flink;
441     }
442 
443     KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
444 
445     if((FCB->EventSelect) &&
446        (FCB->PollState & (FCB->EventSelectTriggers & ~FCB->EventSelectDisabled)))
447     {
448         AFD_DbgPrint(MID_TRACE,("Setting event %p\n", FCB->EventSelect));
449 
450         /* Set the application's event */
451         KeSetEvent( FCB->EventSelect, IO_NETWORK_INCREMENT, FALSE );
452     }
453 
454     AFD_DbgPrint(MID_TRACE,("Leaving\n"));
455 }
456