ndisapi_rs/driver/
base.rs

1//! # Submodule: Basic NDISAPI Structures
2//!
3//! This submodule provides Rust equivalents of several structures used in the NDISAPI Rust library
4//! for communicating with the Windows Packet Filter driver.
5//!
6//! The structures in this submodule are related to network adapters, Ethernet packets, adapter events,
7//! and Remote Access Service (RAS) links.
8//!
9//! For a detailed description of each structure, refer to their respective documentation within the
10//! submodule.
11
12// Import required external crates and types
13use std::mem::size_of;
14use windows::{
15    core::Result,
16    Win32::Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAMETER, HANDLE},
17};
18
19use super::constants::*;
20
21/// The `TcpAdapterList` structure is the Rust equivalent of the
22/// [_TCP_AdapterList](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_tcp_adapterlist/)
23/// structure in the Windows Packet Filter documentation. It represents a list of network adapters,
24/// along with their properties, such as adapter names, handles, medium types, current addresses, and MTUs.
25///
26/// # Fields
27///
28/// * `adapter_count`: A 32-bit unsigned integer representing the total number of adapters in the list.
29/// * `adapter_name_list`: An array of arrays, with each inner array containing `ADAPTER_NAME_SIZE` bytes,
30///   representing the adapter names in the list.
31/// * `adapter_handle`: An array of `HANDLE` values, representing the handles of the adapters in the list.
32/// * `adapter_medium_list`: An array of 32-bit unsigned integers, representing the medium types of the
33///   adapters in the list.
34/// * `current_address`: An array of arrays, with each inner array containing `ETHER_ADDR_LENGTH` bytes,
35///   representing the current addresses of the adapters in the list.
36/// * `mtu`: An array of 16-bit unsigned integers, representing the Maximum Transmission Units (MTUs) of the
37///   adapters in the list.
38#[repr(C, packed)]
39#[derive(Debug, Copy, Clone)]
40pub struct TcpAdapterList {
41    pub adapter_count: u32,
42    pub adapter_name_list: [[u8; ADAPTER_NAME_SIZE]; ADAPTER_LIST_SIZE],
43    pub adapter_handle: [HANDLE; ADAPTER_LIST_SIZE],
44    pub adapter_medium_list: [u32; ADAPTER_LIST_SIZE],
45    pub current_address: [[u8; ETHER_ADDR_LENGTH]; ADAPTER_LIST_SIZE],
46    pub mtu: [u16; ADAPTER_LIST_SIZE],
47}
48
49/// The `ListEntry` structure is the Rust equivalent of the
50/// [_LIST_ENTRY](https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-list_entry)
51/// structure in the Windows API. It represents a doubly-linked list entry, containing forward and backward
52/// pointers to adjacent list entries.
53///
54/// # Fields
55///
56/// * `flink`: A mutable raw pointer to the next `ListEntry` in the list (forward link).
57/// * `blink`: A mutable raw pointer to the previous `ListEntry` in the list (backward link).
58#[repr(C)]
59#[derive(Debug, Copy, Clone)]
60pub struct ListEntry {
61    pub flink: *mut ListEntry,
62    pub blink: *mut ListEntry,
63}
64
65/// The `IntermediateBufferHeaderUnion` structure is the Rust equivalent of the union
66/// used for `INTERMEDIATE_BUFFER` in the driver API. It represents a union between a
67/// `HANDLE` and a `ListEntry`, providing a way to access either of them based on the context.
68///
69/// # Fields
70///
71/// * `adapter_handle`: A `HANDLE` representing the adapter handle.
72/// * `list_entry`: A `ListEntry` structure representing a doubly-linked list entry.
73#[repr(C, packed)]
74#[derive(Copy, Clone)]
75pub union IntermediateBufferHeaderUnion {
76    pub adapter_handle: HANDLE,
77    pub list_entry: ListEntry,
78}
79
80/// Provides a default implementation for the `IntermediateBufferHeaderUnion` structure.
81///
82/// # Safety
83///
84/// This implementation is safe because the union contains either a `HANDLE` or a `ListEntry`.
85/// The `ListEntry` is a union of raw pointers, which can be safely zeroed as long as they are not dereferenced.
86/// The `HANDLE` is a wrapper around an `isize`, which can also be safely zeroed.
87impl Default for IntermediateBufferHeaderUnion {
88    fn default() -> Self {
89        // SAFETY: This union contains either a `HANDLE` or a `ListEntry`
90        // ListEntry: is an union of raw pointers which can be safely zeroed(as long as you not dereference it)
91        // HANDLE: is just an `isize` wrapper which can also be zeroed
92        unsafe { core::mem::zeroed() }
93    }
94}
95
96/// The `IntermediateBuffer` structure represents an intermediate buffer that stores packet data along with some
97/// additional information. This structure is used internally by the packet filter driver.
98///
99/// Rust equivalent for [_INTERMEDIATE_BUFFER](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_intermediate_buffer/).
100///
101/// # Fields
102/// * `header`: An `IntermediateBufferHeaderUnion` which is a union of `HANDLE` and `ListEntry`.
103/// * `device_flags`: A `DirectionFlags` value that indicates the direction of the packet (send or receive).
104/// * `length`: A `u32` representing the length of the packet data.
105/// * `flags`: A `u32` value containing various flags related to the packet.
106/// * `vlan_8021q`: A `u32` value representing the VLAN tag (802.1Q) associated with the packet.
107/// * `filter_id`: A `u32` value identifying the filter that processed the packet.
108/// * `reserved`: A reserved `[u32; 4usize]` array for future use.
109/// * `buffer`: A `Buffer` structure containing the actual packet data.
110#[repr(C, packed)]
111#[derive(Copy, Clone, Default)]
112pub struct IntermediateBuffer {
113    pub header: IntermediateBufferHeaderUnion,
114    pub device_flags: DirectionFlags,
115    pub length: u32,
116    pub flags: u32,
117    pub vlan_8021q: u32,
118    pub filter_id: u32,
119    pub reserved: [u32; 4usize],
120    pub buffer: Buffer,
121}
122
123/// This structure represents the buffer used for storing the actual packet data.
124///
125/// A wrapper around an array of bytes with a size of `MAX_ETHER_FRAME`.
126#[repr(transparent)]
127#[derive(Copy, Clone)]
128pub struct Buffer(pub [u8; MAX_ETHER_FRAME]);
129
130impl Default for Buffer {
131    fn default() -> Self {
132        Self([0; MAX_ETHER_FRAME])
133    }
134}
135
136/// IntermediateBuffer implementation
137impl IntermediateBuffer {
138    /// Creates a new `IntermediateBuffer` with default values.
139    ///
140    /// # Returns
141    /// A new `IntermediateBuffer` instance.
142    pub fn new() -> Self {
143        Self::default()
144    }
145
146    /// Gets the `DirectionFlags` value associated with the `IntermediateBuffer`.
147    ///
148    /// # Returns
149    /// The `DirectionFlags` value indicating the direction of the packet (send or receive).
150    pub fn get_device_flags(&self) -> DirectionFlags {
151        self.device_flags
152    }
153
154    /// Gets the length of the packet data stored in the `IntermediateBuffer`.
155    ///
156    /// # Returns
157    /// A `u32` value representing the length of the packet data.
158    pub fn get_length(&self) -> u32 {
159        self.length
160    }
161
162    /// Sets the length of the packet data stored in the `IntermediateBuffer`.
163    ///
164    /// # Arguments
165    /// * `length`: A `u32` value representing the new length of the packet data.
166    pub fn set_length(&mut self, length: u32) {
167        self.length = length
168    }
169
170    /// Returns a reference to the data stored in the buffer.
171    ///
172    /// This method returns a reference to the data stored in the buffer as a slice of bytes.
173    /// The length of the slice is determined by the `length` field of the `buffer` struct.
174    pub fn get_data(&self) -> &[u8] {
175        &self.buffer.0[..self.length as usize]
176    }
177
178    /// Returns a mutable reference to the data stored in the buffer.
179    ///
180    /// This method returns a mutable reference to the data stored in the buffer as a slice of bytes.
181    /// The length of the slice is determined by the `length` field of the `buffer` struct.
182    pub fn get_data_mut(&mut self) -> &mut [u8] {
183        &mut self.buffer.0[..self.length as usize]
184    }
185}
186
187/// This structure is used to define the mode of an adapter with a specified handle and filter flags.
188///
189/// A Rust equivalent for the [_ADAPTER_MODE](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/adapter_mode/) structure.
190#[repr(C, packed)]
191#[derive(Debug, Copy, Clone, Default)]
192pub struct AdapterMode {
193    /// A `HANDLE` representing the adapter handle.
194    pub adapter_handle: HANDLE,
195    /// `FilterFlags` representing the filter flags associated with the adapter mode.
196    pub flags: FilterFlags,
197}
198
199/// This structure represents an Ethernet packet with an optional mutable reference to an `IntermediateBuffer`.
200///
201/// A Rust equivalent for the [_NDISRD_ETH_Packet](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ndisrd_eth_packet/) structure.
202///
203/// The `buffer` field is an Option wrapping a mutable reference to an `IntermediateBuffer`. This design allows for flexibility
204/// when manipulating Ethernet packets, as a packet may not always have a buffer associated with it (i.e., the buffer may be `None`).
205#[repr(C)]
206pub struct EthPacket<'a> {
207    /// An optional mutable reference to an `IntermediateBuffer` representing the buffer for this Ethernet packet.
208    pub buffer: Option<&'a mut IntermediateBuffer>,
209}
210
211/// Implements the `Into` trait for `EthPacket`.
212///
213/// The purpose of this implementation is to facilitate the conversion of an `EthPacket` into an `Option<&'a mut IntermediateBuffer>`.
214///
215/// The conversion is valuable when there is a need to directly manipulate the buffer of a packet. By implementing `Into` for `EthPacket`,
216/// we provide a convenient and idiomatic way to perform this transformation.
217impl<'a> From<EthPacket<'a>> for Option<&'a mut IntermediateBuffer> {
218    fn from(val: EthPacket<'a>) -> Self {
219        val.buffer
220    }
221}
222
223/// Implements the `Default` trait for `EthPacket`.
224///
225/// This implementation allows for the creation of an "empty" `EthPacket`, i.e., a packet without a buffer. This is useful when
226/// initializing a variable of type `EthPacket` without immediately associating a buffer with it.
227impl<'a> Default for EthPacket<'a> {
228    fn default() -> Self {
229        EthPacket { buffer: None }
230    }
231}
232
233/// This structure represents a request for an Ethernet packet, containing a network adapter handle and an `EthPacket`.
234///
235/// A Rust equivalent for the [_ETH_REQUEST](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_eth_request/) structure.
236///
237/// `adapter_handle` is a handle to the network adapter associated with this request. The `packet` field is an `EthPacket` that represents the Ethernet packet for this request.
238#[repr(C)]
239pub struct EthRequest<'a> {
240    /// A handle to the network adapter associated with this request.
241    pub adapter_handle: HANDLE,
242    /// An `EthPacket` representing the Ethernet packet for this request.
243    pub packet: EthPacket<'a>,
244}
245
246/// Provides methods for manipulating the `EthPacket` within an `EthRequest`.
247impl<'a> EthRequest<'a> {
248    /// Creates a new `EthRequest` with the specified adapter handle and an empty `EthPacket`.
249    ///
250    /// # Arguments
251    ///
252    /// * `adapter_handle` - A handle to the network adapter to be associated with this request.
253    ///
254    /// # Returns
255    ///
256    /// * A new `EthRequest` instance with the specified adapter handle and an empty `EthPacket`.
257    pub fn new(adapter_handle: HANDLE) -> Self {
258        Self {
259            adapter_handle,
260            packet: EthPacket { buffer: None },
261        }
262    }
263
264    /// Takes the `EthPacket` out from the `EthRequest`, replacing it with `None`.
265    ///
266    /// This is useful when you want to use the packet's buffer elsewhere, while ensuring that the `EthRequest` no longer has access to it.
267    pub fn take_packet(&mut self) -> Option<&'a mut IntermediateBuffer> {
268        self.packet.buffer.take()
269    }
270
271    /// Sets the `EthPacket` for the `EthRequest` using a mutable reference to an `IntermediateBuffer`.
272    ///
273    /// This method allows you to associate a new buffer with the `EthRequest`. This is useful when you have a buffer that you want to send with the `EthRequest`.
274    pub fn set_packet(&mut self, buffer: &'a mut IntermediateBuffer) {
275        self.packet = EthPacket {
276            buffer: Some(buffer),
277        };
278    }
279}
280
281/// This structure represents a request for multiple Ethernet packets, containing a network adapter handle, packet number, packet success count, and an array of `EthPacket` instances.
282///
283/// A Rust equivalent for the [_ETH_M_REQUEST](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_eth_m_request/) structure.
284///
285/// `adapter_handle` is a handle to the network adapter associated with this request. `packet_number` is the number of packets in the `packets` array. `packet_success` is the number of packets that have been successfully processed. `packets` is an array of `EthPacket` instances representing the Ethernet packets for this request.
286#[repr(C)]
287pub struct EthMRequest<'a, const N: usize> {
288    /// A handle to the network adapter associated with this request.
289    adapter_handle: HANDLE,
290    /// The number of packets in the `packets` array.
291    packet_number: u32,
292    /// The number of successfully processed packets.
293    packet_success: u32,
294    /// An array of `EthPacket` representing the Ethernet packets for this request.
295    packets: [EthPacket<'a>; N],
296}
297
298/// Provides methods for manipulating the `EthPacket` instances within an `EthMRequest`.
299impl<'a, const N: usize> EthMRequest<'a, N> {
300    /// Creates a new `EthMRequest` with the specified adapter handle.
301    ///
302    /// All packets in the request are initialized to empty.
303    pub fn new(adapter_handle: HANDLE) -> Self {
304        let packets = [(); N].map(|_| EthPacket { buffer: None });
305        Self {
306            adapter_handle,
307            packet_number: 0,
308            packet_success: 0,
309            packets,
310        }
311    }
312
313    /// Creates a new `EthMRequest` from an iterator over `&mut IntermediateBuffer`.
314    ///
315    /// This constructor will attempt to consume up to `N` items from the iterator to initialize the `packets` array.
316    /// If the iterator contains fewer than `N` items, the remaining entries in the `packets` array will be left as `None`.
317    ///
318    /// # Arguments
319    ///
320    /// * `adapter_handle`: A handle to the network adapter associated with this request.
321    /// * `iter`: An iterator over mutable references to `IntermediateBuffer`.
322    ///
323    /// # Returns
324    ///
325    /// A new `EthMRequest`.
326    pub fn from_iter(
327        adapter_handle: HANDLE,
328        iter: impl Iterator<Item = &'a mut IntermediateBuffer>,
329    ) -> Self {
330        let mut packets = [(); N].map(|_| EthPacket { buffer: None });
331        let mut packet_number = 0;
332
333        for (buffer, packet) in iter.zip(packets.iter_mut()) {
334            packet.buffer = Some(buffer);
335            packet_number += 1;
336        }
337
338        Self {
339            adapter_handle,
340            packet_number,
341            packet_success: 0,
342            packets,
343        }
344    }
345
346    /// Returns an iterator that yields `Some(IntermediateBuffer)` for each non-empty buffer in `packets`, in order,
347    /// up to `packet_success`.
348    /// 
349    /// # Description
350    ///
351    /// This function, `drain_success`, operates on mutable reference to the current instance of the struct.
352    /// It returns an iterator that goes over each non-empty buffer in `packets`, in their
353    /// original order, but only up to the index specified by `packet_success`. This iterator will
354    /// yield `Some(IntermediateBuffer)` for each of these buffers. These buffers represent packets
355    /// that have been successfully read from the driver.
356    ///
357    /// Once called, this method drains the non-empty buffers from `packets`, up to `packet_success` making them empty (`None`).
358    ///
359    /// # Returns
360    ///
361    /// This function returns an implementation of Iterator trait. The iterator item type is a mutable reference
362    /// to an `IntermediateBuffer` (`&'a mut IntermediateBuffer`). This iterator can be used to iterate over the drained buffers.
363    pub fn drain_success(&mut self) -> impl Iterator<Item = &'a mut IntermediateBuffer> + '_ {
364        self.packets
365            .iter_mut()
366            .take(self.packet_success as usize)
367            .filter_map(|packet| {
368                if packet.buffer.is_some() {
369                    self.packet_number -= 1;
370                    packet.buffer.take()
371                } else {
372                    None
373                }
374            })
375    }
376
377    /// Returns an iterator that yields `Some(IntermediateBuffer)` for each non-empty buffer in `packets`.
378    ///
379    /// # Description
380    ///
381    /// This function, `drain`, operates on mutable reference to the current instance of the struct.
382    /// It returns an iterator which yields mutable references to `IntermediateBuffer` for each non-empty buffer in `packets`,
383    /// and it yields them in the order they occur in `packets`.
384    ///
385    /// Once called, this method drains the non-empty buffers from `packets`, making them empty (`None`).
386    ///
387    /// # Returns
388    ///
389    /// This function returns an implementation of Iterator trait. The iterator item type is a mutable reference
390    /// to an `IntermediateBuffer` (`&'a mut IntermediateBuffer`). This iterator can be used to iterate over the drained buffers.
391    pub fn drain(&mut self) -> impl Iterator<Item = &'a mut IntermediateBuffer> + '_ {
392        self.packets.iter_mut().filter_map(|packet| {
393            if packet.buffer.is_some() {
394                self.packet_number -= 1;
395                packet.buffer.take()
396            } else {
397                None
398            }
399        })
400    }
401
402    /// Sets the `IntermediateBuffer` for the `EthPacket` at the specified index.
403    ///
404    /// This method allows you to associate a new buffer with the `EthPacket` at the given index.
405    fn set_packet(&mut self, index: usize, buffer: &'a mut IntermediateBuffer) -> Result<()> {
406        if index < N {
407            self.packets[index].buffer = Some(buffer);
408            Ok(())
409        } else {
410            Err(ERROR_INVALID_PARAMETER.into())
411        }
412    }
413
414    /// Returns the number of packets in the `packets` array.
415    ///
416    /// This provides a count of all packets, regardless of whether they've been successfully processed.
417    pub fn get_packet_number(&self) -> u32 {
418        self.packet_number
419    }
420
421    /// Erases all `EthPacket` instances within the `packets` array and releases all references.
422    ///
423    /// After this method is called, all `EthPacket` instances within the `packets` array will be empty (i.e., their `buffer` fields will be `None`), and the packet number will be reset to 0.
424    pub fn reset(&mut self) {
425        for packet in self.packets.iter_mut() {
426            packet.buffer = None;
427        }
428        self.packet_number = 0;
429        self.packet_success = 0;
430    }
431
432    /// Returns the number of successfully processed packets
433    pub fn get_packet_success(&self) -> u32 {
434        self.packet_success
435    }
436
437    /// Adds an `IntermediateBuffer` to the `packets` array if there's available space.
438    /// This effectively wraps the buffer into an `EthPacket` and stores it in the array.
439    ///
440    /// The `packet_number` field of the `EthMRequest` is automatically incremented to reflect the addition of the new packet.
441    ///
442    /// If there is no available space in the array (i.e., if the `packet_number` is equal to the array length `N`), this method returns an error, specifically `ERROR_INVALID_PARAMETER`.
443    ///
444    /// This method provides an idiomatic way of adding new packets to an `EthMRequest` in Rust.
445    ///
446    /// # Arguments
447    ///
448    /// * `packet` - A mutable reference to the `IntermediateBuffer` to be added to the `packets` array.
449    ///
450    /// # Returns
451    ///
452    /// * `Ok(())` if the buffer was successfully added as a packet.
453    /// * `Err(ERROR_BUFFER_OVERFLOW.into())` if the `packets` array is full.
454    pub fn push(&mut self, packet: &'a mut IntermediateBuffer) -> Result<()> {
455        if (self.packet_number as usize) < N {
456            if let Some(index) = self.first_empty_packet() {
457                self.packets[index] = EthPacket {
458                    buffer: Some(packet),
459                };
460                self.packet_number += 1;
461                Ok(())
462            } else {
463                Err(ERROR_BUFFER_OVERFLOW.into())
464            }
465        } else {
466            Err(ERROR_BUFFER_OVERFLOW.into())
467        }
468    }
469
470    /// Returns the index of the first `EthPacket` which contains `None`.
471    ///
472    /// # Returns
473    /// * An `Option<usize>` representing the index of the first empty `EthPacket`.
474    /// If no empty `EthPacket` is found, returns `None`.
475    fn first_empty_packet(&self) -> Option<usize> {
476        self.packets
477            .iter()
478            .position(|packet| packet.buffer.is_none())
479    }
480
481    /// Consumes packets from an Iterator, moving them into `self`.
482    ///
483    /// # Arguments
484    /// * `packets` - An iterator yielding mutable references to IntermediateBuffer.
485    ///
486    /// # Returns
487    /// * Result indicating success or failure.
488    pub fn append<I>(&mut self, packets: I) -> Result<()>
489    where
490        I: Iterator<Item = &'a mut IntermediateBuffer>,
491    {
492        for buffer in packets {
493            if self.packet_number as usize >= N {
494                return Err(ERROR_BUFFER_OVERFLOW.into());
495            }
496
497            if let Some(empty_slot) = self.first_empty_packet() {
498                self.set_packet(empty_slot, buffer)?;
499                self.packet_number += 1;
500            } else {
501                return Err(ERROR_BUFFER_OVERFLOW.into());
502            }
503        }
504
505        Ok(())
506    }
507}
508
509/// This structure represents an adapter event, containing an adapter handle and an event handle.
510///
511/// A Rust equivalent for the [_ADAPTER_EVENT](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/adapter_event/) structure.
512#[repr(C, packed)]
513#[derive(Debug, Copy, Clone)]
514pub struct AdapterEvent {
515    /// A handle to the network adapter associated with this event.
516    pub adapter_handle: HANDLE,
517    /// A handle to the event associated with this adapter.
518    pub event_handle: HANDLE,
519}
520
521/// This structure is used to make queries or set parameters on a network adapter.
522///
523/// A Rust equivalent for the [_PACKET_OID_DATA](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_packet_oid_data/) structure.
524#[repr(C, packed)]
525pub struct PacketOidData<T> {
526    /// A handle to the network adapter associated with this query or parameter setting.
527    pub adapter_handle: HANDLE,
528    /// The OID (Object Identifier) that represents the query or parameter to be set.
529    pub oid: u32,
530    /// The length of the data in bytes.
531    pub length: u32,
532    /// The data associated with the query or parameter.
533    pub data: T,
534}
535
536impl<T> PacketOidData<T> {
537    /// Creates a new PacketOidData instance.
538    ///
539    /// # Arguments
540    ///
541    /// * `adapter_handle` - A handle to the network adapter associated with this query or parameter setting.
542    /// * `oid` - The OID (Object Identifier) that represents the query or parameter to be set.
543    /// * `data` - The data associated with the query or parameter.
544    pub fn new(adapter_handle: HANDLE, oid: u32, data: T) -> Self {
545        Self {
546            adapter_handle,
547            oid,
548            length: size_of::<T>() as u32,
549            data,
550        }
551    }
552}
553
554/// This structure contains information about a RAS (Remote Access Service) link.
555///
556/// A Rust equivalent for the [_RAS_LINK_INFO](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ras_link_info/) structure.
557#[repr(C, packed)]
558#[derive(Debug, Copy, Clone)]
559pub struct RasLinkInformation {
560    /// The link speed in bits per second.
561    link_speed: u32,
562    /// The maximum total size, in bytes.
563    maximum_total_size: u32,
564    /// The remote MAC address.
565    remote_address: [u8; ETHER_ADDR_LENGTH],
566    /// The local MAC address.
567    local_address: [u8; ETHER_ADDR_LENGTH],
568    /// The length of the protocol buffer, in bytes.
569    protocol_buffer_length: u32,
570    /// The buffer containing information about the RAS-managed protocols.
571    protocol_buffer: [u8; RAS_LINK_BUFFER_LENGTH],
572}
573
574impl RasLinkInformation {
575    /// Returns the link speed in bits per second.
576    pub fn get_link_speed(&self) -> u32 {
577        self.link_speed
578    }
579
580    /// Returns the maximum total size.
581    pub fn get_maximum_total_size(&self) -> u32 {
582        self.maximum_total_size
583    }
584
585    /// Returns the remote MAC address.
586    pub fn get_remote_address(&self) -> &[u8; ETHER_ADDR_LENGTH] {
587        &self.remote_address
588    }
589
590    /// Returns the local MAC address.
591    pub fn get_local_address(&self) -> &[u8; ETHER_ADDR_LENGTH] {
592        &self.local_address
593    }
594
595    /// Returns the length of the protocol buffer, in bytes.
596    pub fn get_protocol_buffer_length(&self) -> usize {
597        self.protocol_buffer_length as usize
598    }
599
600    /// Returns the buffer containing information about the RAS-managed protocols.
601    pub fn get_protocol_buffer(&self) -> &[u8; RAS_LINK_BUFFER_LENGTH] {
602        &self.protocol_buffer
603    }
604}
605
606/// This structure is a container for RAS (Remote Access Service) link information structures.
607///
608/// A Rust equivalent for the [_RAS_LINKS](https://www.ntkernel.com/docs/windows-packet-filter-documentation/structures/_ras_links/) structure.
609/// Note that this struct may be too large to be allocated on the stack in Rust and may result in a stack overflow.
610#[repr(C, packed)]
611#[derive(Debug, Copy, Clone)]
612pub struct RasLinks {
613    /// The number of RAS links in the array.
614    number_of_links: u32,
615    /// The array of RAS link information structures.
616    pub ras_links: [RasLinkInformation; RAS_LINKS_MAX],
617}
618
619impl Default for RasLinks {
620    /// Returns a zero-initialized instance of `RasLinks`.
621    ///
622    /// # Safety
623    ///
624    /// This structure is filled by the information by NDIS filter driver when passed as a memory buffer
625    /// along with IOCTL_NDISRD_GET_RAS_LINKS. It is safe to be zeroed because contains only values and arrays that
626    /// can be default initialized with zeroes.
627    fn default() -> Self {
628        unsafe { std::mem::zeroed() }
629    }
630}
631
632impl RasLinks {
633    /// Returns the number of RAS links in the array.
634    pub fn get_number_of_links(&self) -> usize {
635        self.number_of_links as usize
636    }
637}
638
639#[cfg(test)]
640mod tests {
641    use super::*;
642
643    #[test]
644    fn size_of_ethpacket() {
645        assert_eq!(
646            std::mem::size_of::<*mut IntermediateBuffer>(),
647            std::mem::size_of::<EthPacket>()
648        );
649    }
650
651    #[test]
652    fn size_of_ethrequest() {
653        assert_eq!(
654            std::mem::size_of::<EthPacket>() + std::mem::size_of::<HANDLE>(),
655            std::mem::size_of::<EthRequest>()
656        );
657    }
658
659    #[test]
660    fn size_of_ethmrequest() {
661        assert_eq!(
662            std::mem::size_of::<EthPacket>()
663                + std::mem::size_of::<HANDLE>()
664                + 2 * std::mem::size_of::<u32>(),
665            std::mem::size_of::<EthMRequest<1>>()
666        );
667    }
668}