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