Sync with trunk for console graphics palettes.
[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 KDEFERRED_ROUTINE SelectTimeout;
95 static VOID NTAPI SelectTimeout( PKDPC Dpc,
96 PVOID DeferredContext,
97 PVOID SystemArgument1,
98 PVOID SystemArgument2 ) {
99 PAFD_ACTIVE_POLL Poll = DeferredContext;
100 PAFD_POLL_INFO PollReq;
101 PIRP Irp;
102 KIRQL OldIrql;
103 PAFD_DEVICE_EXTENSION DeviceExt;
104
105 UNREFERENCED_PARAMETER(Dpc);
106 UNREFERENCED_PARAMETER(SystemArgument1);
107 UNREFERENCED_PARAMETER(SystemArgument2);
108
109 AFD_DbgPrint(MID_TRACE,("Called\n"));
110
111 Irp = Poll->Irp;
112 DeviceExt = Poll->DeviceExt;
113 PollReq = Irp->AssociatedIrp.SystemBuffer;
114
115 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
116
117 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
118 SignalSocket( Poll, NULL, PollReq, STATUS_TIMEOUT );
119 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
120
121 AFD_DbgPrint(MID_TRACE,("Timeout\n"));
122 }
123
124 VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
125 PFILE_OBJECT FileObject,
126 BOOLEAN OnlyExclusive ) {
127 KIRQL OldIrql;
128 PLIST_ENTRY ListEntry;
129 PAFD_ACTIVE_POLL Poll;
130 PIRP Irp;
131 PAFD_POLL_INFO PollReq;
132 PAFD_HANDLE HandleArray;
133 UINT i;
134
135 AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %p\n", FileObject));
136
137 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
138
139 ListEntry = DeviceExt->Polls.Flink;
140 while ( ListEntry != &DeviceExt->Polls ) {
141 Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
142 ListEntry = ListEntry->Flink;
143 Irp = Poll->Irp;
144 PollReq = Irp->AssociatedIrp.SystemBuffer;
145 HandleArray = AFD_HANDLES(PollReq);
146
147 for( i = 0; i < PollReq->HandleCount; i++ ) {
148 AFD_DbgPrint(MAX_TRACE,("Req: %u, This %p\n",
149 HandleArray[i].Handle, FileObject));
150 if( (PVOID)HandleArray[i].Handle == FileObject &&
151 (!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
152 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
153 SignalSocket( Poll, NULL, PollReq, STATUS_CANCELLED );
154 }
155 }
156 }
157
158 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
159
160 AFD_DbgPrint(MID_TRACE,("Done\n"));
161 }
162
163 NTSTATUS NTAPI
164 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
165 PIO_STACK_LOCATION IrpSp ) {
166 NTSTATUS Status = STATUS_NO_MEMORY;
167 PAFD_FCB FCB;
168 PFILE_OBJECT FileObject;
169 PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
170 PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
171 KIRQL OldIrql;
172 UINT i, Signalled = 0;
173 ULONG Exclusive = PollReq->Exclusive;
174
175 UNREFERENCED_PARAMETER(IrpSp);
176
177 AFD_DbgPrint(MID_TRACE,("Called (HandleCount %u Timeout %d)\n",
178 PollReq->HandleCount,
179 (INT)(PollReq->Timeout.QuadPart)));
180
181 SET_AFD_HANDLES(PollReq,
182 LockHandles( PollReq->Handles, PollReq->HandleCount ));
183
184 if( !AFD_HANDLES(PollReq) ) {
185 Irp->IoStatus.Status = STATUS_NO_MEMORY;
186 Irp->IoStatus.Information = 0;
187 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
188 return STATUS_NO_MEMORY;
189 }
190
191 if( Exclusive ) {
192 for( i = 0; i < PollReq->HandleCount; i++ ) {
193 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
194
195 KillSelectsForFCB( DeviceExt,
196 (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
197 TRUE );
198 }
199 }
200
201 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
202
203 for( i = 0; i < PollReq->HandleCount; i++ ) {
204 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
205
206 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
207 FCB = FileObject->FsContext;
208
209 AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
210 PrintEvents( PollReq->Handles[i].Events );
211 AFD_DbgPrint(MID_TRACE,("\n"));
212
213 PollReq->Handles[i].Status =
214 PollReq->Handles[i].Events & FCB->PollState;
215 if( PollReq->Handles[i].Status ) {
216 AFD_DbgPrint(MID_TRACE,("Signalling %p with %x\n",
217 FCB, FCB->PollState));
218 Signalled++;
219 }
220 }
221
222 if( Signalled ) {
223 Status = STATUS_SUCCESS;
224 Irp->IoStatus.Status = Status;
225 SignalSocket( NULL, Irp, PollReq, Status );
226 } else {
227
228 PAFD_ACTIVE_POLL Poll = NULL;
229
230 Poll = ExAllocatePool( NonPagedPool, sizeof(AFD_ACTIVE_POLL) );
231
232 if (Poll){
233 Poll->Irp = Irp;
234 Poll->DeviceExt = DeviceExt;
235 Poll->Exclusive = Exclusive;
236
237 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
238
239 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc, SelectTimeout, Poll );
240
241 InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
242
243 KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
244
245 Status = STATUS_PENDING;
246 IoMarkIrpPending( Irp );
247 (void)IoSetCancelRoutine(Irp, AfdCancelHandler);
248 } else {
249 AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
250 Status = STATUS_NO_MEMORY;
251 }
252 }
253
254 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
255
256 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
257
258 return Status;
259 }
260
261 NTSTATUS NTAPI
262 AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
263 PIO_STACK_LOCATION IrpSp ) {
264 PFILE_OBJECT FileObject = IrpSp->FileObject;
265 NTSTATUS Status = STATUS_NO_MEMORY;
266 PAFD_EVENT_SELECT_INFO EventSelectInfo =
267 (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp, FALSE, NULL );
268 PAFD_FCB FCB = FileObject->FsContext;
269
270 UNREFERENCED_PARAMETER(DeviceObject);
271
272 if( !SocketAcquireStateLock( FCB ) ) {
273 return LostSocket( Irp );
274 }
275
276 if ( !EventSelectInfo ) {
277 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
278 0 );
279 }
280 AFD_DbgPrint(MID_TRACE,("Called (Event %p Triggers %u)\n",
281 EventSelectInfo->EventObject,
282 EventSelectInfo->Events));
283
284 if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
285 FCB->EventSelect = NULL;
286
287 if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
288 Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
289 EventObject,
290 EVENT_ALL_ACCESS,
291 ExEventObjectType,
292 UserMode,
293 (PVOID *)&FCB->EventSelect,
294 NULL );
295
296 if( !NT_SUCCESS(Status) )
297 {
298 AFD_DbgPrint(MIN_TRACE,("Failed reference event (0x%x)\n", Status));
299 FCB->EventSelect = NULL;
300 }
301 else
302 FCB->EventSelectTriggers = EventSelectInfo->Events;
303 } else {
304 FCB->EventSelect = NULL;
305 FCB->EventSelectTriggers = 0;
306 Status = STATUS_SUCCESS;
307 }
308
309 if((FCB->EventSelect) &&
310 (FCB->PollState & (FCB->EventSelectTriggers & ~FCB->EventSelectDisabled)))
311 {
312 AFD_DbgPrint(MID_TRACE,("Setting event %p\n", FCB->EventSelect));
313
314 /* Set the application's event */
315 KeSetEvent( FCB->EventSelect, IO_NETWORK_INCREMENT, FALSE );
316 }
317
318 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
319
320 return UnlockAndMaybeComplete( FCB, Status, Irp,
321 0 );
322 }
323
324 NTSTATUS NTAPI
325 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
326 PIO_STACK_LOCATION IrpSp ) {
327 PFILE_OBJECT FileObject = IrpSp->FileObject;
328 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
329 (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp, TRUE, NULL );
330 PAFD_FCB FCB = FileObject->FsContext;
331 PKEVENT UserEvent;
332 NTSTATUS Status;
333
334 UNREFERENCED_PARAMETER(DeviceObject);
335
336 AFD_DbgPrint(MID_TRACE,("Called (FCB %p)\n", FCB));
337
338 if( !SocketAcquireStateLock( FCB ) ) {
339 return LostSocket( Irp );
340 }
341
342 if ( !EnumReq ) {
343 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0 );
344 }
345
346 Status = ObReferenceObjectByHandle(EnumReq->Event,
347 EVENT_ALL_ACCESS,
348 ExEventObjectType,
349 UserMode,
350 (PVOID *)&UserEvent,
351 NULL);
352 if (!NT_SUCCESS(Status))
353 {
354 AFD_DbgPrint(MIN_TRACE,("Unable to reference event %x\n", Status));
355 return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
356 }
357
358 /* Clear the event */
359 KeClearEvent(UserEvent);
360 ObDereferenceObject(UserEvent);
361
362 /* Copy the poll state, masking out disabled events */
363 EnumReq->PollEvents = (FCB->PollState & ~FCB->EventSelectDisabled);
364 RtlCopyMemory( EnumReq->EventStatus,
365 FCB->PollStatus,
366 sizeof(EnumReq->EventStatus) );
367
368 /* Disable the events that triggered the select until the reenabling function is called */
369 FCB->EventSelectDisabled |= (FCB->PollState & FCB->EventSelectTriggers);
370
371 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp, 0 );
372 }
373
374 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
375 static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
376 UINT i;
377 PAFD_FCB FCB;
378 UINT Signalled = 0;
379 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
380
381 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
382
383 for( i = 0; i < PollReq->HandleCount; i++ ) {
384 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
385
386 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
387 FCB = FileObject->FsContext;
388
389 PollReq->Handles[i].Status = PollReq->Handles[i].Events & FCB->PollState;
390 if( PollReq->Handles[i].Status ) {
391 AFD_DbgPrint(MID_TRACE,("Signalling %p with %x\n",
392 FCB, FCB->PollState));
393 Signalled++;
394 }
395 }
396
397 return Signalled ? 1 : 0;
398 }
399
400 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
401 PAFD_ACTIVE_POLL Poll = NULL;
402 PLIST_ENTRY ThePollEnt = NULL;
403 PAFD_FCB FCB;
404 KIRQL OldIrql;
405 PAFD_POLL_INFO PollReq;
406
407 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %p FileObject %p\n",
408 DeviceExt, FileObject));
409
410 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
411
412 /* Take care of any event select signalling */
413 FCB = (PAFD_FCB)FileObject->FsContext;
414
415 if( !FCB ) {
416 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
417 return;
418 }
419
420 /* Now signal normal select irps */
421 ThePollEnt = DeviceExt->Polls.Flink;
422
423 while( ThePollEnt != &DeviceExt->Polls ) {
424 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
425 PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
426 AFD_DbgPrint(MID_TRACE,("Checking poll %p\n", Poll));
427
428 if( UpdatePollWithFCB( Poll, FileObject ) ) {
429 ThePollEnt = ThePollEnt->Flink;
430 AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
431 SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
432 } else
433 ThePollEnt = ThePollEnt->Flink;
434 }
435
436 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
437
438 if((FCB->EventSelect) &&
439 (FCB->PollState & (FCB->EventSelectTriggers & ~FCB->EventSelectDisabled)))
440 {
441 AFD_DbgPrint(MID_TRACE,("Setting event %p\n", FCB->EventSelect));
442
443 /* Set the application's event */
444 KeSetEvent( FCB->EventSelect, IO_NETWORK_INCREMENT, FALSE );
445 }
446
447 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
448 }