1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/lock.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 */
10
11 #include "afd.h"
12
GetLockedData(PIRP Irp,PIO_STACK_LOCATION IrpSp)13 PVOID GetLockedData(PIRP Irp, PIO_STACK_LOCATION IrpSp)
14 {
15 ASSERT(Irp->MdlAddress);
16 ASSERT(Irp->Tail.Overlay.DriverContext[0]);
17
18 UNREFERENCED_PARAMETER(IrpSp);
19
20 return Irp->Tail.Overlay.DriverContext[0];
21 }
22
23 /* Lock a method_neither request so it'll be available from DISPATCH_LEVEL */
LockRequest(PIRP Irp,PIO_STACK_LOCATION IrpSp,BOOLEAN Output,KPROCESSOR_MODE * LockMode)24 PVOID LockRequest( PIRP Irp,
25 PIO_STACK_LOCATION IrpSp,
26 BOOLEAN Output,
27 KPROCESSOR_MODE *LockMode) {
28 BOOLEAN LockFailed = FALSE;
29
30 ASSERT(!Irp->MdlAddress);
31
32 switch (IrpSp->MajorFunction)
33 {
34 case IRP_MJ_DEVICE_CONTROL:
35 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
36 ASSERT(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
37 ASSERT(IrpSp->Parameters.DeviceIoControl.InputBufferLength);
38
39
40 Irp->MdlAddress =
41 IoAllocateMdl( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
42 IrpSp->Parameters.DeviceIoControl.InputBufferLength,
43 FALSE,
44 FALSE,
45 NULL );
46 if( Irp->MdlAddress ) {
47 _SEH2_TRY {
48 MmProbeAndLockPages( Irp->MdlAddress, Irp->RequestorMode, IoModifyAccess );
49 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
50 LockFailed = TRUE;
51 } _SEH2_END;
52
53 if( LockFailed ) {
54 AFD_DbgPrint(MIN_TRACE,("Failed to lock pages\n"));
55 IoFreeMdl( Irp->MdlAddress );
56 Irp->MdlAddress = NULL;
57 return NULL;
58 }
59
60 /* The mapped address goes in index 1 */
61 Irp->Tail.Overlay.DriverContext[1] = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
62 if (!Irp->Tail.Overlay.DriverContext[1])
63 {
64 AFD_DbgPrint(MIN_TRACE,("Failed to get mapped address\n"));
65 MmUnlockPages(Irp->MdlAddress);
66 IoFreeMdl( Irp->MdlAddress );
67 Irp->MdlAddress = NULL;
68 return NULL;
69 }
70
71 /* The allocated address goes in index 0 */
72 Irp->Tail.Overlay.DriverContext[0] = ExAllocatePoolWithTag(NonPagedPool,
73 MmGetMdlByteCount(Irp->MdlAddress),
74 TAG_AFD_DATA_BUFFER);
75
76 if (!Irp->Tail.Overlay.DriverContext[0])
77 {
78 AFD_DbgPrint(MIN_TRACE,("Failed to allocate memory\n"));
79 MmUnlockPages(Irp->MdlAddress);
80 IoFreeMdl( Irp->MdlAddress );
81 Irp->MdlAddress = NULL;
82 return NULL;
83 }
84
85 RtlCopyMemory(Irp->Tail.Overlay.DriverContext[0],
86 Irp->Tail.Overlay.DriverContext[1],
87 MmGetMdlByteCount(Irp->MdlAddress));
88
89 /* If we don't want a copy back, we zero the mapped address pointer */
90 if (!Output)
91 {
92 Irp->Tail.Overlay.DriverContext[1] = NULL;
93 }
94
95 /* We're using a user-mode buffer directly */
96 if (LockMode != NULL)
97 {
98 *LockMode = UserMode;
99 }
100 }
101 else return NULL;
102 break;
103
104 case IRP_MJ_READ:
105 case IRP_MJ_WRITE:
106 ASSERT(Irp->UserBuffer);
107
108 Irp->MdlAddress =
109 IoAllocateMdl(Irp->UserBuffer,
110 (IrpSp->MajorFunction == IRP_MJ_READ) ?
111 IrpSp->Parameters.Read.Length : IrpSp->Parameters.Write.Length,
112 FALSE,
113 FALSE,
114 NULL );
115 if( Irp->MdlAddress ) {
116 PAFD_RECV_INFO AfdInfo;
117
118 _SEH2_TRY {
119 MmProbeAndLockPages( Irp->MdlAddress, Irp->RequestorMode, IoModifyAccess );
120 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
121 LockFailed = TRUE;
122 } _SEH2_END;
123
124 if( LockFailed ) {
125 AFD_DbgPrint(MIN_TRACE,("Failed to lock pages\n"));
126 IoFreeMdl( Irp->MdlAddress );
127 Irp->MdlAddress = NULL;
128 return NULL;
129 }
130
131 /* We need to create the info struct that AFD expects for all send/recv requests */
132 AfdInfo = ExAllocatePoolWithTag(NonPagedPool,
133 sizeof(AFD_RECV_INFO) + sizeof(AFD_WSABUF),
134 TAG_AFD_DATA_BUFFER);
135
136 if (!AfdInfo)
137 {
138 AFD_DbgPrint(MIN_TRACE,("Failed to allocate memory\n"));
139 MmUnlockPages(Irp->MdlAddress);
140 IoFreeMdl( Irp->MdlAddress );
141 Irp->MdlAddress = NULL;
142 return NULL;
143 }
144
145 /* We'll append the buffer array to this struct */
146 AfdInfo->BufferArray = (PAFD_WSABUF)(AfdInfo + 1);
147 AfdInfo->BufferCount = 1;
148
149 /* Setup the default flags values */
150 AfdInfo->AfdFlags = 0;
151 AfdInfo->TdiFlags = 0;
152
153 /* Now build the buffer array */
154 AfdInfo->BufferArray[0].buf = MmGetSystemAddressForMdl(Irp->MdlAddress);
155 AfdInfo->BufferArray[0].len = MmGetMdlByteCount(Irp->MdlAddress);
156
157 /* Store the struct where AFD expects */
158 Irp->Tail.Overlay.DriverContext[0] = AfdInfo;
159
160 /* Don't copy anything out */
161 Irp->Tail.Overlay.DriverContext[1] = NULL;
162
163 /* We're using a placeholder buffer that we allocated */
164 if (LockMode != NULL)
165 {
166 *LockMode = KernelMode;
167 }
168 }
169 else return NULL;
170 break;
171
172 default:
173 ASSERT(FALSE);
174 return NULL;
175 }
176
177 return GetLockedData(Irp, IrpSp);
178 }
179
UnlockRequest(PIRP Irp,PIO_STACK_LOCATION IrpSp)180 VOID UnlockRequest( PIRP Irp, PIO_STACK_LOCATION IrpSp )
181 {
182 ASSERT(Irp->MdlAddress);
183 ASSERT(Irp->Tail.Overlay.DriverContext[0]);
184
185 UNREFERENCED_PARAMETER(IrpSp);
186
187 /* Check if we need to copy stuff back */
188 if (Irp->Tail.Overlay.DriverContext[1] != NULL)
189 {
190 RtlCopyMemory(Irp->Tail.Overlay.DriverContext[1],
191 Irp->Tail.Overlay.DriverContext[0],
192 MmGetMdlByteCount(Irp->MdlAddress));
193 }
194
195 ExFreePoolWithTag(Irp->Tail.Overlay.DriverContext[0], TAG_AFD_DATA_BUFFER);
196 MmUnlockPages( Irp->MdlAddress );
197 IoFreeMdl( Irp->MdlAddress );
198 Irp->MdlAddress = NULL;
199 }
200
201 /* Note: We add an extra buffer if LockAddress is true. This allows us to
202 * treat the address buffer as an ordinary client buffer. It's only used
203 * for datagrams. */
204
LockBuffers(PAFD_WSABUF Buf,UINT Count,PVOID AddressBuf,PINT AddressLen,BOOLEAN Write,BOOLEAN LockAddress,KPROCESSOR_MODE LockMode)205 PAFD_WSABUF LockBuffers( PAFD_WSABUF Buf, UINT Count,
206 PVOID AddressBuf, PINT AddressLen,
207 BOOLEAN Write, BOOLEAN LockAddress,
208 KPROCESSOR_MODE LockMode) {
209 UINT i;
210 /* Copy the buffer array so we don't lose it */
211 UINT Lock = LockAddress ? 2 : 0;
212 UINT Size = (sizeof(AFD_WSABUF) + sizeof(AFD_MAPBUF)) * (Count + Lock);
213 PAFD_WSABUF NewBuf = ExAllocatePoolWithTag(PagedPool, Size, TAG_AFD_WSA_BUFFER);
214 BOOLEAN LockFailed = FALSE;
215 PAFD_MAPBUF MapBuf;
216
217 AFD_DbgPrint(MID_TRACE,("Called(%p)\n", NewBuf));
218
219 if( NewBuf ) {
220 RtlZeroMemory(NewBuf, Size);
221
222 MapBuf = (PAFD_MAPBUF)(NewBuf + Count + Lock);
223
224 _SEH2_TRY {
225 RtlCopyMemory( NewBuf, Buf, sizeof(AFD_WSABUF) * Count );
226 if( LockAddress ) {
227 if (AddressBuf && AddressLen) {
228 NewBuf[Count].buf = AddressBuf;
229 NewBuf[Count].len = *AddressLen;
230 NewBuf[Count + 1].buf = (PVOID)AddressLen;
231 NewBuf[Count + 1].len = sizeof(*AddressLen);
232 }
233 Count += 2;
234 }
235 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
236 AFD_DbgPrint(MIN_TRACE,("Access violation copying buffer info "
237 "from userland (%p %p)\n",
238 Buf, AddressLen));
239 ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER);
240 _SEH2_YIELD(return NULL);
241 } _SEH2_END;
242
243 for( i = 0; i < Count; i++ ) {
244 AFD_DbgPrint(MID_TRACE,("Locking buffer %u (%p:%u)\n",
245 i, NewBuf[i].buf, NewBuf[i].len));
246
247 if( NewBuf[i].buf && NewBuf[i].len ) {
248 MapBuf[i].Mdl = IoAllocateMdl( NewBuf[i].buf,
249 NewBuf[i].len,
250 FALSE,
251 FALSE,
252 NULL );
253 } else {
254 MapBuf[i].Mdl = NULL;
255 continue;
256 }
257
258 AFD_DbgPrint(MID_TRACE,("NewMdl @ %p\n", MapBuf[i].Mdl));
259
260 if( MapBuf[i].Mdl ) {
261 AFD_DbgPrint(MID_TRACE,("Probe and lock pages\n"));
262 _SEH2_TRY {
263 MmProbeAndLockPages( MapBuf[i].Mdl, LockMode,
264 Write ? IoModifyAccess : IoReadAccess );
265 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
266 LockFailed = TRUE;
267 } _SEH2_END;
268 AFD_DbgPrint(MID_TRACE,("MmProbeAndLock finished\n"));
269
270 if( LockFailed ) {
271 AFD_DbgPrint(MIN_TRACE,("Failed to lock pages\n"));
272 IoFreeMdl( MapBuf[i].Mdl );
273 MapBuf[i].Mdl = NULL;
274 ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER);
275 return NULL;
276 }
277 } else {
278 ExFreePoolWithTag(NewBuf, TAG_AFD_WSA_BUFFER);
279 return NULL;
280 }
281 }
282 }
283
284 AFD_DbgPrint(MID_TRACE,("Leaving %p\n", NewBuf));
285
286 return NewBuf;
287 }
288
UnlockBuffers(PAFD_WSABUF Buf,UINT Count,BOOL Address)289 VOID UnlockBuffers( PAFD_WSABUF Buf, UINT Count, BOOL Address ) {
290 UINT Lock = Address ? 2 : 0;
291 PAFD_MAPBUF Map = (PAFD_MAPBUF)(Buf + Count + Lock);
292 UINT i;
293
294 if( !Buf ) return;
295
296 for( i = 0; i < Count + Lock; i++ ) {
297 if( Map[i].Mdl ) {
298 MmUnlockPages( Map[i].Mdl );
299 IoFreeMdl( Map[i].Mdl );
300 Map[i].Mdl = NULL;
301 }
302 }
303
304 ExFreePoolWithTag(Buf, TAG_AFD_WSA_BUFFER);
305 Buf = NULL;
306 }
307
308 /* Produce a kernel-land handle array with handles replaced by object
309 * pointers. This will allow the system to do proper alerting */
LockHandles(PAFD_HANDLE HandleArray,UINT HandleCount)310 PAFD_HANDLE LockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) {
311 UINT i;
312 NTSTATUS Status = STATUS_SUCCESS;
313
314 PAFD_HANDLE FileObjects = ExAllocatePoolWithTag(NonPagedPool,
315 HandleCount * sizeof(AFD_HANDLE),
316 TAG_AFD_POLL_HANDLE);
317
318 for( i = 0; FileObjects && i < HandleCount; i++ ) {
319 FileObjects[i].Status = 0;
320 FileObjects[i].Events = HandleArray[i].Events;
321 FileObjects[i].Handle = 0;
322 if( !HandleArray[i].Handle ) continue;
323 if( NT_SUCCESS(Status) ) {
324 Status = ObReferenceObjectByHandle
325 ( (PVOID)HandleArray[i].Handle,
326 FILE_ALL_ACCESS,
327 NULL,
328 KernelMode,
329 (PVOID*)&FileObjects[i].Handle,
330 NULL );
331 }
332
333 if( !NT_SUCCESS(Status) )
334 {
335 AFD_DbgPrint(MIN_TRACE,("Failed to reference handles (0x%x)\n", Status));
336 FileObjects[i].Handle = 0;
337 }
338 }
339
340 if( !NT_SUCCESS(Status) ) {
341 UnlockHandles( FileObjects, HandleCount );
342 return NULL;
343 }
344
345 return FileObjects;
346 }
347
UnlockHandles(PAFD_HANDLE HandleArray,UINT HandleCount)348 VOID UnlockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) {
349 UINT i;
350
351 for( i = 0; i < HandleCount; i++ ) {
352 if( HandleArray[i].Handle )
353 ObDereferenceObject( (PVOID)HandleArray[i].Handle );
354 }
355
356 ExFreePoolWithTag(HandleArray, TAG_AFD_POLL_HANDLE);
357 HandleArray = NULL;
358 }
359
SocketAcquireStateLock(PAFD_FCB FCB)360 BOOLEAN SocketAcquireStateLock( PAFD_FCB FCB ) {
361 if( !FCB ) return FALSE;
362
363 return !KeWaitForMutexObject(&FCB->Mutex,
364 Executive,
365 KernelMode,
366 FALSE,
367 NULL);
368 }
369
SocketStateUnlock(PAFD_FCB FCB)370 VOID SocketStateUnlock( PAFD_FCB FCB ) {
371 KeReleaseMutex(&FCB->Mutex, FALSE);
372 }
373
UnlockAndMaybeComplete(PAFD_FCB FCB,NTSTATUS Status,PIRP Irp,UINT Information)374 NTSTATUS NTAPI UnlockAndMaybeComplete
375 ( PAFD_FCB FCB, NTSTATUS Status, PIRP Irp,
376 UINT Information ) {
377 Irp->IoStatus.Status = Status;
378 Irp->IoStatus.Information = Information;
379 if ( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
380 (void)IoSetCancelRoutine(Irp, NULL);
381 SocketStateUnlock( FCB );
382 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
383 return Status;
384 }
385
386
LostSocket(PIRP Irp)387 NTSTATUS LostSocket( PIRP Irp ) {
388 NTSTATUS Status = STATUS_FILE_CLOSED;
389 AFD_DbgPrint(MIN_TRACE,("Called.\n"));
390 Irp->IoStatus.Information = 0;
391 Irp->IoStatus.Status = Status;
392 if ( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
393 IoCompleteRequest( Irp, IO_NO_INCREMENT );
394 return Status;
395 }
396
QueueUserModeIrp(PAFD_FCB FCB,PIRP Irp,UINT Function)397 NTSTATUS QueueUserModeIrp(PAFD_FCB FCB, PIRP Irp, UINT Function)
398 {
399 NTSTATUS Status;
400
401 /* Add the IRP to the queue in all cases (so AfdCancelHandler will work properly) */
402 InsertTailList( &FCB->PendingIrpList[Function],
403 &Irp->Tail.Overlay.ListEntry );
404
405 /* Acquire the cancel spin lock and check the cancel bit */
406 IoAcquireCancelSpinLock(&Irp->CancelIrql);
407 if (!Irp->Cancel)
408 {
409 /* We are not cancelled; we're good to go so
410 * set the cancel routine, release the cancel spin lock,
411 * mark the IRP as pending, and
412 * return STATUS_PENDING to the caller
413 */
414 (void)IoSetCancelRoutine(Irp, AfdCancelHandler);
415 IoReleaseCancelSpinLock(Irp->CancelIrql);
416 IoMarkIrpPending(Irp);
417 Status = STATUS_PENDING;
418 }
419 else
420 {
421 /* We were already cancelled before we were able to register our cancel routine
422 * so we are to call the cancel routine ourselves right here to cancel the IRP
423 * (which handles all the stuff we do above) and return STATUS_CANCELLED to the caller
424 */
425 AfdCancelHandler(IoGetCurrentIrpStackLocation(Irp)->DeviceObject,
426 Irp);
427 Status = STATUS_CANCELLED;
428 }
429
430 return Status;
431 }
432
LeaveIrpUntilLater(PAFD_FCB FCB,PIRP Irp,UINT Function)433 NTSTATUS LeaveIrpUntilLater( PAFD_FCB FCB, PIRP Irp, UINT Function ) {
434 NTSTATUS Status;
435
436 Status = QueueUserModeIrp(FCB, Irp, Function);
437
438 SocketStateUnlock( FCB );
439
440 return Status;
441 }
442