Patch by hardon. Properly handle 0 timeouts. Fixes bug 857.
[reactos.git] / reactos / drivers / net / afd / afd / select.c
1 /* $Id$
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 #include "tdi_proto.h"
12 #include "tdiconn.h"
13 #include "debug.h"
14
15 static VOID PrintEvents( ULONG Events ) {
16 #if DBG
17 char *events_list[] = { "AFD_EVENT_RECEIVE",
18 "AFD_EVENT_OOB_RECEIVE",
19 "AFD_EVENT_SEND",
20 "AFD_EVENT_DISCONNECT",
21 "AFD_EVENT_ABORT",
22 "AFD_EVENT_CLOSE",
23 "AFD_EVENT_CONNECT",
24 "AFD_EVENT_ACCEPT",
25 "AFD_EVENT_CONNECT_FAIL",
26 "AFD_EVENT_QOS",
27 "AFD_EVENT_GROUP_QOS",
28 NULL };
29 int i;
30
31 for( i = 0; events_list[i]; i++ )
32 if( Events & (1 << i) ) AFD_DbgPrint(MID_TRACE,("%s ", events_list[i] ));
33 #endif
34 }
35
36 static VOID CopyBackStatus( PAFD_HANDLE HandleArray,
37 UINT HandleCount ) {
38 UINT i;
39
40 for( i = 0; i < HandleCount; i++ ) {
41 HandleArray[i].Events = HandleArray[i].Status;
42 HandleArray[i].Status = 0;
43 }
44 }
45
46 static VOID ZeroEvents( PAFD_HANDLE HandleArray,
47 UINT HandleCount ) {
48 UINT i;
49
50 for( i = 0; i < HandleCount; i++ )
51 HandleArray[i].Status = 0;
52 }
53
54
55 /* you must pass either Poll OR Irp */
56 static 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 ExFreePool( 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 AFD_DbgPrint(MID_TRACE,("Completing\n"));
89 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
90 AFD_DbgPrint(MID_TRACE,("Done\n"));
91 }
92
93 static VOID SelectTimeout( PKDPC Dpc,
94 PVOID DeferredContext,
95 PVOID SystemArgument1,
96 PVOID SystemArgument2 ) {
97 PAFD_ACTIVE_POLL Poll = DeferredContext;
98 PAFD_POLL_INFO PollReq;
99 PIRP Irp;
100 KIRQL OldIrql;
101 PAFD_DEVICE_EXTENSION DeviceExt;
102
103 AFD_DbgPrint(MID_TRACE,("Called\n"));
104
105 Irp = Poll->Irp;
106 DeviceExt = Poll->DeviceExt;
107 PollReq = Irp->AssociatedIrp.SystemBuffer;
108
109 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
110
111 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
112 SignalSocket( Poll, NULL, PollReq, STATUS_TIMEOUT );
113 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
114
115 AFD_DbgPrint(MID_TRACE,("Timeout\n"));
116 }
117
118 VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
119 PFILE_OBJECT FileObject,
120 BOOLEAN OnlyExclusive ) {
121 KIRQL OldIrql;
122 PLIST_ENTRY ListEntry;
123 PAFD_ACTIVE_POLL Poll;
124 PIRP Irp;
125 PAFD_POLL_INFO PollReq;
126 PAFD_HANDLE HandleArray;
127 UINT i;
128
129 AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %x\n", FileObject));
130
131 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
132
133 ListEntry = DeviceExt->Polls.Flink;
134 while ( ListEntry != &DeviceExt->Polls ) {
135 Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
136 ListEntry = ListEntry->Flink;
137 Irp = Poll->Irp;
138 PollReq = Irp->AssociatedIrp.SystemBuffer;
139 HandleArray = AFD_HANDLES(PollReq);
140
141 for( i = 0; i < PollReq->HandleCount; i++ ) {
142 AFD_DbgPrint(MAX_TRACE,("Req: %x, This %x\n",
143 HandleArray[i].Handle, FileObject));
144 if( (PVOID)HandleArray[i].Handle == FileObject &&
145 (!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
146 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
147 SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
148 }
149 }
150 }
151
152 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
153
154 AFD_DbgPrint(MID_TRACE,("Done\n"));
155 }
156
157 NTSTATUS STDCALL
158 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
159 PIO_STACK_LOCATION IrpSp ) {
160 NTSTATUS Status = STATUS_NO_MEMORY;
161 PAFD_FCB FCB;
162 PFILE_OBJECT FileObject;
163 PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
164 PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
165 UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
166 UINT AllocSize =
167 CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
168 KIRQL OldIrql;
169 UINT i, Signalled = 0;
170 ULONG Exclusive = PollReq->Exclusive;
171
172 AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
173 PollReq->HandleCount,
174 (INT)(PollReq->Timeout.QuadPart)));
175
176 SET_AFD_HANDLES(PollReq,
177 LockHandles( PollReq->Handles, PollReq->HandleCount ));
178
179 if( !AFD_HANDLES(PollReq) ) {
180 Irp->IoStatus.Status = STATUS_NO_MEMORY;
181 Irp->IoStatus.Information = 0;
182 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
183 return Irp->IoStatus.Status;
184 }
185
186 if( Exclusive ) {
187 for( i = 0; i < PollReq->HandleCount; i++ ) {
188 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
189
190 KillSelectsForFCB( DeviceExt,
191 (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
192 TRUE );
193 }
194 }
195
196 ZeroEvents( PollReq->Handles,
197 PollReq->HandleCount );
198
199 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
200
201 for( i = 0; i < PollReq->HandleCount; i++ ) {
202 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
203
204 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
205 FCB = FileObject->FsContext;
206
207 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
208 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
209 AFD_HANDLES(PollReq)[i].Handle = 0;
210 PollReq->Handles[i].Events = 0;
211 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
212 Signalled++;
213 } else {
214 AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
215 PrintEvents( PollReq->Handles[i].Events );
216 AFD_DbgPrint(MID_TRACE,("\n"));
217
218 PollReq->Handles[i].Status =
219 PollReq->Handles[i].Events & FCB->PollState;
220 if( PollReq->Handles[i].Status ) {
221 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
222 FCB, FCB->PollState));
223 Signalled++;
224 }
225 }
226 }
227
228 if( Signalled ) {
229 Status = STATUS_SUCCESS;
230 Irp->IoStatus.Status = Status;
231 SignalSocket( NULL, Irp, PollReq, Status );
232 } else {
233
234 PAFD_ACTIVE_POLL Poll = NULL;
235
236 Poll = ExAllocatePool( NonPagedPool, AllocSize );
237
238 if (Poll){
239 Poll->Irp = Irp;
240 Poll->DeviceExt = DeviceExt;
241 Poll->Exclusive = Exclusive;
242
243 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
244
245 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
246 (PKDEFERRED_ROUTINE)SelectTimeout,
247 Poll );
248
249 InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
250
251 KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
252
253 Status = STATUS_PENDING;
254 IoMarkIrpPending( Irp );
255 } else {
256 AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
257 Status = STATUS_NO_MEMORY;
258 }
259 }
260
261 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
262
263 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
264
265 return Status;
266 }
267
268 NTSTATUS STDCALL
269 AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
270 PIO_STACK_LOCATION IrpSp ) {
271 PFILE_OBJECT FileObject = IrpSp->FileObject;
272 NTSTATUS Status = STATUS_NO_MEMORY;
273 PAFD_EVENT_SELECT_INFO EventSelectInfo =
274 (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp );
275 PAFD_FCB FCB = FileObject->FsContext;
276
277 AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
278 EventSelectInfo->EventObject,
279 EventSelectInfo->Events));
280
281 if( !SocketAcquireStateLock( FCB ) ) {
282 UnlockRequest( Irp, IrpSp );
283 return LostSocket( Irp, FALSE );
284 }
285
286 FCB->EventSelectTriggers = FCB->EventsFired = 0;
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 FILE_ALL_ACCESS,
294 NULL,
295 KernelMode,
296 (PVOID *)&FCB->EventSelect,
297 NULL );
298
299 if( !NT_SUCCESS(Status) )
300 FCB->EventSelect = NULL;
301 else
302 FCB->EventSelectTriggers = EventSelectInfo->Events;
303 } else /* Work done, cancelling select */
304 Status = STATUS_SUCCESS;
305
306 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
307
308 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
309 0, NULL, TRUE );
310 }
311
312 NTSTATUS STDCALL
313 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
314 PIO_STACK_LOCATION IrpSp ) {
315 PFILE_OBJECT FileObject = IrpSp->FileObject;
316 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
317 (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
318 PAFD_FCB FCB = FileObject->FsContext;
319
320 AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
321
322 if( !SocketAcquireStateLock( FCB ) ) {
323 UnlockRequest( Irp, IrpSp );
324 return LostSocket( Irp, FALSE );
325 }
326
327 EnumReq->PollEvents = FCB->PollState;
328 RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
329
330 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
331 0, NULL, TRUE );
332 }
333
334 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
335 static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
336 UINT i;
337 PAFD_FCB FCB;
338 UINT Signalled = 0;
339 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
340
341 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
342
343 for( i = 0; i < PollReq->HandleCount; i++ ) {
344 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
345
346 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
347 FCB = FileObject->FsContext;
348
349 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
350 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
351 AFD_HANDLES(PollReq)[i].Handle = 0;
352 PollReq->Handles[i].Events = 0;
353 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
354 Signalled++;
355 } else {
356 PollReq->Handles[i].Status =
357 PollReq->Handles[i].Events & FCB->PollState;
358 if( PollReq->Handles[i].Status ) {
359 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
360 FCB, FCB->PollState));
361 Signalled++;
362 }
363 }
364 }
365
366 return Signalled ? 1 : 0;
367 }
368
369 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
370 PAFD_ACTIVE_POLL Poll = NULL;
371 PLIST_ENTRY ThePollEnt = NULL;
372 PAFD_FCB FCB;
373 KIRQL OldIrql;
374 PAFD_POLL_INFO PollReq;
375 PKEVENT EventSelect = NULL;
376
377 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
378 DeviceExt, FileObject));
379
380 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
381
382 /* Take care of any event select signalling */
383 FCB = (PAFD_FCB)FileObject->FsContext;
384
385 /* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
386 AFD_DbgPrint(MID_TRACE,("Current State: %x, Events Fired: %x, "
387 "Select Triggers %x\n",
388 FCB->PollState, FCB->EventsFired,
389 FCB->EventSelectTriggers));
390 if( FCB->PollState & ~FCB->EventsFired & FCB->EventSelectTriggers ) {
391 FCB->EventsFired |= FCB->PollState;
392 EventSelect = FCB->EventSelect;
393 }
394
395 if( !FCB ) {
396 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
397 return;
398 }
399
400 /* Now signal normal select irps */
401 ThePollEnt = DeviceExt->Polls.Flink;
402
403 while( ThePollEnt != &DeviceExt->Polls ) {
404 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
405 PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
406 AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
407
408 if( UpdatePollWithFCB( Poll, FileObject ) ) {
409 ThePollEnt = ThePollEnt->Flink;
410 AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
411 SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
412 } else
413 ThePollEnt = ThePollEnt->Flink;
414 }
415
416 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
417
418 AFD_DbgPrint(MID_TRACE,("Setting event %x\n", EventSelect));
419 if( EventSelect ) KeSetEvent( EventSelect, IO_NETWORK_INCREMENT, FALSE );
420
421 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
422 }