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