1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 FxRequestBuffer.cpp
8
9 Abstract:
10
11 This module implements a memory union object
12
13 Author:
14
15
16
17 Environment:
18
19 Both kernel and user mode
20
21 Revision History:
22
23 --*/
24
25 #include "fxsupportpch.hpp"
26
27 extern "C" {
28 // #include "FxRequestBuffer.tmh"
29 }
30
FxRequestBuffer(VOID)31 FxRequestBuffer::FxRequestBuffer(
32 VOID
33 )
34 {
35 DataType = FxRequestBufferUnspecified;
36 RtlZeroMemory(&u, sizeof(u));
37 }
38
39 NTSTATUS
ValidateMemoryDescriptor(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PWDF_MEMORY_DESCRIPTOR Descriptor,__in ULONG Flags)40 FxRequestBuffer::ValidateMemoryDescriptor(
41 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
42 __in PWDF_MEMORY_DESCRIPTOR Descriptor,
43 __in ULONG Flags
44 )
45 {
46 IFxMemory* pMemory;
47 NTSTATUS status;
48
49 if (Descriptor == NULL) {
50 if (Flags & MemoryDescriptorNullAllowed) {
51 return STATUS_SUCCESS;
52 }
53 else {
54 DoTraceLevelMessage(
55 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
56 "A NULL Descriptor is not allowed");
57
58 return STATUS_INVALID_PARAMETER;
59 }
60 }
61
62 //
63 // For each type, check to see if the buffer is non NULL and err out if the
64 // calller considers this an error. If the buffer is NULL, but a length
65 // was specified, this is considered an error.
66 //
67 switch (Descriptor->Type) {
68 case WdfMemoryDescriptorTypeBuffer:
69 if (Descriptor->u.BufferType.Buffer == NULL) {
70 if ((Flags & MemoryDescriptorNoBufferAllowed) == 0) {
71 DoTraceLevelMessage(
72 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
73 "A NULL Buffer is not allowed");
74
75 return STATUS_INVALID_PARAMETER;
76 }
77 else if (Descriptor->u.BufferType.Length != 0) {
78 DoTraceLevelMessage(
79 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
80 "Buffer is NULL, but a length (0x%x) is specified",
81 Descriptor->u.BufferType.Length);
82
83 return STATUS_INVALID_PARAMETER;
84 }
85 }
86
87 SetBuffer(Descriptor->u.BufferType.Buffer,
88 Descriptor->u.BufferType.Length);
89
90 status = STATUS_SUCCESS;
91 break;
92
93 case WdfMemoryDescriptorTypeMdl:
94 if (Descriptor->u.MdlType.Mdl == NULL) {
95 if ((Flags & MemoryDescriptorNoBufferAllowed) == 0) {
96 DoTraceLevelMessage(
97 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
98 "A NULL MDL is not allowed");
99
100 return STATUS_INVALID_PARAMETER;
101 }
102 else if (Descriptor->u.MdlType.BufferLength != 0) {
103 DoTraceLevelMessage(
104 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
105 "MDL is NULL, but a length (0x%x) is specified",
106 Descriptor->u.MdlType.BufferLength);
107
108 return STATUS_INVALID_PARAMETER;
109 }
110 }
111
112 SetMdl(Descriptor->u.MdlType.Mdl, Descriptor->u.MdlType.BufferLength);
113 status = STATUS_SUCCESS;
114 break;
115
116 case WdfMemoryDescriptorTypeHandle:
117 pMemory = NULL;
118 if (Descriptor->u.HandleType.Memory == NULL) {
119 if (Flags & MemoryDescriptorNoBufferAllowed) {
120 status = STATUS_SUCCESS;
121 }
122 else {
123 DoTraceLevelMessage(
124 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
125 "A NULL WDFMEMORY handle is not allowed");
126
127 status = STATUS_INVALID_PARAMETER;
128 }
129 }
130 else {
131 FxObjectHandleGetPtr(FxDriverGlobals,
132 Descriptor->u.HandleType.Memory,
133 IFX_TYPE_MEMORY,
134 (PVOID*) &pMemory);
135
136 status = pMemory->ValidateMemoryOffsets(
137 Descriptor->u.HandleType.Offsets);
138 if (!NT_SUCCESS(status)) {
139 DoTraceLevelMessage(
140 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR,
141 "Memory offset values are not valid %!STATUS!", status);
142 }
143 }
144
145 if (NT_SUCCESS(status) && pMemory != NULL) {
146 SetMemory(pMemory, Descriptor->u.HandleType.Offsets);
147 }
148 break;
149
150 default:
151 status = STATUS_INVALID_PARAMETER;
152 }
153
154 return status;
155 }
156
157 ULONG
GetBufferLength(VOID)158 FxRequestBuffer::GetBufferLength(
159 VOID
160 )
161 {
162 switch (DataType) {
163 case FxRequestBufferMemory:
164 //
165 // If the BufferLength and BufferOffset is zero, then the transfer length is same
166 // as the length of the request.
167 //
168 if (u.Memory.Offsets == NULL ||
169 (u.Memory.Offsets->BufferOffset == 0 && u.Memory.Offsets->BufferLength == 0)) {
170 return (ULONG) u.Memory.Memory->GetBufferSize();
171 }
172 else {
173 //
174 // If the BufferLength value is zero then the transfer length is request length
175 // minus the offset value.
176 //
177 if (u.Memory.Offsets->BufferLength == 0) {
178 return ((ULONG) u.RefMdl.Memory->GetBufferSize() - (ULONG) u.RefMdl.Offsets->BufferOffset);
179 }
180 else {
181 return (ULONG) u.Memory.Offsets->BufferLength;
182 }
183 }
184 break;
185
186 case FxRequestBufferMdl:
187 return u.Mdl.Length;
188
189 case FxRequestBufferReferencedMdl:
190 //
191 // If the BufferLength and BufferOffset is zero, then the transfer length is same
192 // as the length of the request.
193 //
194 if (u.RefMdl.Offsets == NULL ||
195 (u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) {
196 return (ULONG) u.RefMdl.Memory->GetBufferSize();
197 }
198 else {
199 //
200 // If the BufferLength value is zero then the transfer length is request length
201 // minus the offset value.
202 //
203 if (u.RefMdl.Offsets->BufferLength == 0) {
204 return ((ULONG) u.RefMdl.Memory->GetBufferSize() - (ULONG) u.RefMdl.Offsets->BufferOffset);
205 }
206 else {
207 return (ULONG) u.RefMdl.Offsets->BufferLength;
208 }
209 }
210
211 case FxRequestBufferBuffer:
212 return u.Buffer.Length;
213
214 default:
215 return 0;
216 }
217 }
218
219 _Must_inspect_result_
220 NTSTATUS
GetBuffer(__deref_out PVOID * Buffer)221 FxRequestBuffer::GetBuffer(
222 __deref_out PVOID* Buffer
223 )
224 {
225 switch (DataType) {
226 case FxRequestBufferUnspecified:
227 *Buffer = NULL;
228 return STATUS_SUCCESS;
229
230 case FxRequestBufferMemory:
231 if (u.Memory.Offsets != NULL) {
232 *Buffer = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(),
233 u.Memory.Offsets->BufferOffset);
234 }
235 else {
236 *Buffer = u.Memory.Memory->GetBuffer();
237 }
238 return STATUS_SUCCESS;
239
240 case FxRequestBufferBuffer:
241 *Buffer = u.Buffer.Buffer;
242 return STATUS_SUCCESS;
243
244 case FxRequestBufferMdl:
245 *Buffer = Mx::MxGetSystemAddressForMdlSafe(u.Mdl.Mdl, NormalPagePriority);
246 if (*Buffer != NULL) {
247 return STATUS_SUCCESS;
248 }
249 else {
250 return STATUS_INSUFFICIENT_RESOURCES;
251 }
252
253 case FxRequestBufferReferencedMdl:
254 *Buffer = Mx::MxGetSystemAddressForMdlSafe(u.RefMdl.Mdl, NormalPagePriority);
255 if (*Buffer != NULL) {
256 if (u.RefMdl.Offsets != NULL) {
257 *Buffer = WDF_PTR_ADD_OFFSET(*Buffer,
258 u.RefMdl.Offsets->BufferOffset);
259 }
260 return STATUS_SUCCESS;
261 }
262 else {
263 return STATUS_INSUFFICIENT_RESOURCES;
264 }
265
266 default:
267 return STATUS_INVALID_PARAMETER;
268 }
269 }
270
271
272 VOID
AssignValues(__deref_out_opt PVOID * PPBuffer,__deref_out_opt PMDL * PPMdl,__out PULONG BufferLength)273 FxRequestBuffer::AssignValues(
274 __deref_out_opt PVOID* PPBuffer,
275 __deref_out_opt PMDL* PPMdl,
276 __out PULONG BufferLength
277 )
278 {
279 PVOID pBuffer;
280 PMDL pMdl;
281 size_t bufferSize;
282
283 //
284 // Make sure we have valid double pointers, make life simpler below
285 //
286 if (PPBuffer == NULL) {
287 PPBuffer = &pBuffer;
288 }
289 if (PPMdl == NULL) {
290 PPMdl = &pMdl;
291 }
292
293 switch (DataType) {
294 case FxRequestBufferMemory:
295 pBuffer = u.Memory.Memory->GetBuffer();
296 bufferSize = u.Memory.Memory->GetBufferSize();
297
298 if (u.Memory.Offsets != NULL) {
299 if (u.Memory.Offsets->BufferLength > 0) {
300 bufferSize = u.Memory.Offsets->BufferLength;
301 }
302 if (u.Memory.Offsets->BufferOffset > 0) {
303 pBuffer = WDF_PTR_ADD_OFFSET(pBuffer, u.Memory.Offsets->BufferOffset);
304 }
305 }
306
307 *PPBuffer = pBuffer;
308 *BufferLength = (ULONG) bufferSize;
309 break;
310
311 case FxRequestBufferMdl:
312 *PPMdl = u.Mdl.Mdl;
313 *PPBuffer = NULL;
314 *BufferLength = u.Mdl.Length;
315 break;
316
317 case FxRequestBufferBuffer:
318 *PPMdl = NULL;
319 *PPBuffer = u.Buffer.Buffer;
320 *BufferLength = u.Buffer.Length;
321 break;
322
323 case FxRequestBufferReferencedMdl:
324 *PPMdl = u.RefMdl.Mdl;
325 *PPBuffer = NULL;
326 if (u.RefMdl.Offsets != NULL && u.RefMdl.Offsets->BufferLength > 0) {
327 *BufferLength = (ULONG) u.RefMdl.Offsets->BufferLength;
328 }
329 else {
330 *BufferLength = (ULONG) u.RefMdl.Memory->GetBufferSize();
331 }
332 break;
333
334 default:
335 *PPMdl = NULL;
336 *PPBuffer = NULL;
337 *BufferLength = 0;
338 break;
339 }
340 }
341