1 /*++ 2 3 Copyright (C) Microsoft Corporation 2010 4 5 Module Name: 6 7 srblib.c 8 9 Abstract: 10 11 Header for SRB utility functions 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 25 #include "classp.h" 26 27 PVOID 28 DefaultStorageRequestBlockAllocateRoutine( 29 _In_ CLONG ByteSize 30 ) 31 /*++ 32 33 Routine Description: 34 35 Default allocation routine. 36 37 Arguments: 38 39 ByteSize - SRB size in bytes. 40 41 Return Value: 42 43 Pointer to the SRB buffer. NULL if SRB buffer could not be allocated. 44 45 --*/ 46 { 47 return ExAllocatePoolWithTag(NonPagedPoolNx, ByteSize, '+brs'); 48 } 49 50 51 NTSTATUS 52 pInitializeStorageRequestBlock( 53 _Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb, 54 _In_ USHORT AddressType, 55 _In_ ULONG ByteSize, 56 _In_ ULONG NumSrbExData, 57 _In_ va_list ap 58 ) 59 /*++ 60 61 Routine Description: 62 63 Initialize a STORAGE_REQUEST_BLOCK. 64 65 Arguments: 66 67 Srb - Pointer to STORAGE_REQUEST_BLOCK to initialize. 68 69 AddressType - Storage address type. 70 71 ByteSize - STORAGE_REQUEST_BLOCK size in bytes. 72 73 NumSrbExData - Number of SRB extended data. 74 75 ap - Variable argument list matching the SRB extended data in the 76 STORAGE_REQUEST_BLOCK. 77 78 Return Value: 79 80 NTSTATUS 81 82 --*/ 83 { 84 NTSTATUS status = STATUS_SUCCESS; 85 PSTOR_ADDRESS address; 86 PSRBEX_DATA srbExData; 87 ULONG offset; 88 ULONG length = (ULONG)-1; 89 SRBEXDATATYPE type; 90 ULONG srbExDataLength = (ULONG)-1; 91 ULONG varLength; 92 ULONG i; 93 94 if (ByteSize < sizeof(STORAGE_REQUEST_BLOCK)) { 95 return STATUS_BUFFER_OVERFLOW; 96 } 97 98 RtlZeroMemory(Srb, ByteSize); 99 100 Srb->Length = FIELD_OFFSET(STORAGE_REQUEST_BLOCK, Signature); 101 Srb->Function = SRB_FUNCTION_STORAGE_REQUEST_BLOCK; 102 Srb->Signature = SRB_SIGNATURE; 103 Srb->Version = STORAGE_REQUEST_BLOCK_VERSION_1; 104 Srb->SrbLength = ByteSize; 105 Srb->NumSrbExData = NumSrbExData; 106 107 offset = sizeof(STORAGE_REQUEST_BLOCK); 108 if (NumSrbExData > 0) { 109 offset += ((NumSrbExData - 1) * sizeof(ULONG)); 110 111 // Ensure offset is pointer type aligned 112 if (offset % sizeof(PVOID)) { 113 offset += (sizeof(PVOID) - (offset % sizeof(PVOID))); 114 } 115 } 116 Srb->AddressOffset = offset; 117 118 if (AddressType == STORAGE_ADDRESS_TYPE_BTL8) 119 { 120 if ((ByteSize < offset) || 121 (ByteSize < (offset + sizeof(STOR_ADDR_BTL8)))) { 122 return STATUS_BUFFER_OVERFLOW; 123 } 124 address = (PSTOR_ADDRESS)((PUCHAR)Srb + offset); 125 address->Type = STOR_ADDRESS_TYPE_BTL8; 126 address->AddressLength = STOR_ADDR_BTL8_ADDRESS_LENGTH; 127 offset += sizeof(STOR_ADDR_BTL8); 128 } else 129 { 130 status = STATUS_INVALID_PARAMETER; 131 } 132 133 for (i = 0; i < NumSrbExData && status == STATUS_SUCCESS; i++) 134 { 135 if (ByteSize <= offset) { 136 status = STATUS_BUFFER_OVERFLOW; 137 break; 138 } 139 srbExData = (PSRBEX_DATA)((PUCHAR)Srb + offset); 140 Srb->SrbExDataOffset[i] = offset; 141 142 type = va_arg(ap, SRBEXDATATYPE); 143 144 switch (type) 145 { 146 case SrbExDataTypeBidirectional: 147 length = sizeof(SRBEX_DATA_BIDIRECTIONAL); 148 srbExDataLength = SRBEX_DATA_BIDIRECTIONAL_LENGTH; 149 break; 150 case SrbExDataTypeScsiCdb16: 151 length = sizeof(SRBEX_DATA_SCSI_CDB16); 152 srbExDataLength = SRBEX_DATA_SCSI_CDB16_LENGTH; 153 break; 154 case SrbExDataTypeScsiCdb32: 155 length = sizeof(SRBEX_DATA_SCSI_CDB32); 156 srbExDataLength = SRBEX_DATA_SCSI_CDB32_LENGTH; 157 break; 158 case SrbExDataTypeScsiCdbVar: 159 varLength = va_arg(ap, ULONG); 160 length = sizeof(SRBEX_DATA_SCSI_CDB_VAR) + varLength; 161 srbExDataLength = SRBEX_DATA_SCSI_CDB_VAR_LENGTH_MIN + varLength; 162 break; 163 case SrbExDataTypeWmi: 164 length = sizeof(SRBEX_DATA_WMI); 165 srbExDataLength = SRBEX_DATA_WMI_LENGTH; 166 break; 167 case SrbExDataTypePower: 168 length = sizeof(SRBEX_DATA_POWER); 169 srbExDataLength = SRBEX_DATA_POWER_LENGTH; 170 break; 171 case SrbExDataTypePnP: 172 length = sizeof(SRBEX_DATA_PNP); 173 srbExDataLength = SRBEX_DATA_PNP_LENGTH; 174 break; 175 case SrbExDataTypeIoInfo: 176 length = sizeof(SRBEX_DATA_IO_INFO); 177 srbExDataLength = SRBEX_DATA_IO_INFO_LENGTH; 178 break; 179 default: 180 status = STATUS_INVALID_PARAMETER; 181 break; 182 } 183 184 if (status == STATUS_SUCCESS) 185 { 186 NT_ASSERT(length != (ULONG)-1); 187 188 if (ByteSize < (offset + length)) { 189 status = STATUS_BUFFER_OVERFLOW; 190 break; 191 } 192 193 NT_ASSERT(srbExDataLength != (ULONG)-1); 194 195 srbExData->Type = type; 196 srbExData->Length = srbExDataLength; 197 offset += length; 198 } 199 } 200 201 return status; 202 } 203 204 205 NTSTATUS 206 InitializeStorageRequestBlock( 207 _Inout_bytecount_(ByteSize) PSTORAGE_REQUEST_BLOCK Srb, 208 _In_ USHORT AddressType, 209 _In_ ULONG ByteSize, 210 _In_ ULONG NumSrbExData, 211 ... 212 ) 213 /*++ 214 215 Routine Description: 216 217 Initialize an extended SRB. 218 219 Arguments: 220 221 Srb - Pointer to SRB buffer to initialize. 222 223 AddressType - Storage address type. 224 225 ByteSize - STORAGE_REQUEST_BLOCK size in bytes. 226 227 NumSrbExData - Number of SRB extended data. 228 229 ... - Variable argument list matching the SRB extended data in the 230 STORAGE_REQUEST_BLOCK. 231 232 Return Value: 233 234 NTSTATUS 235 236 --*/ 237 { 238 NTSTATUS status; 239 va_list ap; 240 va_start(ap, NumSrbExData); 241 status = pInitializeStorageRequestBlock(Srb, AddressType, ByteSize, NumSrbExData, ap); 242 va_end(ap); 243 return status; 244 } 245 246 247 248 NTSTATUS 249 CreateStorageRequestBlock( 250 _Inout_ PSTORAGE_REQUEST_BLOCK *Srb, 251 _In_ USHORT AddressType, 252 _In_opt_ PSRB_ALLOCATE_ROUTINE AllocateRoutine, 253 _Inout_opt_ ULONG *ByteSize, 254 _In_ ULONG NumSrbExData, 255 ... 256 ) 257 /*++ 258 259 Routine Description: 260 261 Create an extended SRB. 262 263 Arguments: 264 265 Srb - Pointer to buffer to store SRB pointer. 266 267 AddressType - Storage address type. 268 269 AllocateRoutine - Buffer allocation function (optional). 270 271 ByteSize - Pointer to ULONG to store size of SRB in bytes (optional). 272 273 NumSrbExData - Number of SRB extended data. 274 275 ... - Variable argument list matching the SRB extended data in the 276 STORAGE_REQUEST_BLOCK. 277 278 Return Value: 279 280 NTSTATUS 281 282 --*/ 283 { 284 ULONG sizeNeeded = 0; 285 va_list ap; 286 ULONG i; 287 NTSTATUS status = STATUS_SUCCESS; 288 289 // Ensure SrbExData offsets are pointer type aligned 290 sizeNeeded = sizeof(STORAGE_REQUEST_BLOCK); 291 if (NumSrbExData > 0) { 292 sizeNeeded += ((NumSrbExData - 1) * sizeof(ULONG)); 293 if (sizeNeeded % sizeof(PVOID)) { 294 sizeNeeded += (sizeof(PVOID) - (sizeNeeded % sizeof(PVOID))); 295 } 296 } 297 298 if (AddressType == STORAGE_ADDRESS_TYPE_BTL8) 299 { 300 sizeNeeded += sizeof(STOR_ADDR_BTL8); 301 } else 302 { 303 status = STATUS_INVALID_PARAMETER; 304 } 305 306 va_start(ap, NumSrbExData); 307 308 for (i = 0; i < NumSrbExData && status == STATUS_SUCCESS; i++) 309 { 310 switch (va_arg(ap, SRBEXDATATYPE)) 311 { 312 case SrbExDataTypeBidirectional: 313 sizeNeeded += sizeof(SRBEX_DATA_BIDIRECTIONAL); 314 break; 315 case SrbExDataTypeScsiCdb16: 316 sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB16); 317 break; 318 case SrbExDataTypeScsiCdb32: 319 sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB32); 320 break; 321 case SrbExDataTypeScsiCdbVar: 322 sizeNeeded += sizeof(SRBEX_DATA_SCSI_CDB_VAR) + va_arg(ap, ULONG); 323 break; 324 case SrbExDataTypeWmi: 325 sizeNeeded += sizeof(SRBEX_DATA_WMI); 326 break; 327 case SrbExDataTypePower: 328 sizeNeeded += sizeof(SRBEX_DATA_POWER); 329 break; 330 case SrbExDataTypePnP: 331 sizeNeeded += sizeof(SRBEX_DATA_PNP); 332 break; 333 case SrbExDataTypeIoInfo: 334 sizeNeeded += sizeof(SRBEX_DATA_IO_INFO); 335 break; 336 default: 337 status = STATUS_INVALID_PARAMETER; 338 break; 339 } 340 } 341 va_end(ap); 342 343 if (status == STATUS_SUCCESS) 344 { 345 if (AllocateRoutine) 346 { 347 *Srb = AllocateRoutine(sizeNeeded); 348 if (*Srb == NULL) 349 { 350 status = STATUS_INSUFFICIENT_RESOURCES; 351 } 352 } 353 354 if (ByteSize != NULL) 355 { 356 *ByteSize = sizeNeeded; 357 } 358 359 if (*Srb) 360 { 361 va_start(ap, NumSrbExData); 362 #ifdef _MSC_VER 363 #pragma prefast(suppress:26015, "pInitializeStorageRequestBlock will set the SrbLength field") 364 #endif 365 status = pInitializeStorageRequestBlock(*Srb, AddressType, sizeNeeded, NumSrbExData, ap); 366 va_end(ap); 367 } 368 369 } 370 371 return status; 372 } 373 374 375 376 377