xref: /reactos/drivers/network/afd/afd/lock.c (revision b8309397)
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