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}