Fixes:
[reactos.git] / reactos / drivers / net / afd / afd / select.c
1 /* $Id: select.c,v 1.3 2004/09/05 04:26:29 arty Exp $
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].Events = 0;
31 HandleArray[i].Status = 0;
32 }
33 }
34
35 NTSTATUS STDCALL
36 ScanForImmediateTrigger( PAFD_HANDLE HandleArray,
37 UINT HandleCount,
38 PUINT HandlesSet ) {
39 NTSTATUS Status = STATUS_SUCCESS;
40 PFILE_OBJECT FileObject;
41 PAFD_FCB FCB;
42 UINT i;
43 BOOLEAN ShouldReturnNow = FALSE;
44
45 for( i = 0; i < HandleCount && NT_SUCCESS(Status); i++ ) {
46 HandleArray[i].Status = 0;
47 Status =
48 ObReferenceObjectByHandle
49 ( (PVOID)HandleArray[i].Handle,
50 FILE_ALL_ACCESS,
51 NULL,
52 KernelMode,
53 (PVOID*)&FileObject,
54 NULL );
55
56 if( NT_SUCCESS(Status) ) {
57 FCB = FileObject->FsContext;
58 /* Check select bits */
59 if( !SocketAcquireStateLock( FCB ) )
60 Status = STATUS_UNSUCCESSFUL;
61 if( NT_SUCCESS(Status) )
62 HandleArray[i].Status =
63 FCB->PollState & HandleArray[i].Events;
64 if( HandleArray[i].Status ) ShouldReturnNow = TRUE;
65 ObDereferenceObject( (PVOID)HandleArray[i].Handle );
66 }
67 }
68
69 if( !NT_SUCCESS(Status) || ShouldReturnNow ) return Status;
70 else return STATUS_PENDING;
71 }
72
73 VOID SelectTimeout( PKDPC Dpc,
74 PVOID DeferredContext,
75 PVOID SystemArgument1,
76 PVOID SystemArgument2 ) {
77 PAFD_ACTIVE_POLL Poll = DeferredContext;
78 PAFD_POLL_INFO PollReq;
79 PAFD_DEVICE_EXTENSION DeviceExt;
80 PIRP Irp;
81 KIRQL OldIrql;
82
83 Irp = Poll->Irp;
84 DeviceExt = Poll->DeviceExt;
85
86 PollReq = Irp->AssociatedIrp.SystemBuffer;
87
88 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
89 RemoveEntryList( &Poll->ListEntry );
90 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
91
92 ExFreePool( Poll );
93
94 ZeroEvents( PollReq->Handles, PollReq->HandleCount );
95
96 Irp->IoStatus.Status = STATUS_TIMEOUT;
97 Irp->IoStatus.Information = -1;
98
99 IoCompleteRequest( Irp, IO_NO_INCREMENT );
100 }
101
102 NTSTATUS STDCALL
103 AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
104 PIO_STACK_LOCATION IrpSp ) {
105 NTSTATUS Status = STATUS_NO_MEMORY;
106 PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
107 PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
108 PAFD_ACTIVE_POLL Poll = NULL;
109 UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
110 UINT AllocSize =
111 CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
112 KIRQL OldIrql;
113 UINT HandlesSignalled;
114
115 AFD_DbgPrint(MID_TRACE,("Called\n"));
116
117 Status = ScanForImmediateTrigger( PollReq->Handles,
118 PollReq->HandleCount,
119 &HandlesSignalled );
120
121 if( Status == STATUS_PENDING ) {
122 Poll = ExAllocatePool( NonPagedPool, AllocSize );
123
124 if( Poll ) {
125 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
126
127 KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
128 (PKDEFERRED_ROUTINE)SelectTimeout,
129 Poll );
130 PollReq->Timeout.QuadPart *= -1;
131 /* Negative values are relative */
132 KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
133 KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
134
135 Poll->Irp = Irp;
136 Poll->DeviceExt = DeviceExt;
137
138 InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
139 Status = STATUS_PENDING;
140
141 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
142 } else Status = STATUS_NO_MEMORY;
143 } else if( Status == STATUS_SUCCESS ) {
144 CopyBackStatus( PollReq->Handles,
145 PollReq->HandleCount );
146 } else {
147 ZeroEvents( PollReq->Handles,
148 PollReq->HandleCount );
149 }
150
151 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
152
153 if( Status == STATUS_PENDING )
154 IoMarkIrpPending( Irp );
155 else {
156 Irp->IoStatus.Status = Status;
157 Irp->IoStatus.Information = HandlesSignalled;
158 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
159 }
160
161 return Status;
162 }
163
164 VOID SignalSocket( PAFD_ACTIVE_POLL Poll, PAFD_POLL_INFO PollReq, UINT i ) {
165 /* One of the files was destroyed. We return now with error. */
166 Poll->Irp->IoStatus.Status = STATUS_SUCCESS; /* XXX REVISIT */
167 Poll->Irp->IoStatus.Information = 1;
168 CopyBackStatus( PollReq->Handles,
169 PollReq->HandleCount );
170 IoCompleteRequest( Poll->Irp, IO_NETWORK_INCREMENT );
171 }
172
173 BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
174 UINT i;
175 NTSTATUS Status;
176 PFILE_OBJECT TargetFile;
177 PAFD_FCB FCB;
178 PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
179
180 for( i = 0; i < PollReq->HandleCount; i++ ) {
181 Status =
182 ObReferenceObjectByHandle
183 ( (PVOID)PollReq->Handles[i].Handle,
184 FILE_ALL_ACCESS,
185 NULL,
186 KernelMode,
187 (PVOID*)&TargetFile,
188 NULL );
189
190 if( !NT_SUCCESS(Status) ) {
191 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
192 SignalSocket( Poll, PollReq, i );
193 return TRUE;
194 } else {
195 FCB = FileObject->FsContext;
196
197 if( !SocketAcquireStateLock( FCB ) ) {
198 PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
199 SignalSocket( Poll, PollReq, i );
200 } else {
201 PollReq->Handles[i].Status =
202 PollReq->Handles[i].Events & FCB->PollState;
203 if( PollReq->Handles[i].Status )
204 SignalSocket( Poll, PollReq, i );
205 }
206 return TRUE;
207 }
208 }
209
210 return FALSE;
211 }
212
213 VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
214 PAFD_ACTIVE_POLL Poll = NULL;
215 PLIST_ENTRY ThePollEnt = NULL;
216 KIRQL OldIrql;
217
218 AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
219 DeviceExt, FileObject));
220
221 KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
222
223 ThePollEnt = DeviceExt->Polls.Flink;
224
225 while( ThePollEnt != &DeviceExt->Polls ) {
226 Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
227 if( UpdatePollWithFCB( Poll, FileObject ) ) {
228 ThePollEnt = ThePollEnt->Flink;
229 RemoveEntryList( &Poll->ListEntry );
230 } else
231 ThePollEnt = ThePollEnt->Flink;
232 }
233
234 KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
235
236 AFD_DbgPrint(MID_TRACE,("Leaving\n"));
237 }