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