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)
11 #include "tdi_proto.h"
14 #include "pseh/pseh2.h"
16 /* Lock a method_neither request so it'll be available from DISPATCH_LEVEL */
17 PVOID
LockRequest( PIRP Irp
, PIO_STACK_LOCATION IrpSp
) {
18 BOOLEAN LockFailed
= FALSE
;
21 IoAllocateMdl( IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
22 IrpSp
->Parameters
.DeviceIoControl
.InputBufferLength
,
26 if( Irp
->MdlAddress
) {
28 MmProbeAndLockPages( Irp
->MdlAddress
, Irp
->RequestorMode
, IoModifyAccess
);
29 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
34 IoFreeMdl( Irp
->MdlAddress
);
35 Irp
->MdlAddress
= NULL
;
39 IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
=
40 MmGetSystemAddressForMdlSafe( Irp
->MdlAddress
, NormalPagePriority
);
42 if( !IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
) {
43 IoFreeMdl( Irp
->MdlAddress
);
44 Irp
->MdlAddress
= NULL
;
48 return IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
52 VOID
UnlockRequest( PIRP Irp
, PIO_STACK_LOCATION IrpSp
) {
53 PVOID Buffer
= MmGetSystemAddressForMdlSafe( Irp
->MdlAddress
, NormalPagePriority
);
54 if( IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
== Buffer
|| Buffer
== NULL
) {
55 MmUnmapLockedPages( IrpSp
->Parameters
.DeviceIoControl
.Type3InputBuffer
, Irp
->MdlAddress
);
56 MmUnlockPages( Irp
->MdlAddress
);
57 IoFreeMdl( Irp
->MdlAddress
);
60 Irp
->MdlAddress
= NULL
;
63 /* Note: We add an extra buffer if LockAddress is true. This allows us to
64 * treat the address buffer as an ordinary client buffer. It's only used
67 PAFD_WSABUF
LockBuffers( PAFD_WSABUF Buf
, UINT Count
,
68 PVOID AddressBuf
, PINT AddressLen
,
69 BOOLEAN Write
, BOOLEAN LockAddress
) {
71 /* Copy the buffer array so we don't lose it */
72 UINT Lock
= (LockAddress
&& AddressLen
) ? 2 : 0;
73 UINT Size
= sizeof(AFD_WSABUF
) * (Count
+ Lock
);
74 PAFD_WSABUF NewBuf
= ExAllocatePool( PagedPool
, Size
* 2 );
76 BOOLEAN LockFailed
= FALSE
;
78 AFD_DbgPrint(MID_TRACE
,("Called(%08x)\n", NewBuf
));
81 PAFD_MAPBUF MapBuf
= (PAFD_MAPBUF
)(NewBuf
+ Count
+ Lock
);
84 RtlCopyMemory( NewBuf
, Buf
, sizeof(AFD_WSABUF
) * Count
);
86 NewBuf
[Count
].buf
= AddressBuf
;
87 NewBuf
[Count
].len
= *AddressLen
;
89 NewBuf
[Count
].buf
= (PVOID
)AddressLen
;
90 NewBuf
[Count
].len
= sizeof(*AddressLen
);
93 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
94 AFD_DbgPrint(MIN_TRACE
,("Access violation copying buffer info "
95 "from userland (%x %x)\n",
98 _SEH2_YIELD(return NULL
);
101 for( i
= 0; i
< Count
; i
++ ) {
102 AFD_DbgPrint(MID_TRACE
,("Locking buffer %d (%x:%d)\n",
103 i
, NewBuf
[i
].buf
, NewBuf
[i
].len
));
105 if( NewBuf
[i
].len
) {
106 NewMdl
= IoAllocateMdl( NewBuf
[i
].buf
,
112 MapBuf
[i
].Mdl
= NULL
;
116 AFD_DbgPrint(MID_TRACE
,("NewMdl @ %x\n", NewMdl
));
118 MapBuf
[i
].Mdl
= NewMdl
;
120 if( MapBuf
[i
].Mdl
) {
121 AFD_DbgPrint(MID_TRACE
,("Probe and lock pages\n"));
123 MmProbeAndLockPages( MapBuf
[i
].Mdl
, KernelMode
,
124 Write
? IoModifyAccess
: IoReadAccess
);
125 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
128 AFD_DbgPrint(MID_TRACE
,("MmProbeAndLock finished\n"));
131 IoFreeMdl( MapBuf
[i
].Mdl
);
132 MapBuf
[i
].Mdl
= NULL
;
133 ExFreePool( NewBuf
);
137 ExFreePool( NewBuf
);
143 AFD_DbgPrint(MID_TRACE
,("Leaving %x\n", NewBuf
));
148 VOID
UnlockBuffers( PAFD_WSABUF Buf
, UINT Count
, BOOL Address
) {
149 UINT Lock
= Address
? 2 : 0;
150 PAFD_MAPBUF Map
= (PAFD_MAPBUF
)(Buf
+ Count
+ Lock
);
155 for( i
= 0; i
< Count
+ Lock
; i
++ ) {
157 MmUnlockPages( Map
[i
].Mdl
);
158 IoFreeMdl( Map
[i
].Mdl
);
167 /* Produce a kernel-land handle array with handles replaced by object
168 * pointers. This will allow the system to do proper alerting */
169 PAFD_HANDLE
LockHandles( PAFD_HANDLE HandleArray
, UINT HandleCount
) {
171 NTSTATUS Status
= STATUS_SUCCESS
;
173 PAFD_HANDLE FileObjects
= ExAllocatePool
174 ( NonPagedPool
, HandleCount
* sizeof(AFD_HANDLE
) );
176 for( i
= 0; FileObjects
&& i
< HandleCount
; i
++ ) {
177 FileObjects
[i
].Status
= 0;
178 FileObjects
[i
].Events
= HandleArray
[i
].Events
;
179 FileObjects
[i
].Handle
= 0;
180 if( !HandleArray
[i
].Handle
) continue;
181 if( NT_SUCCESS(Status
) ) {
182 Status
= ObReferenceObjectByHandle
183 ( (PVOID
)(ULONG_PTR
)HandleArray
[i
].Handle
,
187 (PVOID
*)&FileObjects
[i
].Handle
,
192 if( !NT_SUCCESS(Status
) ) {
193 UnlockHandles( FileObjects
, HandleCount
);
200 VOID
UnlockHandles( PAFD_HANDLE HandleArray
, UINT HandleCount
) {
203 for( i
= 0; i
< HandleCount
; i
++ ) {
204 if( HandleArray
[i
].Handle
)
205 ObDereferenceObject( (PVOID
)(ULONG_PTR
)HandleArray
[i
].Handle
);
208 ExFreePool( HandleArray
);
212 /* Returns transitioned state or SOCKET_STATE_INVALID_TRANSITION */
213 UINT
SocketAcquireStateLock( PAFD_FCB FCB
) {
214 NTSTATUS Status
= STATUS_SUCCESS
;
215 PVOID CurrentThread
= KeGetCurrentThread();
217 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
219 AFD_DbgPrint(MAX_TRACE
,("Called on %x, attempting to lock\n", FCB
));
221 /* Wait for the previous user to unlock the FCB state. There might be
222 * multiple waiters waiting to change the state. We need to check each
223 * time we get the event whether somebody still has the state locked */
225 if( !FCB
) return FALSE
;
227 if( CurrentThread
== FCB
->CurrentThread
) {
229 AFD_DbgPrint(MID_TRACE
,
230 ("Same thread, lock count %d\n", FCB
->LockCount
));
233 AFD_DbgPrint(MID_TRACE
,
234 ("Thread %x opposes lock thread %x\n",
235 CurrentThread
, FCB
->CurrentThread
));
239 ExAcquireFastMutex( &FCB
->Mutex
);
241 while( FCB
->Locked
) {
243 (MID_TRACE
,("FCB %x is locked, waiting for notification\n",
245 ExReleaseFastMutex( &FCB
->Mutex
);
246 Status
= KeWaitForSingleObject( &FCB
->StateLockedEvent
,
251 ExAcquireFastMutex( &FCB
->Mutex
);
254 FCB
->CurrentThread
= CurrentThread
;
256 ExReleaseFastMutex( &FCB
->Mutex
);
258 AFD_DbgPrint(MAX_TRACE
,("Got lock (%d).\n", FCB
->LockCount
));
263 VOID
SocketStateUnlock( PAFD_FCB FCB
) {
265 PVOID CurrentThread
= KeGetCurrentThread();
267 ASSERT(FCB
->LockCount
> 0);
268 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
270 ExAcquireFastMutex( &FCB
->Mutex
);
273 if( !FCB
->LockCount
) {
274 FCB
->CurrentThread
= NULL
;
277 AFD_DbgPrint(MAX_TRACE
,("Unlocked.\n"));
278 KePulseEvent( &FCB
->StateLockedEvent
, IO_NETWORK_INCREMENT
, FALSE
);
280 AFD_DbgPrint(MAX_TRACE
,("New lock count: %d (Thr: %x)\n",
281 FCB
->LockCount
, CurrentThread
));
283 ExReleaseFastMutex( &FCB
->Mutex
);
286 NTSTATUS NTAPI UnlockAndMaybeComplete
287 ( PAFD_FCB FCB
, NTSTATUS Status
, PIRP Irp
,
289 PIO_COMPLETION_ROUTINE Completion
) {
291 Irp
->IoStatus
.Status
= Status
;
292 Irp
->IoStatus
.Information
= Information
;
294 if( Status
== STATUS_PENDING
) {
295 /* We should firstly mark this IRP as pending, because
296 otherwise it may be completed by StreamSocketConnectComplete()
297 before we return from SocketStateUnlock(). */
298 IoMarkIrpPending( Irp
);
299 SocketStateUnlock( FCB
);
301 if ( Irp
->MdlAddress
) UnlockRequest( Irp
, IoGetCurrentIrpStackLocation( Irp
) );
302 SocketStateUnlock( FCB
);
304 Completion( FCB
->DeviceExt
->DeviceObject
, Irp
, FCB
);
305 IoCompleteRequest( Irp
, IO_NETWORK_INCREMENT
);
311 NTSTATUS
LostSocket( PIRP Irp
) {
312 NTSTATUS Status
= STATUS_FILE_CLOSED
;
313 AFD_DbgPrint(MIN_TRACE
,("Called.\n"));
314 Irp
->IoStatus
.Information
= 0;
315 Irp
->IoStatus
.Status
= Status
;
316 if ( Irp
->MdlAddress
) UnlockRequest( Irp
, IoGetCurrentIrpStackLocation( Irp
) );
317 IoCompleteRequest( Irp
, IO_NO_INCREMENT
);
321 NTSTATUS
LeaveIrpUntilLater( PAFD_FCB FCB
, PIRP Irp
, UINT Function
) {
322 InsertTailList( &FCB
->PendingIrpList
[Function
],
323 &Irp
->Tail
.Overlay
.ListEntry
);
324 return UnlockAndMaybeComplete( FCB
, STATUS_PENDING
, Irp
, 0, NULL
);
327 VOID
SocketCalloutEnter( PAFD_FCB FCB
) {
329 FCB
->Critical
= TRUE
;
330 SocketStateUnlock( FCB
);
333 VOID
SocketCalloutLeave( PAFD_FCB FCB
) {
334 FCB
->Critical
= FALSE
;
335 SocketAcquireStateLock( FCB
);