- Start of fixing CreateProcess's problems. Implemented the console creation as...
[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 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 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 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 VOID RemoveSelect( PAFD_ACTIVE_POLL Poll ) {
55 AFD_DbgPrint(MID_TRACE,("Called\n"));
56
57 RemoveEntryList( &Poll->ListEntry );
58 KeCancelTimer( &Poll->Timer );
59
60 ExFreePool( Poll );
61
62 AFD_DbgPrint(MID_TRACE,("Done\n"));
63 }
64
65 VOID SignalSocket( PAFD_ACTIVE_POLL Poll, PAFD_POLL_INFO PollReq,
66 NTSTATUS Status ) {
67 UINT i;
68 PIRP Irp = Poll->Irp;
69 AFD_DbgPrint(MID_TRACE,("Called (Status %x)\n", Status));
70 KeCancelTimer( &Poll->Timer );
71 Poll->Irp->IoStatus.Status = Status;
72 Poll->Irp->IoStatus.Information =
73 FIELD_OFFSET(AFD_POLL_INFO, Handles) + sizeof(AFD_HANDLE) * PollReq->HandleCount;
74 CopyBackStatus( PollReq->Handles,
75 PollReq->HandleCount );
76 for( i = 0; i < PollReq->HandleCount; i++ ) {
77 AFD_DbgPrint
78 (MAX_TRACE,
79 ("Handle(%x): Got %x,%x\n",
80 PollReq->Handles[i].Handle,
81 PollReq->Handles[i].Events,
82 PollReq->Handles[i].Status));
83 }
84 UnlockHandles( AFD_HANDLES(PollReq), PollReq->HandleCount );
85 AFD_DbgPrint(MID_TRACE,("Completing\n"));
86 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
87 RemoveEntryList( &Poll->ListEntry );
88 RemoveSelect( Poll );
89 AFD_DbgPrint(MID_TRACE,("Done\n"));
90 }
91
92 VOID SelectTimeout( PKDPC Dpc,
93 PVOID DeferredContext,
94 PVOID SystemArgument1,
95 PVOID SystemArgument2 ) {
96 PAFD_ACTIVE_POLL Poll = DeferredContext;
97 PAFD_POLL_INFO PollReq;
98 PIRP Irp;
99 KIRQL OldIrql;
100 PAFD_DEVICE_EXTENSION DeviceExt;
101
102 AFD_DbgPrint(MID_TRACE,("Called\n"));
103
104 Irp = Poll->Irp;
105 DeviceExt = Poll->DeviceExt;
106 PollReq = Irp->AssociatedIrp.SystemBuffer;
107
108 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
109
110 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
111 SignalSocket( Poll, PollReq, STATUS_TIMEOUT );
112 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
113
114 AFD_DbgPrint(MID_TRACE,("Timeout\n"));
115 }
116
117 VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
118 PFILE_OBJECT FileObject,
119 BOOLEAN OnlyExclusive ) {
120 KIRQL OldIrql;
121 PLIST_ENTRY ListEntry;
122 PAFD_ACTIVE_POLL Poll;
123 PIRP Irp;
124 PAFD_POLL_INFO PollReq;
125 PAFD_HANDLE HandleArray;
126 UINT i;
127
128 AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %x\n", FileObject));
129
130 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
131
132 ListEntry = DeviceExt->Polls.Flink;
133 while ( ListEntry != &DeviceExt->Polls ) {
134 Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
135 ListEntry = ListEntry->Flink;
136 Irp = Poll->Irp;
137 PollReq = Irp->AssociatedIrp.SystemBuffer;
138 HandleArray = AFD_HANDLES(PollReq);
139
140 for( i = 0; i < PollReq->HandleCount; i++ ) {
141 AFD_DbgPrint(MAX_TRACE,("Req: %x, This %x\n",
142 HandleArray[i].Handle, FileObject));
143 if( (PVOID)HandleArray[i].Handle == FileObject &&
144 (!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
145 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
146 SignalSocket( Poll, PollReq, STATUS_SUCCESS );
147 }
148 }
149 }
150
151 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
152
153 AFD_DbgPrint(MID_TRACE,("Done\n"));
154 }
155
156 NTSTATUS STDCALL
157 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
158 PIO_STACK_LOCATION IrpSp ) {
159 NTSTATUS Status = STATUS_NO_MEMORY;
160 PAFD_FCB FCB;
161 PFILE_OBJECT FileObject;
162 PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
163 PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
164 PAFD_ACTIVE_POLL Poll = NULL;
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 Poll = ExAllocatePool( NonPagedPool, AllocSize );
200
201 if( Poll ) {
202 Poll->Irp = Irp;
203 Poll->DeviceExt = DeviceExt;
204 Poll->Exclusive = Exclusive;
205
206 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
207 KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
208
209 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
210 (PKDEFERRED_ROUTINE)SelectTimeout,
211 Poll );
212
213 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
214 InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
215
216 for( i = 0; i < PollReq->HandleCount; i++ ) {
217 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
218
219 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
220 FCB = FileObject->FsContext;
221
222 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
223 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
224 AFD_HANDLES(PollReq)[i].Handle = 0;
225 PollReq->Handles[i].Events = 0;
226 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
227 Signalled++;
228 } else {
229 AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
230 PrintEvents( PollReq->Handles[i].Events );
231 AFD_DbgPrint(MID_TRACE,("\n"));
232
233 PollReq->Handles[i].Status =
234 PollReq->Handles[i].Events & FCB->PollState;
235 if( PollReq->Handles[i].Status ) {
236 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
237 FCB, FCB->PollState));
238 Signalled++;
239 }
240 }
241 }
242
243 if( Signalled ) {
244 Status = STATUS_SUCCESS;
245 Irp->IoStatus.Status = Status;
246 SignalSocket( Poll, PollReq, Status );
247 } else {
248 Status = STATUS_PENDING;
249 IoMarkIrpPending( Irp );
250 }
251
252 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
253 } else Status = STATUS_NO_MEMORY;
254
255 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
256
257 return Status;
258 }
259
260 NTSTATUS STDCALL
261 AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
262 PIO_STACK_LOCATION IrpSp ) {
263 PFILE_OBJECT FileObject = IrpSp->FileObject;
264 NTSTATUS Status = STATUS_NO_MEMORY;
265 PAFD_EVENT_SELECT_INFO EventSelectInfo =
266 (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp );
267 PAFD_FCB FCB = FileObject->FsContext;
268
269 AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
270 EventSelectInfo->EventObject,
271 EventSelectInfo->Events));
272
273 if( !SocketAcquireStateLock( FCB ) ) {
274 UnlockRequest( Irp, IrpSp );
275 return LostSocket( Irp, FALSE );
276 }
277
278 FCB->EventSelectTriggers = FCB->EventsFired = 0;
279 if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
280 FCB->EventSelect = NULL;
281
282 if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
283 Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
284 EventObject,
285 FILE_ALL_ACCESS,
286 NULL,
287 KernelMode,
288 (PVOID *)&FCB->EventSelect,
289 NULL );
290
291 if( !NT_SUCCESS(Status) )
292 FCB->EventSelect = NULL;
293 else
294 FCB->EventSelectTriggers = EventSelectInfo->Events;
295 } else /* Work done, cancelling select */
296 Status = STATUS_SUCCESS;
297
298 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
299
300 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
301 0, NULL, TRUE );
302 }
303
304 NTSTATUS STDCALL
305 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
306 PIO_STACK_LOCATION IrpSp ) {
307 PFILE_OBJECT FileObject = IrpSp->FileObject;
308 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
309 (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
310 PAFD_FCB FCB = FileObject->FsContext;
311
312 AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
313
314 if( !SocketAcquireStateLock( FCB ) ) {
315 UnlockRequest( Irp, IrpSp );
316 return LostSocket( Irp, FALSE );
317 }
318
319 EnumReq->PollEvents = FCB->PollState;
320 RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
321
322 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
323 0, NULL, TRUE );
324 }
325
326 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
327 BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
328 UINT i;
329 PAFD_FCB FCB;
330 UINT Signalled = 0;
331 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
332
333 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
334
335 for( i = 0; i < PollReq->HandleCount; i++ ) {
336 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
337
338 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
339 FCB = FileObject->FsContext;
340
341 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
342 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
343 AFD_HANDLES(PollReq)[i].Handle = 0;
344 PollReq->Handles[i].Events = 0;
345 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
346 Signalled++;
347 } else {
348 PollReq->Handles[i].Status =
349 PollReq->Handles[i].Events & FCB->PollState;
350 if( PollReq->Handles[i].Status ) {
351 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
352 FCB, FCB->PollState));
353 Signalled++;
354 }
355 }
356 }
357
358 return Signalled ? 1 : 0;
359 }
360
361 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
362 PAFD_ACTIVE_POLL Poll = NULL;
363 PLIST_ENTRY ThePollEnt = NULL;
364 PAFD_FCB FCB;
365 KIRQL OldIrql;
366 PAFD_POLL_INFO PollReq;
367 PKEVENT EventSelect = NULL;
368
369 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
370 DeviceExt, FileObject));
371
372 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
373
374 /* Take care of any event select signalling */
375 FCB = (PAFD_FCB)FileObject->FsContext;
376
377 /* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
378 AFD_DbgPrint(MID_TRACE,("Current State: %x, Events Fired: %x, "
379 "Select Triggers %x\n",
380 FCB->PollState, FCB->EventsFired,
381 FCB->EventSelectTriggers));
382 if( FCB->PollState & ~FCB->EventsFired & FCB->EventSelectTriggers ) {
383 FCB->EventsFired |= FCB->PollState;
384 EventSelect = FCB->EventSelect;
385 }
386
387 if( !FCB ) {
388 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
389 return;
390 }
391
392 /* Now signal normal select irps */
393 ThePollEnt = DeviceExt->Polls.Flink;
394
395 while( ThePollEnt != &DeviceExt->Polls ) {
396 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
397 PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
398 AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
399
400 if( UpdatePollWithFCB( Poll, FileObject ) ) {
401 ThePollEnt = ThePollEnt->Flink;
402 AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
403 SignalSocket( Poll, PollReq, STATUS_SUCCESS );
404 } else
405 ThePollEnt = ThePollEnt->Flink;
406 }
407
408 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
409
410 AFD_DbgPrint(MID_TRACE,("Setting event %x\n", EventSelect));
411 if( EventSelect ) KeSetEvent( EventSelect, IO_NETWORK_INCREMENT, FALSE );
412
413 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
414 }