migrate substitution keywords to SVN
[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 CopyBackStatus( PAFD_HANDLE HandleArray,
16 UINT HandleCount ) {
17 UINT i;
18
19 for( i = 0; i < HandleCount; i++ ) {
20 HandleArray[i].Events = HandleArray[i].Status;
21 HandleArray[i].Status = 0;
22 }
23 }
24
25 VOID ZeroEvents( PAFD_HANDLE HandleArray,
26 UINT HandleCount ) {
27 UINT i;
28
29 for( i = 0; i < HandleCount; i++ )
30 HandleArray[i].Status = 0;
31 }
32
33 VOID RemoveSelect( PAFD_ACTIVE_POLL Poll ) {
34 AFD_DbgPrint(MID_TRACE,("Called\n"));
35
36 RemoveEntryList( &Poll->ListEntry );
37 KeCancelTimer( &Poll->Timer );
38
39 ExFreePool( Poll );
40
41 AFD_DbgPrint(MID_TRACE,("Done\n"));
42 }
43
44 VOID SignalSocket( PAFD_ACTIVE_POLL Poll, PAFD_POLL_INFO PollReq,
45 NTSTATUS Status ) {
46 PIRP Irp = Poll->Irp;
47 AFD_DbgPrint(MID_TRACE,("Called (Status %x)\n", Status));
48 Poll->Irp->IoStatus.Status = Status;
49 Poll->Irp->IoStatus.Information =
50 FIELD_OFFSET(AFD_POLL_INFO, Handles) + sizeof(AFD_HANDLE) * PollReq->HandleCount;
51 CopyBackStatus( PollReq->Handles,
52 PollReq->HandleCount );
53 UnlockHandles( AFD_HANDLES(PollReq), PollReq->HandleCount );
54 AFD_DbgPrint(MID_TRACE,("Completing\n"));
55 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
56 RemoveEntryList( &Poll->ListEntry );
57 RemoveSelect( Poll );
58 AFD_DbgPrint(MID_TRACE,("Done\n"));
59 }
60
61 VOID SelectTimeout( PKDPC Dpc,
62 PVOID DeferredContext,
63 PVOID SystemArgument1,
64 PVOID SystemArgument2 ) {
65 PAFD_ACTIVE_POLL Poll = DeferredContext;
66 PAFD_POLL_INFO PollReq;
67 PIRP Irp;
68 KIRQL OldIrql;
69 PAFD_DEVICE_EXTENSION DeviceExt;
70
71 AFD_DbgPrint(MID_TRACE,("Called\n"));
72
73 Irp = Poll->Irp;
74 DeviceExt = Poll->DeviceExt;
75 PollReq = Irp->AssociatedIrp.SystemBuffer;
76
77 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
78
79 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
80 SignalSocket( Poll, PollReq, STATUS_TIMEOUT );
81 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
82
83 AFD_DbgPrint(MID_TRACE,("Timeout\n"));
84 }
85
86 VOID KillExclusiveSelects( PAFD_DEVICE_EXTENSION DeviceExt ) {
87 KIRQL OldIrql;
88 PLIST_ENTRY ListEntry;
89 PAFD_ACTIVE_POLL Poll;
90 PIRP Irp;
91 PAFD_POLL_INFO PollReq;
92
93 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
94
95 ListEntry = DeviceExt->Polls.Flink;
96 while ( ListEntry != &DeviceExt->Polls ) {
97 Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
98 ListEntry = ListEntry->Flink;
99 if( Poll->Exclusive ) {
100 Irp = Poll->Irp;
101 PollReq = Irp->AssociatedIrp.SystemBuffer;
102 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
103 SignalSocket( Poll, PollReq, STATUS_CANCELLED );
104 }
105 }
106
107 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
108 }
109
110 NTSTATUS STDCALL
111 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
112 PIO_STACK_LOCATION IrpSp ) {
113 NTSTATUS Status = STATUS_NO_MEMORY;
114 PAFD_FCB FCB;
115 PFILE_OBJECT FileObject;
116 PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
117 PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
118 PAFD_ACTIVE_POLL Poll = NULL;
119 UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
120 UINT AllocSize =
121 CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
122 KIRQL OldIrql;
123 UINT i, Signalled = 0;
124 ULONG Exclusive = PollReq->Exclusive;
125
126 AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
127 PollReq->HandleCount,
128 (INT)(PollReq->Timeout.QuadPart)));
129
130 SET_AFD_HANDLES(PollReq,
131 LockHandles( PollReq->Handles, PollReq->HandleCount ));
132
133 if( Exclusive ) KillExclusiveSelects( DeviceExt );
134
135
136 if( !AFD_HANDLES(PollReq) ) {
137 Irp->IoStatus.Status = STATUS_NO_MEMORY;
138 Irp->IoStatus.Information = 0;
139 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
140 return Irp->IoStatus.Status;
141 }
142
143 ZeroEvents( PollReq->Handles,
144 PollReq->HandleCount );
145
146 Poll = ExAllocatePool( NonPagedPool, AllocSize );
147
148 if( Poll ) {
149 Poll->Irp = Irp;
150 Poll->DeviceExt = DeviceExt;
151 Poll->Exclusive = Exclusive;
152
153 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
154 KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
155
156 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
157 (PKDEFERRED_ROUTINE)SelectTimeout,
158 Poll );
159
160 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
161 InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
162
163 for( i = 0; i < PollReq->HandleCount; i++ ) {
164 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
165
166 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
167 FCB = FileObject->FsContext;
168
169 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
170 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
171 AFD_HANDLES(PollReq)[i].Handle = 0;
172 PollReq->Handles[i].Events = 0;
173 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
174 Signalled++;
175 } else {
176 PollReq->Handles[i].Status =
177 PollReq->Handles[i].Events & FCB->PollState;
178 if( PollReq->Handles[i].Status ) {
179 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
180 FCB, FCB->PollState));
181 Signalled++;
182 }
183 }
184 }
185
186 if( Signalled ) {
187 Status = STATUS_SUCCESS;
188 Irp->IoStatus.Status = Status;
189 SignalSocket( Poll, PollReq, Status );
190 } else {
191 Status = STATUS_PENDING;
192 IoMarkIrpPending( Irp );
193 }
194
195 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
196 } else Status = STATUS_NO_MEMORY;
197
198 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
199
200 return Status;
201 }
202
203 NTSTATUS STDCALL
204 AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
205 PIO_STACK_LOCATION IrpSp ) {
206 PFILE_OBJECT FileObject = IrpSp->FileObject;
207 NTSTATUS Status = STATUS_NO_MEMORY;
208 PAFD_EVENT_SELECT_INFO EventSelectInfo =
209 (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp );
210 PAFD_FCB FCB = FileObject->FsContext;
211
212 AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
213 EventSelectInfo->EventObject,
214 EventSelectInfo->Events));
215
216 if( !SocketAcquireStateLock( FCB ) ) {
217 UnlockRequest( Irp, IrpSp );
218 return LostSocket( Irp, FALSE );
219 }
220
221 FCB->EventSelectTriggers = FCB->EventsFired = 0;
222 if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
223 FCB->EventSelect = NULL;
224
225 if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
226 Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
227 EventObject,
228 FILE_ALL_ACCESS,
229 NULL,
230 KernelMode,
231 (PVOID *)&FCB->EventSelect,
232 NULL );
233
234 if( !NT_SUCCESS(Status) )
235 FCB->EventSelect = NULL;
236 else
237 FCB->EventSelectTriggers = EventSelectInfo->Events;
238 } else /* Work done, cancelling select */
239 Status = STATUS_SUCCESS;
240
241 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
242
243 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
244 0, NULL, TRUE );
245 }
246
247 NTSTATUS STDCALL
248 AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
249 PIO_STACK_LOCATION IrpSp ) {
250 PFILE_OBJECT FileObject = IrpSp->FileObject;
251 PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
252 (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
253 PAFD_FCB FCB = FileObject->FsContext;
254
255 AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
256
257 if( !SocketAcquireStateLock( FCB ) ) {
258 UnlockRequest( Irp, IrpSp );
259 return LostSocket( Irp, FALSE );
260 }
261
262 EnumReq->PollEvents = FCB->PollState;
263 RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
264
265 return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
266 0, NULL, TRUE );
267 }
268
269 /* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
270 BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
271 UINT i;
272 PAFD_FCB FCB;
273 UINT Signalled = 0;
274 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
275
276 ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
277
278 for( i = 0; i < PollReq->HandleCount; i++ ) {
279 if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
280
281 FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
282 FCB = FileObject->FsContext;
283
284 if( (FCB->PollState & AFD_EVENT_CLOSE) ||
285 (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
286 AFD_HANDLES(PollReq)[i].Handle = 0;
287 PollReq->Handles[i].Events = 0;
288 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
289 Signalled++;
290 } else {
291 PollReq->Handles[i].Status =
292 PollReq->Handles[i].Events & FCB->PollState;
293 if( PollReq->Handles[i].Status ) {
294 AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
295 FCB, FCB->PollState));
296 Signalled++;
297 }
298 }
299 }
300
301 return Signalled ? 1 : 0;
302 }
303
304 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
305 PAFD_ACTIVE_POLL Poll = NULL;
306 PLIST_ENTRY ThePollEnt = NULL;
307 PAFD_FCB FCB;
308 KIRQL OldIrql;
309 PAFD_POLL_INFO PollReq;
310 PKEVENT EventSelect = NULL;
311
312 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
313 DeviceExt, FileObject));
314
315 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
316
317 /* Take care of any event select signalling */
318 FCB = (PAFD_FCB)FileObject->FsContext;
319
320 /* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
321 AFD_DbgPrint(MID_TRACE,("Current State: %x, Events Fired: %x, "
322 "Select Triggers %x\n",
323 FCB->PollState, FCB->EventsFired,
324 FCB->EventSelectTriggers));
325 if( FCB->PollState & ~FCB->EventsFired & FCB->EventSelectTriggers ) {
326 FCB->EventsFired |= FCB->PollState;
327 EventSelect = FCB->EventSelect;
328 }
329
330 if( !FCB ) {
331 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
332 return;
333 }
334
335 /* Now signal normal select irps */
336 ThePollEnt = DeviceExt->Polls.Flink;
337
338 while( ThePollEnt != &DeviceExt->Polls ) {
339 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
340 PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
341 AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
342
343 if( UpdatePollWithFCB( Poll, FileObject ) ) {
344 ThePollEnt = ThePollEnt->Flink;
345 AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
346 SignalSocket( Poll, PollReq, STATUS_SUCCESS );
347 } else
348 ThePollEnt = ThePollEnt->Flink;
349 }
350
351 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
352
353 AFD_DbgPrint(MID_TRACE,("Setting event %x\n", EventSelect));
354 if( EventSelect ) KeSetEvent( EventSelect, IO_NETWORK_INCREMENT, FALSE );
355
356 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
357 }