6c8e5a279dac630e2fb2f52a09f58dfdcc4ec39d
[reactos.git] / drivers / network / afd / afd / select.c
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
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
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
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 */
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;
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
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
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
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
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 * * */
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
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 }