1use core::ffi::c_void;
4use core::ptr::NonNull;
5
6use super::error::{status, NtStatus};
7use super::memory::MdlRaw;
8
9#[repr(u8)]
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum IrpMajorFunction {
13 Create = 0x00,
14 CreateNamedPipe = 0x01,
15 Close = 0x02,
16 Read = 0x03,
17 Write = 0x04,
18 QueryInformation = 0x05,
19 SetInformation = 0x06,
20 QueryEa = 0x07,
21 SetEa = 0x08,
22 FlushBuffers = 0x09,
23 QueryVolumeInformation = 0x0a,
24 SetVolumeInformation = 0x0b,
25 DirectoryControl = 0x0c,
26 FileSystemControl = 0x0d,
27 DeviceControl = 0x0e,
28 InternalDeviceControl = 0x0f,
29 Shutdown = 0x10,
30 LockControl = 0x11,
31 Cleanup = 0x12,
32 CreateMailslot = 0x13,
33 QuerySecurity = 0x14,
34 SetSecurity = 0x15,
35 Power = 0x16,
36 SystemControl = 0x17,
37 DeviceChange = 0x18,
38 QueryQuota = 0x19,
39 SetQuota = 0x1a,
40 Pnp = 0x1b,
41}
42
43#[repr(C)]
45pub struct IrpRaw {
46 pub type_: i16,
47 pub size: u16,
48 pub mdl_address: *mut MdlRaw,
49 pub flags: u32,
50 pub associated_irp: IrpAssociatedUnion,
51 pub thread_list_entry: [*mut c_void; 2],
52 pub io_status: IoStatusBlock,
53 pub requestor_mode: i8,
54 pub pending_returned: u8,
55 pub stack_count: i8,
56 pub current_location: i8,
57 pub cancel: u8,
58 pub cancel_irql: u8,
59 pub apc_environment: i8,
60 pub allocation_flags: u8,
61 pub user_iosb: *mut IoStatusBlock,
62 pub user_event: *mut c_void,
63 pub overlay: IrpOverlay,
64 pub cancel_routine: *mut c_void,
65 pub user_buffer: *mut c_void,
66 pub tail: IrpTail,
67}
68
69#[repr(C)]
71pub union IrpAssociatedUnion {
72 pub master_irp: *mut IrpRaw,
73 pub irp_count: i32,
74 pub system_buffer: *mut c_void,
75}
76
77#[repr(C)]
79pub union IrpOverlay {
80 pub async_parameters: AsyncParameters,
81 pub allocation_size: u64,
82}
83
84#[repr(C)]
85#[derive(Clone, Copy)]
86pub struct AsyncParameters {
87 pub user_apc_routine: *mut c_void,
88 pub user_apc_context: *mut c_void,
89}
90
91#[repr(C)]
93pub union IrpTail {
94 pub overlay: TailOverlay,
95 pub apc: [u8; 88],
96 pub completion_key: *mut c_void,
97}
98
99#[repr(C)]
100#[derive(Clone, Copy)]
101pub struct TailOverlay {
102 pub driver_context: [*mut c_void; 4],
103 pub thread: *mut c_void,
104 pub auxiliary_buffer: *mut c_void,
105 pub list_entry: [*mut c_void; 2],
106 pub current_stack_location: *mut IoStackLocation,
107 pub original_file_object: *mut c_void,
108}
109
110#[repr(C)]
112#[derive(Debug, Clone, Copy)]
113pub struct IoStatusBlock {
114 pub status: NtStatus,
115 pub information: usize,
116}
117
118impl Default for IoStatusBlock {
119 fn default() -> Self {
120 Self {
121 status: status::STATUS_SUCCESS,
122 information: 0,
123 }
124 }
125}
126
127#[repr(C)]
129pub struct IoStackLocation {
130 pub major_function: u8,
131 pub minor_function: u8,
132 pub flags: u8,
133 pub control: u8,
134 pub parameters: IoStackParameters,
135 pub device_object: *mut c_void,
136 pub file_object: *mut c_void,
137 pub completion_routine: *mut c_void,
138 pub context: *mut c_void,
139}
140
141#[repr(C)]
143pub union IoStackParameters {
144 pub create: CreateParameters,
145 pub read: ReadWriteParameters,
146 pub write: ReadWriteParameters,
147 pub device_io_control: DeviceIoControlParameters,
148 pub others: OtherParameters,
149}
150
151#[repr(C)]
152#[derive(Clone, Copy)]
153pub struct CreateParameters {
154 pub security_context: *mut c_void,
155 pub options: u32,
156 pub file_attributes: u16,
157 pub share_access: u16,
158 pub ea_length: u32,
159}
160
161#[repr(C)]
162#[derive(Clone, Copy)]
163pub struct ReadWriteParameters {
164 pub length: u32,
165 pub key: u32,
166 pub byte_offset: u64,
167}
168
169#[repr(C)]
170#[derive(Clone, Copy)]
171pub struct DeviceIoControlParameters {
172 pub output_buffer_length: u32,
173 pub input_buffer_length: u32,
174 pub io_control_code: u32,
175 pub type3_input_buffer: *mut c_void,
176}
177
178#[repr(C)]
179#[derive(Clone, Copy)]
180pub struct OtherParameters {
181 pub argument1: *mut c_void,
182 pub argument2: *mut c_void,
183 pub argument3: *mut c_void,
184 pub argument4: *mut c_void,
185}
186
187pub struct Irp {
189 raw: NonNull<IrpRaw>,
190}
191
192impl Irp {
193 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
198 NonNull::new(ptr as *mut IrpRaw).map(|raw| Self { raw })
199 }
200
201 pub fn as_raw(&self) -> *mut IrpRaw {
203 self.raw.as_ptr()
204 }
205
206 pub fn current_stack_location(&self) -> Option<&IoStackLocation> {
208 unsafe {
210 let tail = &(*self.raw.as_ptr()).tail;
211 let overlay = &tail.overlay;
212 let stack = overlay.current_stack_location;
213 if stack.is_null() {
214 None
215 } else {
216 Some(&*stack)
217 }
218 }
219 }
220
221 pub fn current_stack_location_mut(&mut self) -> Option<&mut IoStackLocation> {
223 unsafe {
225 let tail = &mut (*self.raw.as_ptr()).tail;
226 let overlay = &mut tail.overlay;
227 let stack = overlay.current_stack_location;
228 if stack.is_null() {
229 None
230 } else {
231 Some(&mut *stack)
232 }
233 }
234 }
235
236 pub fn major_function(&self) -> Option<IrpMajorFunction> {
238 self.current_stack_location().map(|stack| {
239 unsafe { core::mem::transmute(stack.major_function) }
241 })
242 }
243
244 pub fn minor_function(&self) -> Option<u8> {
246 self.current_stack_location().map(|stack| stack.minor_function)
247 }
248
249 pub fn system_buffer(&self) -> *mut c_void {
251 unsafe { (*self.raw.as_ptr()).associated_irp.system_buffer }
253 }
254
255 pub fn user_buffer(&self) -> *mut c_void {
257 unsafe { (*self.raw.as_ptr()).user_buffer }
259 }
260
261 pub fn mdl_address(&self) -> *mut MdlRaw {
263 unsafe { (*self.raw.as_ptr()).mdl_address }
265 }
266
267 pub fn ioctl_parameters(&self) -> Option<DeviceIoControlParameters> {
269 self.current_stack_location().map(|stack| {
270 unsafe { stack.parameters.device_io_control }
272 })
273 }
274
275 pub fn ioctl_code(&self) -> Option<u32> {
277 self.ioctl_parameters().map(|p| p.io_control_code)
278 }
279
280 pub fn input_buffer_length(&self) -> Option<u32> {
282 self.ioctl_parameters().map(|p| p.input_buffer_length)
283 }
284
285 pub fn output_buffer_length(&self) -> Option<u32> {
287 self.ioctl_parameters().map(|p| p.output_buffer_length)
288 }
289
290 pub fn rw_parameters(&self) -> Option<ReadWriteParameters> {
292 self.current_stack_location().map(|stack| {
293 unsafe { stack.parameters.read }
295 })
296 }
297
298 pub fn rw_length(&self) -> Option<u32> {
300 self.rw_parameters().map(|p| p.length)
301 }
302
303 pub fn rw_offset(&self) -> Option<u64> {
305 self.rw_parameters().map(|p| p.byte_offset)
306 }
307
308 pub fn set_status(&mut self, status: NtStatus, information: usize) {
310 unsafe {
312 (*self.raw.as_ptr()).io_status.status = status;
313 (*self.raw.as_ptr()).io_status.information = information;
314 }
315 }
316
317 pub fn io_status(&self) -> IoStatusBlock {
319 unsafe { (*self.raw.as_ptr()).io_status }
321 }
322
323 pub fn complete(&mut self, status: NtStatus) {
325 self.complete_with_info(status, 0);
326 }
327
328 pub fn complete_with_info(&mut self, status: NtStatus, information: usize) {
330 self.set_status(status, information);
331 unsafe {
333 IofCompleteRequest(self.raw.as_ptr() as *mut c_void, 0); }
335 }
336
337 pub fn complete_with_boost(&mut self, status: NtStatus, information: usize, boost: i8) {
339 self.set_status(status, information);
340 unsafe {
342 IofCompleteRequest(self.raw.as_ptr() as *mut c_void, boost);
343 }
344 }
345
346 pub fn mark_pending(&mut self) {
348 unsafe {
350 IoMarkIrpPending(self.raw.as_ptr() as *mut c_void);
351 }
352 }
353
354 pub fn input_buffer<T>(&self) -> Option<&T> {
356 let buffer = self.system_buffer();
357 let len = self.input_buffer_length()?;
358
359 if buffer.is_null() || (len as usize) < core::mem::size_of::<T>() {
360 return None;
361 }
362
363 Some(unsafe { &*(buffer as *const T) })
365 }
366
367 pub fn output_buffer_mut<T>(&mut self) -> Option<&mut T> {
369 let buffer = self.system_buffer();
370 let len = self.output_buffer_length()?;
371
372 if buffer.is_null() || (len as usize) < core::mem::size_of::<T>() {
373 return None;
374 }
375
376 Some(unsafe { &mut *(buffer as *mut T) })
378 }
379
380 pub fn input_bytes(&self) -> Option<&[u8]> {
382 let buffer = self.system_buffer();
383 let len = self.input_buffer_length()?;
384
385 if buffer.is_null() || len == 0 {
386 return None;
387 }
388
389 Some(unsafe { core::slice::from_raw_parts(buffer as *const u8, len as usize) })
391 }
392
393 pub fn output_bytes_mut(&mut self) -> Option<&mut [u8]> {
395 let buffer = self.system_buffer();
396 let len = self.output_buffer_length()?;
397
398 if buffer.is_null() || len == 0 {
399 return None;
400 }
401
402 Some(unsafe { core::slice::from_raw_parts_mut(buffer as *mut u8, len as usize) })
404 }
405}
406
407extern "system" {
409 fn IofCompleteRequest(Irp: *mut c_void, PriorityBoost: i8);
410 fn IoMarkIrpPending(Irp: *mut c_void);
411}