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 
31 FxRequestBuffer::FxRequestBuffer(
32     VOID
33     )
34 {
35     DataType = FxRequestBufferUnspecified;
36     RtlZeroMemory(&u, sizeof(u));
37 }
38 
39 NTSTATUS
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
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
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
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