ndisapi_rs/ndisapi/
fastio_api.rs

1//! # Submodule: Fast I/O operations
2//!
3//! This submodule  offers methods to interact with the NDIS filter driver, allowing users to
4//! initialize the fast I/O mechanism, add a secondary fast I/O shared memory sections, and forward
5//! packets to the driver or to the target network interface or protocol layer. The methods in this
6//! submodule are designed to be highly flexible, allowing for parameterization by the size of the shared
7//! memory section or the number of packets to send. This submodule is part of the larger NDISAPI module,
8//! which provides a high-level API for the Windows Packet Filter on Windows.
9//!
10
11use std::mem::size_of;
12
13use windows::{core::Result, Win32::Foundation::GetLastError, Win32::System::IO::DeviceIoControl};
14
15use super::Ndisapi;
16use crate::driver::*;
17
18impl Ndisapi {
19    /// This function adds a secondary Fast I/O shared memory section to the NDIS filter driver,
20    /// allowing faster communication between user-mode applications and the driver.
21    ///
22    /// # Type Parameters
23    ///
24    /// * `N`: The size of the Fast I/O shared memory section.
25    ///
26    /// # Arguments
27    ///
28    /// * `fast_io_section`: A mutable reference to a `FastIoSection<N>` object representing
29    ///   the shared memory section to be added.
30    ///
31    /// # Returns
32    ///
33    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
34    pub fn add_secondary_fast_io<const N: usize>(
35        &self,
36        fast_io_section: &mut FastIoSection<N>,
37    ) -> Result<()> {
38        let params = InitializeFastIoParams::<N> {
39            header_ptr: fast_io_section as *mut FastIoSection<N>,
40            data_size: N as u32,
41        };
42
43        let result = unsafe {
44            DeviceIoControl(
45                self.driver_handle,
46                IOCTL_NDISRD_ADD_SECOND_FAST_IO_SECTION,
47                Some(&params as *const InitializeFastIoParams<N> as *const std::ffi::c_void),
48                size_of::<InitializeFastIoParams<N>>() as u32,
49                None,
50                0,
51                None,
52                None,
53            )
54        };
55
56        if !result.as_bool() {
57            Err(unsafe { GetLastError() }.into())
58        } else {
59            Ok(())
60        }
61    }
62
63    /// This function initializes the fast I/O mechanism for the NDIS filter driver and
64    /// submits the initial shared memory section for faster communication between
65    /// user-mode applications and the driver.
66    ///
67    /// # Type Parameters
68    ///
69    /// * `N`: The size of the Fast I/O shared memory section.
70    ///
71    /// # Arguments
72    ///
73    /// * `fast_io_section`: A mutable reference to a `FastIoSection<N>` object representing
74    ///   the shared memory section to be submitted.
75    ///
76    /// # Returns
77    ///
78    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
79    pub fn initialize_fast_io<const N: usize>(
80        &self,
81        fast_io_section: &mut FastIoSection<N>,
82    ) -> Result<()> {
83        let params = InitializeFastIoParams::<N> {
84            header_ptr: fast_io_section as *mut FastIoSection<N>,
85            data_size: N as u32,
86        };
87
88        let result = unsafe {
89            DeviceIoControl(
90                self.driver_handle,
91                IOCTL_NDISRD_INITIALIZE_FAST_IO,
92                Some(&params as *const InitializeFastIoParams<N> as *const std::ffi::c_void),
93                size_of::<InitializeFastIoParams<N>>() as u32,
94                None,
95                0,
96                None,
97                None,
98            )
99        };
100
101        if !result.as_bool() {
102            Err(unsafe { GetLastError() }.into())
103        } else {
104            Ok(())
105        }
106    }
107
108    /// This function retrieves queued packets from the NDIS filter driver without considering
109    /// the network interface. It reads packets in an unsorted manner and stores them in the
110    /// provided buffer.
111    ///
112    /// # Type Parameters
113    ///
114    /// * `N`: The number of packets to read.
115    ///
116    /// # Arguments
117    ///
118    /// * `packets`: A mutable reference to an array of `IntermediateBuffer` objects, where the
119    ///   read packets will be stored.
120    ///
121    /// # Returns
122    ///
123    /// * `Result<usize>`: If successful, returns `Ok(usize)` with the number of packets read.
124    ///   Otherwise, returns an error.
125    pub fn read_packets_unsorted<const N: usize>(
126        &self,
127        packets: &mut [IntermediateBuffer; N],
128    ) -> Result<usize> {
129        let mut request = UnsortedReadSendRequest::<N> {
130            packets: packets as *mut [IntermediateBuffer; N],
131            packets_num: N as u32,
132        };
133
134        let result = unsafe {
135            DeviceIoControl(
136                self.driver_handle,
137                IOCTL_NDISRD_READ_PACKETS_UNSORTED,
138                Some(&request as *const UnsortedReadSendRequest<N> as *const std::ffi::c_void),
139                size_of::<UnsortedReadSendRequest<N>>() as u32,
140                Some(&mut request as *mut UnsortedReadSendRequest<N> as *mut std::ffi::c_void),
141                size_of::<UnsortedReadSendRequest<N>>() as u32,
142                None,
143                None,
144            )
145        };
146
147        if !result.as_bool() {
148            Err(unsafe { GetLastError() }.into())
149        } else {
150            Ok(request.packets_num as usize)
151        }
152    }
153
154    /// This function forwards packets to the NDIS filter driver in an unsorted manner, which then
155    /// sends them to the target network interface. The target adapter handle should be set in the
156    /// `IntermediateBuffer.header.adapter_handle` field.
157    ///
158    /// # Type Parameters
159    ///
160    /// * `N`: The number of packets to send.
161    ///
162    /// # Arguments
163    ///
164    /// * `packets`: A mutable reference to an array of `IntermediateBuffer` objects, which contain
165    ///   the packets to be sent.
166    /// * `packets_num`: The number of packets to send from the array.
167    ///
168    /// # Returns
169    ///
170    /// * `Result<usize>`: If successful, returns `Ok(usize)` with the number of packets sent.
171    ///   Otherwise, returns an error.
172    pub fn send_packets_to_adapters_unsorted<const N: usize>(
173        &self,
174        packets: &mut [IntermediateBuffer; N],
175        packets_num: usize,
176    ) -> Result<usize> {
177        let mut request = UnsortedReadSendRequest::<N> {
178            packets: packets as *mut [IntermediateBuffer; N],
179            packets_num: packets_num as u32,
180        };
181
182        let result = unsafe {
183            DeviceIoControl(
184                self.driver_handle,
185                IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER_UNSORTED,
186                Some(&request as *const UnsortedReadSendRequest<N> as *const std::ffi::c_void),
187                size_of::<UnsortedReadSendRequest<N>>() as u32,
188                Some(&mut request as *mut UnsortedReadSendRequest<N> as *mut std::ffi::c_void),
189                size_of::<UnsortedReadSendRequest<N>>() as u32,
190                None,
191                None,
192            )
193        };
194
195        if !result.as_bool() {
196            Err(unsafe { GetLastError() }.into())
197        } else {
198            Ok(request.packets_num as usize)
199        }
200    }
201
202    /// This function forwards packets to the NDIS filter driver in an unsorted manner, which then
203    /// sends them to the target protocols layer (MSTCP). The target adapter handle (to be indicated
204    /// from) should be set in the `IntermediateBuffer.header.adapter_handle` field.
205    ///
206    /// # Type Parameters
207    ///
208    /// * `N`: The number of packets to send.
209    ///
210    /// # Arguments
211    ///
212    /// * `packets`: A mutable reference to an array of `IntermediateBuffer` objects, which contain
213    ///   the packets to be sent.
214    /// * `packets_num`: The number of packets to send from the array.
215    ///
216    /// # Returns
217    ///
218    /// * `Result<usize>`: If successful, returns `Ok(usize)` with the number of packets sent.
219    ///   Otherwise, returns an error.
220    pub fn send_packets_to_mstcp_unsorted<const N: usize>(
221        &self,
222        packets: &mut [IntermediateBuffer; N],
223        packets_num: usize,
224    ) -> Result<usize> {
225        let mut request = UnsortedReadSendRequest::<N> {
226            packets: packets as *mut [IntermediateBuffer; N],
227            packets_num: packets_num as u32,
228        };
229
230        let result = unsafe {
231            DeviceIoControl(
232                self.driver_handle,
233                IOCTL_NDISRD_SEND_PACKET_TO_MSTCP_UNSORTED,
234                Some(&request as *const UnsortedReadSendRequest<N> as *const std::ffi::c_void),
235                size_of::<UnsortedReadSendRequest<N>>() as u32,
236                Some(&mut request as *mut UnsortedReadSendRequest<N> as *mut std::ffi::c_void),
237                size_of::<UnsortedReadSendRequest<N>>() as u32,
238                None,
239                None,
240            )
241        };
242
243        if !result.as_bool() {
244            Err(unsafe { GetLastError() }.into())
245        } else {
246            Ok(request.packets_num as usize)
247        }
248    }
249}