b78ee07f624fc7ffccc629573c49288fa5a4f21c
[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 HandleArray[i].Events = 0;
53 }
54 }
55
56
57 /* you must pass either Poll OR Irp */
58 static VOID SignalSocket(
59 PAFD_ACTIVE_POLL Poll OPTIONAL,
60 PIRP _Irp OPTIONAL,
61 PAFD_POLL_INFO PollReq,
62 NTSTATUS Status
63 )
64 {
65 UINT i;
66 PIRP Irp = _Irp ? _Irp : Poll->Irp;
67 AFD_DbgPrint(MID_TRACE,("Called (Status %x)\n", Status));
68
69 if (Poll)
70 {
71 KeCancelTimer( &Poll->Timer );
72 RemoveEntryList( &Poll->ListEntry );
73 ExFreePool( Poll );
74 }
75
76 Irp->IoStatus.Status = Status;
77 Irp->IoStatus.Information =
78 FIELD_OFFSET(AFD_POLL_INFO, Handles) + sizeof(AFD_HANDLE) * PollReq->HandleCount;
79 CopyBackStatus( PollReq->Handles,
80 PollReq->HandleCount );
81 for( i = 0; i < PollReq->HandleCount; i++ ) {
82 AFD_DbgPrint
83 (MAX_TRACE,
84 ("Handle(%x): Got %x,%x\n",
85 PollReq->Handles[i].Handle,
86 PollReq->Handles[i].Events,
87 PollReq->Handles[i].Status));
88 }
89 UnlockHandles( AFD_HANDLES(PollReq), PollReq->HandleCount );
90 if( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
91 AFD_DbgPrint(MID_TRACE,("Completing\n"));
92 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
93 AFD_DbgPrint(MID_TRACE,("Done\n"));
94 }
95
96 static VOID SelectTimeout( PKDPC Dpc,
97 PVOID DeferredContext,
98 PVOID SystemArgument1,
99 PVOID SystemArgument2 ) {
100 PAFD_ACTIVE_POLL Poll = DeferredContext;
101 PAFD_POLL_INFO PollReq;
102 PIRP Irp;
103 KIRQL OldIrql;
104 PAFD_DEVICE_EXTENSION DeviceExt;
105
106 AFD_DbgPrint(MID_TRACE,("Called\n"));
107
108 Irp = Poll->Irp;
109 DeviceExt = Poll->DeviceExt;
110 PollReq = Irp->AssociatedIrp.SystemBuffer;
111
112 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
113
114 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
115 SignalSocket( Poll, NULL, PollReq, STATUS_TIMEOUT );
116 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
117
118 AFD_DbgPrint(MID_TRACE,("Timeout\n"));
119 }
120
121 VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
122 PFILE_OBJECT FileObject,
123 BOOLEAN OnlyExclusive ) {
124 KIRQL OldIrql;
125 PLIST_ENTRY ListEntry;
126 PAFD_ACTIVE_POLL Poll;
127 PIRP Irp;
128 PAFD_POLL_INFO PollReq;
129 PAFD_HANDLE HandleArray;
130 UINT i;
131
132 AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %x\n", FileObject));
133
134 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
135
136 ListEntry = DeviceExt->Polls.Flink;
137 while ( ListEntry != &DeviceExt->Polls ) {
138 Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
139 ListEntry = ListEntry->Flink;
140 Irp = Poll->Irp;
141 PollReq = Irp->AssociatedIrp.SystemBuffer;
142 HandleArray = AFD_HANDLES(PollReq);
143
144 for( i = 0; i < PollReq->HandleCount; i++ ) {
145 AFD_DbgPrint(MAX_TRACE,("Req: %x, This %x\n",
146 HandleArray[i].Handle, FileObject));
147 if( (PVOID)HandleArray[i].Handle == FileObject &&
148 (!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
149 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
150 SignalSocket( Poll, NULL, PollReq, STATUS_CANCELLED );
151 }
152 }
153 }
154
155 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
156
157 AFD_DbgPrint(MID_TRACE,("Done\n"));
158 }
159
160 NTSTATUS NTAPI
161 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
162 PIO_STACK_LOCATION IrpSp ) {
163 NTSTATUS Status = STATUS_NO_MEMORY;
164 PAFD_FCB FCB;
165 PFILE_OBJECT FileObject;
166 PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
167 PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
168 UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
169 UINT AllocSize =
170 CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
171 KIRQL OldIrql;
172 UINT i, Signalled = 0;
173 ULONG Exclusive = PollReq->Exclusive;
174
175 AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
176 PollReq->HandleCount,
177 (INT)(PollReq->Timeout.QuadPart)));
178
179 SET_AFD_HANDLES(PollReq,
180 LockHandles( PollReq->Handles, PollReq->HandleCount ));
181
182 if( !AFD_HANDLES(PollReq) ) {
183 Irp->IoStatus.Status = STATUS_NO_MEMORY;
184 Irp->IoStatus.Information = 0;
185 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
186 return STATUS_NO_MEMORY;
187 }
188
189 if( Exclusive ) {
190 for( i = 0; i < PollReq->HandleCount; i++ ) {
191 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
192
193 KillSelectsForFCB( DeviceExt,
194 (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
195 TRUE );
196 }
197 }
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 AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
208 PrintEvents( PollReq->Handles[i].Events );
209 AFD_DbgPrint(MID_TRACE,("\n"));
210
211 PollReq->Handles[i].Status =
212 PollReq->Handles[i].Events & FCB->PollState;
213 if( PollReq->Handles[i].Status ) {
214 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
215 FCB, FCB->PollState));
216 Signalled++;
217 }
218 }
219
220 if( Signalled ) {
221 Status = STATUS_SUCCESS;
222 Irp->IoStatus.Status = Status;
223 SignalSocket( NULL, Irp, PollReq, Status );
224 } else {
225
226 PAFD_ACTIVE_POLL Poll = NULL;
227
228 Poll = ExAllocatePool( NonPagedPool, AllocSize );
229
230 if (Poll){
231 Poll->Irp = Irp;
232 Poll->DeviceExt = DeviceExt;
233 Poll->Exclusive = Exclusive;
234
235 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
236
237 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
238 (PKDEFERRED_ROUTINE)SelectTimeout,
239 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 } else {
248 AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
249 Status = STATUS_NO_MEMORY;
250 }
251 }
252
253 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
254
255 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
256
257 return Status;
258 }
259
260 NTSTATUS NTAPI
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 if( !SocketAcquireStateLock( FCB ) ) {
270 return LostSocket( Irp );
271 }
272
273 if ( !EventSelectInfo ) {
274 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
275 0 );
276 }
277 AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
278 EventSelectInfo->EventObject,
279 EventSelectInfo->Events));
280
281 if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
282 FCB->EventSelect = NULL;
283
284 if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
285 Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
286 EventObject,
287 FILE_ALL_ACCESS,
288 NULL,
289 KernelMode,
290 (PVOID *)&FCB->EventSelect,
291 NULL );
292
293 if( !NT_SUCCESS(Status) )
294 FCB->EventSelect = NULL;
295 else
296 FCB->EventSelectTriggers = EventSelectInfo->Events;
297 } else
298 Status = STATUS_INVALID_PARAMETER;
299
300 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
301
302 return UnlockAndMaybeComplete( FCB, Status, Irp,
303 0 );
304 }
305
306 NTSTATUS NTAPI
307 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
308 PIO_STACK_LOCATION IrpSp ) {
309 PFILE_OBJECT FileObject = IrpSp->FileObject;
310 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
311 (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
312 PAFD_FCB FCB = FileObject->FsContext;
313
314 AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
315
316 if( !SocketAcquireStateLock( FCB ) ) {
317 return LostSocket( Irp );
318 }
319
320 if ( !EnumReq ) {
321 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
322 0 );
323 }
324
325 EnumReq->PollEvents = FCB->PollState;
326 RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
327
328 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
329 0 );
330 }
331
332 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
333 static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
334 UINT i;
335 PAFD_FCB FCB;
336 UINT Signalled = 0;
337 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
338
339 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
340
341 for( i = 0; i < PollReq->HandleCount; i++ ) {
342 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
343
344 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
345 FCB = FileObject->FsContext;
346
347 PollReq->Handles[i].Status = PollReq->Handles[i].Events & FCB->PollState;
348 if( PollReq->Handles[i].Status ) {
349 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
350 FCB, FCB->PollState));
351 Signalled++;
352 }
353 }
354
355 return Signalled ? 1 : 0;
356 }
357
358 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
359 PAFD_ACTIVE_POLL Poll = NULL;
360 PLIST_ENTRY ThePollEnt = NULL;
361 PAFD_FCB FCB;
362 KIRQL OldIrql;
363 PAFD_POLL_INFO PollReq;
364
365 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
366 DeviceExt, FileObject));
367
368 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
369
370 /* Take care of any event select signalling */
371 FCB = (PAFD_FCB)FileObject->FsContext;
372
373 if( !FCB ) {
374 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
375 return;
376 }
377
378 /* Now signal normal select irps */
379 ThePollEnt = DeviceExt->Polls.Flink;
380
381 while( ThePollEnt != &DeviceExt->Polls ) {
382 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
383 PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
384 AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
385
386 if( UpdatePollWithFCB( Poll, FileObject ) ) {
387 ThePollEnt = ThePollEnt->Flink;
388 AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
389 SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
390 } else
391 ThePollEnt = ThePollEnt->Flink;
392 }
393
394 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
395
396 if( FCB->EventSelect && (FCB->PollState & FCB->EventSelectTriggers) ) {
397 AFD_DbgPrint(MID_TRACE,("Setting event %x\n", FCB->EventSelect));
398 KeSetEvent( FCB->EventSelect, IO_NETWORK_INCREMENT, FALSE );
399 }
400
401 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
402 }