Merging r37048, r37051, r37052, r37055 from the-real-msvc branch
[reactos.git] / reactos / drivers / network / 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 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
89 AFD_DbgPrint(MID_TRACE,("Completing\n"));
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_SUCCESS );
149 }
150 }
151 }
152
153 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
154
155 AFD_DbgPrint(MID_TRACE,("Done\n"));
156 }
157
158 NTSTATUS STDCALL
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 UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
167 UINT AllocSize =
168 CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
169 KIRQL OldIrql;
170 UINT i, Signalled = 0;
171 ULONG Exclusive = PollReq->Exclusive;
172
173 AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
174 PollReq->HandleCount,
175 (INT)(PollReq->Timeout.QuadPart)));
176
177 SET_AFD_HANDLES(PollReq,
178 LockHandles( PollReq->Handles, PollReq->HandleCount ));
179
180 if( !AFD_HANDLES(PollReq) ) {
181 Irp->IoStatus.Status = STATUS_NO_MEMORY;
182 Irp->IoStatus.Information = 0;
183 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
184 return Irp->IoStatus.Status;
185 }
186
187 if( Exclusive ) {
188 for( i = 0; i < PollReq->HandleCount; i++ ) {
189 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
190
191 KillSelectsForFCB( DeviceExt,
192 (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
193 TRUE );
194 }
195 }
196
197 ZeroEvents( PollReq->Handles,
198 PollReq->HandleCount );
199
200 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
201
202 for( i = 0; i < PollReq->HandleCount; i++ ) {
203 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
204
205 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
206 FCB = FileObject->FsContext;
207
208 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
209 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
210 AFD_HANDLES(PollReq)[i].Handle = 0;
211 PollReq->Handles[i].Events = 0;
212 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
213 Signalled++;
214 } else {
215 AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
216 PrintEvents( PollReq->Handles[i].Events );
217 AFD_DbgPrint(MID_TRACE,("\n"));
218
219 PollReq->Handles[i].Status =
220 PollReq->Handles[i].Events & FCB->PollState;
221 if( PollReq->Handles[i].Status ) {
222 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
223 FCB, FCB->PollState));
224 Signalled++;
225 }
226 }
227 }
228
229 if( Signalled ) {
230 Status = STATUS_SUCCESS;
231 Irp->IoStatus.Status = Status;
232 SignalSocket( NULL, Irp, PollReq, Status );
233 } else {
234
235 PAFD_ACTIVE_POLL Poll = NULL;
236
237 Poll = ExAllocatePool( NonPagedPool, AllocSize );
238
239 if (Poll){
240 Poll->Irp = Irp;
241 Poll->DeviceExt = DeviceExt;
242 Poll->Exclusive = Exclusive;
243
244 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
245
246 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
247 (PKDEFERRED_ROUTINE)SelectTimeout,
248 Poll );
249
250 InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
251
252 KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
253
254 Status = STATUS_PENDING;
255 IoMarkIrpPending( Irp );
256 } else {
257 AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
258 Status = STATUS_NO_MEMORY;
259 }
260 }
261
262 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
263
264 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
265
266 Irp->IoStatus.Status = Status;
267
268 return Status;
269 }
270
271 NTSTATUS STDCALL
272 AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
273 PIO_STACK_LOCATION IrpSp ) {
274 PFILE_OBJECT FileObject = IrpSp->FileObject;
275 NTSTATUS Status = STATUS_NO_MEMORY;
276 PAFD_EVENT_SELECT_INFO EventSelectInfo =
277 (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp );
278 PAFD_FCB FCB = FileObject->FsContext;
279
280 if( !SocketAcquireStateLock( FCB ) ) {
281 return LostSocket( Irp );
282 }
283
284 if ( !EventSelectInfo ) {
285 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
286 0, NULL );
287 }
288 AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
289 EventSelectInfo->EventObject,
290 EventSelectInfo->Events));
291
292 FCB->EventSelectTriggers = FCB->EventsFired = 0;
293 if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
294 FCB->EventSelect = NULL;
295
296 if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
297 Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
298 EventObject,
299 FILE_ALL_ACCESS,
300 NULL,
301 KernelMode,
302 (PVOID *)&FCB->EventSelect,
303 NULL );
304
305 if( !NT_SUCCESS(Status) )
306 FCB->EventSelect = NULL;
307 else
308 FCB->EventSelectTriggers = EventSelectInfo->Events;
309 } else /* Work done, cancelling select */
310 Status = STATUS_SUCCESS;
311
312 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
313
314 return UnlockAndMaybeComplete( FCB, Status, Irp,
315 0, NULL );
316 }
317
318 NTSTATUS STDCALL
319 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
320 PIO_STACK_LOCATION IrpSp ) {
321 PFILE_OBJECT FileObject = IrpSp->FileObject;
322 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
323 (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
324 PAFD_FCB FCB = FileObject->FsContext;
325
326 AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
327
328 if( !SocketAcquireStateLock( FCB ) ) {
329 return LostSocket( Irp );
330 }
331
332 if ( !EnumReq ) {
333 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
334 0, NULL );
335 }
336
337 EnumReq->PollEvents = FCB->PollState;
338 RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
339
340 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
341 0, NULL );
342 }
343
344 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
345 static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
346 UINT i;
347 PAFD_FCB FCB;
348 UINT Signalled = 0;
349 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
350
351 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
352
353 for( i = 0; i < PollReq->HandleCount; i++ ) {
354 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
355
356 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
357 FCB = FileObject->FsContext;
358
359 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
360 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
361 AFD_HANDLES(PollReq)[i].Handle = 0;
362 PollReq->Handles[i].Events = 0;
363 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
364 Signalled++;
365 } else {
366 PollReq->Handles[i].Status =
367 PollReq->Handles[i].Events & FCB->PollState;
368 if( PollReq->Handles[i].Status ) {
369 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
370 FCB, FCB->PollState));
371 Signalled++;
372 }
373 }
374 }
375
376 return Signalled ? 1 : 0;
377 }
378
379 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
380 PAFD_ACTIVE_POLL Poll = NULL;
381 PLIST_ENTRY ThePollEnt = NULL;
382 PAFD_FCB FCB;
383 KIRQL OldIrql;
384 PAFD_POLL_INFO PollReq;
385 PKEVENT EventSelect = NULL;
386
387 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
388 DeviceExt, FileObject));
389
390 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
391
392 /* Take care of any event select signalling */
393 FCB = (PAFD_FCB)FileObject->FsContext;
394
395 if( !FCB ) {
396 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
397 return;
398 }
399
400 /* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
401 AFD_DbgPrint(MID_TRACE,("Current State: %x, Events Fired: %x, "
402 "Select Triggers %x\n",
403 FCB->PollState, FCB->EventsFired,
404 FCB->EventSelectTriggers));
405 if( FCB->PollState & ~FCB->EventsFired & FCB->EventSelectTriggers ) {
406 FCB->EventsFired |= FCB->PollState;
407 EventSelect = FCB->EventSelect;
408 }
409
410 /* Now signal normal select irps */
411 ThePollEnt = DeviceExt->Polls.Flink;
412
413 while( ThePollEnt != &DeviceExt->Polls ) {
414 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
415 PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
416 AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
417
418 if( UpdatePollWithFCB( Poll, FileObject ) ) {
419 ThePollEnt = ThePollEnt->Flink;
420 AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
421 SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
422 } else
423 ThePollEnt = ThePollEnt->Flink;
424 }
425
426 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
427
428 AFD_DbgPrint(MID_TRACE,("Setting event %x\n", EventSelect));
429 if( EventSelect ) KeSetEvent( EventSelect, IO_NETWORK_INCREMENT, FALSE );
430
431 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
432 }