Sync with trunk (r47116), hopefully without breaking anything.
[reactos.git] / drivers / network / 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/pseh2.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 BOOLEAN LockFailed = FALSE;
19
20 ASSERT(IrpSp->Parameters.DeviceIoControl.Type3InputBuffer);
21 ASSERT(IrpSp->Parameters.DeviceIoControl.InputBufferLength);
22 ASSERT(!Irp->MdlAddress);
23
24 Irp->MdlAddress =
25 IoAllocateMdl( IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
26 IrpSp->Parameters.DeviceIoControl.InputBufferLength,
27 FALSE,
28 FALSE,
29 NULL );
30 if( Irp->MdlAddress ) {
31 _SEH2_TRY {
32 MmProbeAndLockPages( Irp->MdlAddress, Irp->RequestorMode, IoModifyAccess );
33 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
34 LockFailed = TRUE;
35 } _SEH2_END;
36
37 if( LockFailed ) {
38 IoFreeMdl( Irp->MdlAddress );
39 Irp->MdlAddress = NULL;
40 return NULL;
41 }
42
43 IrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
44 MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
45
46 if( !IrpSp->Parameters.DeviceIoControl.Type3InputBuffer ) {
47 MmUnlockPages( Irp->MdlAddress );
48 IoFreeMdl( Irp->MdlAddress );
49 Irp->MdlAddress = NULL;
50 return NULL;
51 }
52
53 return IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
54 } else return NULL;
55 }
56
57 VOID UnlockRequest( PIRP Irp, PIO_STACK_LOCATION IrpSp )
58 {
59 MmUnlockPages( Irp->MdlAddress );
60 IoFreeMdl( Irp->MdlAddress );
61 Irp->MdlAddress = NULL;
62 }
63
64 /* Note: We add an extra buffer if LockAddress is true. This allows us to
65 * treat the address buffer as an ordinary client buffer. It's only used
66 * for datagrams. */
67
68 PAFD_WSABUF LockBuffers( PAFD_WSABUF Buf, UINT Count,
69 PVOID AddressBuf, PINT AddressLen,
70 BOOLEAN Write, BOOLEAN LockAddress ) {
71 UINT i;
72 /* Copy the buffer array so we don't lose it */
73 UINT Lock = LockAddress ? 2 : 0;
74 UINT Size = sizeof(AFD_WSABUF) * (Count + Lock);
75 PAFD_WSABUF NewBuf = ExAllocatePool( PagedPool, Size * 2 );
76 BOOLEAN LockFailed = FALSE;
77 PAFD_MAPBUF MapBuf;
78
79 AFD_DbgPrint(MID_TRACE,("Called(%08x)\n", NewBuf));
80
81 if( NewBuf ) {
82 RtlZeroMemory(NewBuf, Size * 2);
83
84 MapBuf = (PAFD_MAPBUF)(NewBuf + Count + Lock);
85
86 _SEH2_TRY {
87 RtlCopyMemory( NewBuf, Buf, sizeof(AFD_WSABUF) * Count );
88 if( LockAddress ) {
89 if (AddressBuf && AddressLen) {
90 NewBuf[Count].buf = AddressBuf;
91 NewBuf[Count].len = *AddressLen;
92 NewBuf[Count + 1].buf = (PVOID)AddressLen;
93 NewBuf[Count + 1].len = sizeof(*AddressLen);
94 }
95 Count += 2;
96 }
97 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
98 AFD_DbgPrint(MIN_TRACE,("Access violation copying buffer info "
99 "from userland (%x %x)\n",
100 Buf, AddressLen));
101 ExFreePool( NewBuf );
102 _SEH2_YIELD(return NULL);
103 } _SEH2_END;
104
105 for( i = 0; i < Count; i++ ) {
106 AFD_DbgPrint(MID_TRACE,("Locking buffer %d (%x:%d)\n",
107 i, NewBuf[i].buf, NewBuf[i].len));
108
109 if( NewBuf[i].buf && NewBuf[i].len ) {
110 MapBuf[i].Mdl = IoAllocateMdl( NewBuf[i].buf,
111 NewBuf[i].len,
112 FALSE,
113 FALSE,
114 NULL );
115 } else {
116 MapBuf[i].Mdl = NULL;
117 continue;
118 }
119
120 AFD_DbgPrint(MID_TRACE,("NewMdl @ %x\n", MapBuf[i].Mdl));
121
122 if( MapBuf[i].Mdl ) {
123 AFD_DbgPrint(MID_TRACE,("Probe and lock pages\n"));
124 _SEH2_TRY {
125 MmProbeAndLockPages( MapBuf[i].Mdl, KernelMode,
126 Write ? IoModifyAccess : IoReadAccess );
127 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
128 LockFailed = TRUE;
129 } _SEH2_END;
130 AFD_DbgPrint(MID_TRACE,("MmProbeAndLock finished\n"));
131
132 if( LockFailed ) {
133 IoFreeMdl( MapBuf[i].Mdl );
134 MapBuf[i].Mdl = NULL;
135 ExFreePool( NewBuf );
136 return NULL;
137 }
138 } else {
139 ExFreePool( NewBuf );
140 return NULL;
141 }
142 }
143 }
144
145 AFD_DbgPrint(MID_TRACE,("Leaving %x\n", NewBuf));
146
147 return NewBuf;
148 }
149
150 VOID UnlockBuffers( PAFD_WSABUF Buf, UINT Count, BOOL Address ) {
151 UINT Lock = Address ? 2 : 0;
152 PAFD_MAPBUF Map = (PAFD_MAPBUF)(Buf + Count + Lock);
153 UINT i;
154
155 if( !Buf ) return;
156
157 for( i = 0; i < Count + Lock; i++ ) {
158 if( Map[i].Mdl ) {
159 MmUnlockPages( Map[i].Mdl );
160 IoFreeMdl( Map[i].Mdl );
161 Map[i].Mdl = NULL;
162 }
163 }
164
165 ExFreePool( Buf );
166 Buf = NULL;
167 }
168
169 /* Produce a kernel-land handle array with handles replaced by object
170 * pointers. This will allow the system to do proper alerting */
171 PAFD_HANDLE LockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) {
172 UINT i;
173 NTSTATUS Status = STATUS_SUCCESS;
174
175 PAFD_HANDLE FileObjects = ExAllocatePool
176 ( NonPagedPool, HandleCount * sizeof(AFD_HANDLE) );
177
178 for( i = 0; FileObjects && i < HandleCount; i++ ) {
179 FileObjects[i].Status = 0;
180 FileObjects[i].Events = HandleArray[i].Events;
181 FileObjects[i].Handle = 0;
182 if( !HandleArray[i].Handle ) continue;
183 if( NT_SUCCESS(Status) ) {
184 Status = ObReferenceObjectByHandle
185 ( (PVOID)HandleArray[i].Handle,
186 FILE_ALL_ACCESS,
187 NULL,
188 KernelMode,
189 (PVOID*)&FileObjects[i].Handle,
190 NULL );
191 }
192
193 if( !NT_SUCCESS(Status) )
194 FileObjects[i].Handle = 0;
195 }
196
197 if( !NT_SUCCESS(Status) ) {
198 UnlockHandles( FileObjects, HandleCount );
199 return NULL;
200 }
201
202 return FileObjects;
203 }
204
205 VOID UnlockHandles( PAFD_HANDLE HandleArray, UINT HandleCount ) {
206 UINT i;
207
208 for( i = 0; i < HandleCount; i++ ) {
209 if( HandleArray[i].Handle )
210 ObDereferenceObject( (PVOID)HandleArray[i].Handle );
211 }
212
213 ExFreePool( HandleArray );
214 HandleArray = NULL;
215 }
216
217 BOOLEAN SocketAcquireStateLock( PAFD_FCB FCB ) {
218 if( !FCB ) return FALSE;
219
220 return !KeWaitForMutexObject(&FCB->Mutex,
221 Executive,
222 KernelMode,
223 FALSE,
224 NULL);
225 }
226
227 VOID SocketStateUnlock( PAFD_FCB FCB ) {
228 KeReleaseMutex(&FCB->Mutex, FALSE);
229 }
230
231 NTSTATUS NTAPI UnlockAndMaybeComplete
232 ( PAFD_FCB FCB, NTSTATUS Status, PIRP Irp,
233 UINT Information ) {
234 Irp->IoStatus.Status = Status;
235 Irp->IoStatus.Information = Information;
236 if ( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
237 (void)IoSetCancelRoutine(Irp, NULL);
238 SocketStateUnlock( FCB );
239 IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
240 return Status;
241 }
242
243
244 NTSTATUS LostSocket( PIRP Irp ) {
245 NTSTATUS Status = STATUS_FILE_CLOSED;
246 AFD_DbgPrint(MIN_TRACE,("Called.\n"));
247 Irp->IoStatus.Information = 0;
248 Irp->IoStatus.Status = Status;
249 if ( Irp->MdlAddress ) UnlockRequest( Irp, IoGetCurrentIrpStackLocation( Irp ) );
250 IoCompleteRequest( Irp, IO_NO_INCREMENT );
251 return Status;
252 }
253
254 NTSTATUS LeaveIrpUntilLater( PAFD_FCB FCB, PIRP Irp, UINT Function ) {
255 InsertTailList( &FCB->PendingIrpList[Function],
256 &Irp->Tail.Overlay.ListEntry );
257 IoMarkIrpPending(Irp);
258 (void)IoSetCancelRoutine(Irp, AfdCancelHandler);
259 SocketStateUnlock( FCB );
260 return STATUS_PENDING;
261 }