- Get afd to build.
[reactos.git] / reactos / drivers / net / afd / afd / lock.c
1 /* $Id$
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 #include "afd.h"
11 #include "tdi_proto.h"
12 #include "tdiconn.h"
13 #include "debug.h"
14 #include "pseh/pseh.h"
15
16 /* Lock a method_neither request so it'll be available from DISPATCH_LEVEL */
17 PVOID LockRequest( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
18 Irp->MdlAddress =
19 IoAllocateMdl( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
20 IrpSp->Parameters.DeviceIoControl.InputBufferLength,
21 FALSE,
22 FALSE,
23 NULL );
24 if( Irp->MdlAddress ) {
25 MmProbeAndLockPages( Irp->MdlAddress, KernelMode, IoModifyAccess );
26 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
27 MmMapLockedPages( Irp->MdlAddress, KernelMode );
28 return IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
29 } else return NULL;
30 }
31
32 VOID UnlockRequest( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
33 MmUnmapLockedPages( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
34 Irp->MdlAddress );
35 MmUnlockPages( Irp->MdlAddress );
36 IoFreeMdl( Irp->MdlAddress );
37 Irp->MdlAddress = NULL;
38 }
39
40 /* Note: We add an extra buffer if LockAddress is true. This allows us to
41 * treat the address buffer as an ordinary client buffer. It's only used
42 * for datagrams. */
43
44 PAFD_WSABUF LockBuffers( PAFD_WSABUF Buf, UINT Count,
45 PVOID AddressBuf, PINT AddressLen,
46 BOOLEAN Write, BOOLEAN LockAddress ) {
47 UINT i;
48 /* Copy the buffer array so we don't lose it */
49 UINT Lock = LockAddress ? 2 : 0;
50 UINT Size = sizeof(AFD_WSABUF) * (Count + Lock);
51 PAFD_WSABUF NewBuf = ExAllocatePool( PagedPool, Size * 2 );
52 PMDL NewMdl;
53
54 AFD_DbgPrint(MID_TRACE,("Called\n"));
55
56 if( NewBuf ) {
57 PAFD_MAPBUF MapBuf = (PAFD_MAPBUF)(NewBuf + Count + Lock);
58
59 _SEH_TRY {
60 RtlCopyMemory( NewBuf, Buf, sizeof(AFD_WSABUF) * Count );
61 if( LockAddress ) {
62 NewBuf[Count].buf = AddressBuf;
63 NewBuf[Count].len = *AddressLen;
64 Count++;
65 NewBuf[Count].buf = (PVOID)AddressLen;
66 NewBuf[Count].len = sizeof(*AddressLen);
67 Count++;
68 }
69 } _SEH_HANDLE {
70 AFD_DbgPrint(MIN_TRACE,("Access violation copying buffer info "
71 "from userland (%x %x)\n",
72 Buf, AddressLen));
73 ExFreePool( NewBuf );
74 return NULL;
75 } _SEH_END;
76
77 for( i = 0; i < Count; i++ ) {
78 AFD_DbgPrint(MID_TRACE,("Locking buffer %d (%x:%d)\n",
79 i, NewBuf[i].buf, NewBuf[i].len));
80
81 if( NewBuf[i].len ) {
82 NewMdl = IoAllocateMdl( NewBuf[i].buf,
83 NewBuf[i].len,
84 FALSE,
85 FALSE,
86 NULL );
87 } else {
88 MapBuf[i].Mdl = NULL;
89 continue;
90 }
91
92 AFD_DbgPrint(MID_TRACE,("NewMdl @ %x\n", NewMdl));
93
94 MapBuf[i].Mdl = NewMdl;
95
96 if( MapBuf[i].Mdl ) {
97 AFD_DbgPrint(MID_TRACE,("Probe and lock pages\n"));
98 MmProbeAndLockPages( MapBuf[i].Mdl, KernelMode,
99 Write ? IoModifyAccess : IoReadAccess );
100 AFD_DbgPrint(MID_TRACE,("MmProbeAndLock finished\n"));
101 }
102 }
103 }
104
105 AFD_DbgPrint(MID_TRACE,("Leaving %x\n", NewBuf));
106
107 return NewBuf;
108 }
109
110 VOID UnlockBuffers( PAFD_WSABUF Buf, UINT Count, BOOL Address ) {
111 UINT Lock = Address ? 2 : 0;
112 PAFD_MAPBUF Map = (PAFD_MAPBUF)(Buf + Count + Lock);
113 UINT i;
114
115 for( i = 0; i < Count + Lock; i++ ) {
116 if( Map[i].Mdl ) {
117 MmUnlockPages( Map[i].Mdl );
118 IoFreeMdl( Map[i].Mdl );
119 }
120 }
121
122 ExFreePool( Buf );
123 }
124
125 /* Produce a kernel-land handle array with handles replaced by object
126 * pointers. This will allow the system to do proper alerting */
127 PAFD_HANDLE LockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) {
128 UINT i;
129 NTSTATUS Status;
130
131 PAFD_HANDLE FileObjects = ExAllocatePool
132 ( NonPagedPool, HandleCount * sizeof(AFD_HANDLE) );
133
134 for( i = 0; FileObjects && i < HandleCount; i++ ) {
135 HandleArray[i].Status = 0;
136 HandleArray[i].Events = HandleArray[i].Events;
137 FileObjects[i].Handle = 0;
138 Status = ObReferenceObjectByHandle
139 ( (PVOID)HandleArray[i].Handle,
140 FILE_ALL_ACCESS,
141 NULL,
142 KernelMode,
143 (PVOID*)&FileObjects[i].Handle,
144 NULL );
145 }
146
147 return FileObjects;
148 }
149
150 VOID UnlockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) {
151 UINT i;
152
153 for( i = 0; i < HandleCount; i++ ) {
154 if( HandleArray[i].Handle )
155 ObDereferenceObject( (PVOID)HandleArray[i].Handle );
156 }
157
158 ExFreePool( HandleArray );
159 }
160
161 /* Returns transitioned state or SOCKET_STATE_INVALID_TRANSITION */
162 UINT SocketAcquireStateLock( PAFD_FCB FCB ) {
163 NTSTATUS Status = STATUS_SUCCESS;
164 PVOID CurrentThread = KeGetCurrentThread();
165
166 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
167
168 AFD_DbgPrint(MAX_TRACE,("Called on %x, attempting to lock\n", FCB));
169
170 /* Wait for the previous user to unlock the FCB state. There might be
171 * multiple waiters waiting to change the state. We need to check each
172 * time we get the event whether somebody still has the state locked */
173
174 if( !FCB ) return FALSE;
175
176 if( CurrentThread == FCB->CurrentThread ) {
177 FCB->LockCount++;
178 AFD_DbgPrint(MID_TRACE,
179 ("Same thread, lock count %d\n", FCB->LockCount));
180 return TRUE;
181 } else {
182 AFD_DbgPrint(MID_TRACE,
183 ("Thread %x opposes lock thread %x\n",
184 CurrentThread, FCB->CurrentThread));
185 }
186
187
188 ExAcquireFastMutex( &FCB->Mutex );
189
190 while( FCB->Locked ) {
191 AFD_DbgPrint
192 (MID_TRACE,("FCB %x is locked, waiting for notification\n",
193 FCB));
194 ExReleaseFastMutex( &FCB->Mutex );
195 Status = KeWaitForSingleObject( &FCB->StateLockedEvent,
196 UserRequest,
197 KernelMode,
198 FALSE,
199 NULL );
200 ExAcquireFastMutex( &FCB->Mutex );
201 }
202 FCB->Locked = TRUE;
203 FCB->CurrentThread = CurrentThread;
204 FCB->LockCount++;
205 ExReleaseFastMutex( &FCB->Mutex );
206
207 AFD_DbgPrint(MAX_TRACE,("Got lock (%d).\n", FCB->LockCount));
208
209 return TRUE;
210 }
211
212 VOID SocketStateUnlock( PAFD_FCB FCB ) {
213 #ifdef DBG
214 PVOID CurrentThread = KeGetCurrentThread();
215 #endif
216 ASSERT(FCB->LockCount > 0);
217 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
218
219 ExAcquireFastMutex( &FCB->Mutex );
220 FCB->LockCount--;
221
222 if( !FCB->LockCount ) {
223 FCB->CurrentThread = NULL;
224 FCB->Locked = FALSE;
225
226 AFD_DbgPrint(MAX_TRACE,("Unlocked.\n"));
227 KePulseEvent( &FCB->StateLockedEvent, IO_NETWORK_INCREMENT, FALSE );
228 } else {
229 AFD_DbgPrint(MAX_TRACE,("New lock count: %d (Thr: %x)\n",
230 FCB->LockCount, CurrentThread));
231 }
232 ExReleaseFastMutex( &FCB->Mutex );
233 }
234
235 NTSTATUS NTAPI UnlockAndMaybeComplete
236 ( PAFD_FCB FCB, NTSTATUS Status, PIRP Irp,
237 UINT Information,
238 PIO_COMPLETION_ROUTINE Completion,
239 BOOL ShouldUnlock ) {
240 SocketStateUnlock( FCB );
241 if( Status == STATUS_PENDING ) {
242 IoMarkIrpPending( Irp );
243 } else {
244 Irp->IoStatus.Status = Status;
245 Irp->IoStatus.Information = Information;
246 if( Completion )
247 Completion( FCB->DeviceExt->DeviceObject, Irp, FCB );
248 if( ShouldUnlock )
249 UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
250 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
251 }
252 return Status;
253 }
254
255
256 NTSTATUS LostSocket( PIRP Irp, BOOL ShouldUnlockIrp ) {
257 NTSTATUS Status = STATUS_INVALID_PARAMETER;
258 AFD_DbgPrint(MIN_TRACE,("Called.\n"));
259 Irp->IoStatus.Information = 0;
260 Irp->IoStatus.Status = Status;
261 if( ShouldUnlockIrp )
262 UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
263 IoCompleteRequest( Irp, IO_NO_INCREMENT );
264 return Status;
265 }
266
267 NTSTATUS LeaveIrpUntilLater( PAFD_FCB FCB, PIRP Irp, UINT Function ) {
268 InsertTailList( &FCB->PendingIrpList[Function],
269 &Irp->Tail.Overlay.ListEntry );
270 return UnlockAndMaybeComplete( FCB, STATUS_PENDING, Irp, 0, NULL, FALSE );
271 }
272
273 VOID SocketCalloutEnter( PAFD_FCB FCB ) {
274 ASSERT(FCB->Locked);
275 FCB->Critical = TRUE;
276 SocketStateUnlock( FCB );
277 }
278
279 VOID SocketCalloutLeave( PAFD_FCB FCB ) {
280 FCB->Critical = FALSE;
281 SocketAcquireStateLock( FCB );
282 }