ndisapi_rs/ndisapi/
io_api.rs

1//! # Submodule: I/O functions
2//!
3//! This submodule defines a set of functions that interact with the NDIS filter driver.
4//! These functions include clearing the packet queue associated with a network adapter,
5//! retrieving the number of packets currently queued in the packet queue, reading single
6//! or multiple network packets from the NDIS filter driver, and sending single or multiple
7//! network packets to the NDIS filter driver to be passed down or up the network stack.
8//! This submodule also provides a function to set a Win32 event to be signaled by the
9//! NDIS filter when packets are available for read on a network adapter.
10//!
11
12use std::mem::size_of;
13
14use windows::{
15    core::Result,
16    Win32::Foundation::{GetLastError, HANDLE},
17    Win32::System::IO::DeviceIoControl,
18};
19
20use super::Ndisapi;
21use crate::driver::*;
22
23impl Ndisapi {
24    /// This function clears the packet queue associated with the specified network adapter
25    /// handle in the NDIS filter driver.
26    ///
27    /// # Arguments
28    ///
29    /// * `adapter_handle: HANDLE`: The handle of the network adapter whose packet queue
30    ///   should be flushed.
31    ///
32    /// # Returns
33    ///
34    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
35    pub fn flush_adapter_packet_queue(&self, adapter_handle: HANDLE) -> Result<()> {
36        let result = unsafe {
37            DeviceIoControl(
38                self.driver_handle,
39                IOCTL_NDISRD_FLUSH_ADAPTER_QUEUE,
40                Some(&adapter_handle as *const HANDLE as *const std::ffi::c_void),
41                size_of::<HANDLE>() as u32,
42                None,
43                0,
44                None,
45                None,
46            )
47        };
48
49        if !result.as_bool() {
50            Err(unsafe { GetLastError() }.into())
51        } else {
52            Ok(())
53        }
54    }
55
56    /// This function retrieves the number of packets currently queued in the packet queue associated with the
57    /// specified network adapter handle in the NDIS filter driver.
58    ///
59    /// # Arguments
60    ///
61    /// * `adapter_handle: HANDLE`: The handle of the network adapter whose packet queue size should be queried.
62    ///
63    /// # Returns
64    ///
65    /// * `Result<u32>`: If successful, returns `Ok(queue_size)` where `queue_size` is the number of packets in the
66    ///   adapter's packet queue. Otherwise, returns an error.
67    pub fn get_adapter_packet_queue_size(&self, adapter_handle: HANDLE) -> Result<u32> {
68        let mut queue_size = 0u32;
69
70        let result = unsafe {
71            DeviceIoControl(
72                self.driver_handle,
73                IOCTL_NDISRD_ADAPTER_QUEUE_SIZE,
74                Some(&adapter_handle as *const HANDLE as *const std::ffi::c_void),
75                size_of::<HANDLE>() as u32,
76                Some(&mut queue_size as *mut u32 as *mut std::ffi::c_void),
77                size_of::<u32>() as u32,
78                None,
79                None,
80            )
81        };
82
83        if !result.as_bool() {
84            Err(unsafe { GetLastError() }.into())
85        } else {
86            Ok(queue_size)
87        }
88    }
89
90    /// This function retrieves a single network packet from the NDIS filter driver associated with
91    /// the specified `EthRequest`.
92    ///
93    /// # Arguments
94    ///
95    /// * `packet: &mut EthRequest`: A mutable reference to the `EthRequest` structure that will be filled with
96    ///   the retrieved packet data.
97    ///
98    /// # Returns
99    ///
100    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
101    pub fn read_packet(&self, packet: &mut EthRequest) -> Result<()> {
102        let result = unsafe {
103            DeviceIoControl(
104                self.driver_handle,
105                IOCTL_NDISRD_READ_PACKET,
106                Some(packet as *const EthRequest as *const std::ffi::c_void),
107                size_of::<EthRequest>() as u32,
108                None,
109                0u32,
110                None,
111                None,
112            )
113        };
114
115        if !result.as_bool() {
116            Err(unsafe { GetLastError() }.into())
117        } else {
118            Ok(())
119        }
120    }
121
122    /// This function retrieves a block of network packets from the NDIS filter driver associated with
123    /// the specified `EthMRequest<N>`.
124    ///
125    /// # Arguments
126    ///
127    /// * `packets: &mut EthMRequest<N>`: A mutable reference to the `EthMRequest<N>` structure that will be filled with
128    ///   the retrieved packet data.
129    ///
130    /// # Returns
131    ///
132    /// * `Result<usize>`: If successful, returns `Ok(packet_count)` where `packet_count` is the number of packets read
133    ///   into `EthMRequest<N>`. Otherwise, returns an error.
134    pub fn read_packets<const N: usize>(&self, packets: &mut EthMRequest<N>) -> Result<usize> {
135        let result = unsafe {
136            DeviceIoControl(
137                self.driver_handle,
138                IOCTL_NDISRD_READ_PACKETS,
139                Some(packets as *const EthMRequest<N> as *const std::ffi::c_void),
140                size_of::<EthMRequest<N>>() as u32,
141                Some(packets as *mut EthMRequest<N> as *mut std::ffi::c_void),
142                size_of::<EthMRequest<N>>() as u32,
143                None,
144                None,
145            )
146        };
147
148        if result.as_bool() {
149            Ok(packets.get_packet_success() as usize)
150        } else {
151            Err(unsafe { GetLastError() }.into())
152        }
153    }
154
155    /// This function sends a single network packet to the NDIS filter driver associated with
156    /// the specified `EthRequest`, which will then be passed down the network stack.
157    ///
158    /// # Arguments
159    ///
160    /// * `packet: &EthRequest`: A reference to the `EthRequest` structure containing the packet data to be sent.
161    ///
162    /// # Returns
163    ///
164    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
165    pub fn send_packet_to_adapter(&self, packet: &EthRequest) -> Result<()> {
166        let result = unsafe {
167            DeviceIoControl(
168                self.driver_handle,
169                IOCTL_NDISRD_SEND_PACKET_TO_ADAPTER,
170                Some(packet as *const EthRequest as *const std::ffi::c_void),
171                size_of::<EthRequest>() as u32,
172                None,
173                0,
174                None,
175                None,
176            )
177        };
178
179        if !result.as_bool() {
180            Err(unsafe { GetLastError() }.into())
181        } else {
182            Ok(())
183        }
184    }
185
186    /// This function sends a single network packet to the NDIS filter driver associated with
187    /// the specified `EthRequest`, which will then be passed down the network stack to the Microsoft TCP/IP stack.
188    ///
189    /// # Arguments
190    ///
191    /// * `packet: &EthRequest`: A reference to the `EthRequest` structure containing the packet data to be sent.
192    ///
193    /// # Returns
194    ///
195    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
196    pub fn send_packet_to_mstcp(&self, packet: &EthRequest) -> Result<()> {
197        let result = unsafe {
198            DeviceIoControl(
199                self.driver_handle,
200                IOCTL_NDISRD_SEND_PACKET_TO_MSTCP,
201                Some(packet as *const EthRequest as *const std::ffi::c_void),
202                size_of::<EthRequest>() as u32,
203                None,
204                0,
205                None,
206                None,
207            )
208        };
209
210        if !result.as_bool() {
211            Err(unsafe { GetLastError() }.into())
212        } else {
213            Ok(())
214        }
215    }
216
217    /// This function sends a block of network packets to the NDIS filter driver associated with
218    /// the specified `EthMRequest<N>`, which will then be passed down the network stack.
219    ///
220    /// # Arguments
221    ///
222    /// * `packets: &EthMRequest<N>`: A reference to the `EthMRequest<N>` structure containing the packet data to be sent.
223    ///
224    /// # Returns
225    ///
226    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
227    pub fn send_packets_to_adapter<const N: usize>(&self, packets: &EthMRequest<N>) -> Result<()> {
228        let result = unsafe {
229            DeviceIoControl(
230                self.driver_handle,
231                IOCTL_NDISRD_SEND_PACKETS_TO_ADAPTER,
232                Some(packets as *const EthMRequest<N> as *const std::ffi::c_void),
233                size_of::<EthMRequest<N>>() as u32,
234                None,
235                0,
236                None,
237                None,
238            )
239        };
240
241        if !result.as_bool() {
242            Err(unsafe { GetLastError() }.into())
243        } else {
244            Ok(())
245        }
246    }
247
248    /// This function sends a block of network packets to the NDIS filter driver associated with
249    /// the specified `EthMRequest<N>`, which will then be passed up the network stack to the Microsoft TCP/IP stack.
250    ///
251    /// # Arguments
252    ///
253    /// * `packets: &EthMRequest<N>`: A reference to the `EthMRequest<N>` structure containing the packet data to be sent.
254    ///
255    /// # Returns
256    ///
257    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
258    pub fn send_packets_to_mstcp<const N: usize>(&self, packets: &EthMRequest<N>) -> Result<()> {
259        let result = unsafe {
260            DeviceIoControl(
261                self.driver_handle,
262                IOCTL_NDISRD_SEND_PACKETS_TO_MSTCP,
263                Some(packets as *const EthMRequest<N> as *const std::ffi::c_void),
264                size_of::<EthMRequest<N>>() as u32,
265                None,
266                0,
267                None,
268                None,
269            )
270        };
271
272        if !result.as_bool() {
273            Err(unsafe { GetLastError() }.into())
274        } else {
275            Ok(())
276        }
277    }
278
279    /// This function sets a Win32 event to be signaled by the NDIS filter when it has queued packets available for read
280    /// on the specified network adapter.
281    ///
282    /// # Arguments
283    ///
284    /// * `adapter_handle: HANDLE`: The handle of the network adapter to associate the event with.
285    /// * `event_handle: HANDLE`: The handle of the Win32 event to be signaled when queued packets are available.
286    ///
287    /// # Returns
288    ///
289    /// * `Result<()>`: If successful, returns `Ok(())`. Otherwise, returns an error.
290    pub fn set_packet_event(&self, adapter_handle: HANDLE, event_handle: HANDLE) -> Result<()> {
291        let adapter_event = AdapterEvent {
292            adapter_handle,
293            event_handle,
294        };
295
296        let result = unsafe {
297            DeviceIoControl(
298                self.driver_handle,
299                IOCTL_NDISRD_SET_EVENT,
300                Some(&adapter_event as *const AdapterEvent as *const std::ffi::c_void),
301                size_of::<AdapterEvent>() as u32,
302                None,
303                0,
304                None,
305                None,
306            )
307        };
308
309        if !result.as_bool() {
310            Err(unsafe { GetLastError() }.into())
311        } else {
312            Ok(())
313        }
314    }
315}