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