From f978a8e822bff95c88dcf76598d36cb0b51c1f04 Mon Sep 17 00:00:00 2001 From: Jarl Evanson Date: Mon, 14 Apr 2025 23:42:09 -0500 Subject: [PATCH] uefi-raw: Move EFI_SIMPLE_NETWORK_PROTOCOL --- uefi-raw/src/protocol/network/mod.rs | 1 + uefi-raw/src/protocol/network/snp.rs | 408 ++++++++++++++++ uefi-test-runner/src/proto/network/snp.rs | 4 +- uefi/src/proto/network/snp.rs | 570 +++++----------------- 4 files changed, 524 insertions(+), 459 deletions(-) create mode 100644 uefi-raw/src/protocol/network/snp.rs diff --git a/uefi-raw/src/protocol/network/mod.rs b/uefi-raw/src/protocol/network/mod.rs index a1dd5467c..f2a016cfc 100644 --- a/uefi-raw/src/protocol/network/mod.rs +++ b/uefi-raw/src/protocol/network/mod.rs @@ -5,4 +5,5 @@ pub mod http; pub mod ip4; pub mod ip4_config2; pub mod pxe; +pub mod snp; pub mod tls; diff --git a/uefi-raw/src/protocol/network/snp.rs b/uefi-raw/src/protocol/network/snp.rs new file mode 100644 index 000000000..7332567fe --- /dev/null +++ b/uefi-raw/src/protocol/network/snp.rs @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use core::ffi; + +use bitflags::bitflags; + +use crate::{guid, Boolean, Event, Guid, IpAddress, MacAddress, Status}; + +#[derive(Debug)] +#[repr(C)] +pub struct SimpleNetworkProtocol { + pub revision: u64, + pub start: unsafe extern "efiapi" fn(this: *const Self) -> Status, + pub stop: unsafe extern "efiapi" fn(this: *const Self) -> Status, + pub initialize: unsafe extern "efiapi" fn( + this: *const Self, + extra_receive_buffer_size: usize, + extra_transmit_buffer_size: usize, + ) -> Status, + pub reset: + unsafe extern "efiapi" fn(this: *const Self, extended_verification: Boolean) -> Status, + pub shutdown: unsafe extern "efiapi" fn(this: *const Self) -> Status, + pub receive_filters: unsafe extern "efiapi" fn( + this: *const Self, + enable: ReceiveFlags, + disable: ReceiveFlags, + reset_multicast_filter: Boolean, + multicast_filter_count: usize, + multicast_filter: *const MacAddress, + ) -> Status, + pub station_address: unsafe extern "efiapi" fn( + this: *const Self, + reset: Boolean, + new: *const MacAddress, + ) -> Status, + pub statistics: unsafe extern "efiapi" fn( + this: *const Self, + reset: Boolean, + statistics_size: *mut usize, + statistics_table: *mut NetworkStatistics, + ) -> Status, + pub multicast_ip_to_mac: unsafe extern "efiapi" fn( + this: *const Self, + ipv6: Boolean, + ip: *const IpAddress, + mac: *mut MacAddress, + ) -> Status, + pub non_volatile_data: unsafe extern "efiapi" fn( + this: *const Self, + read: Boolean, + offset: usize, + buffer_size: usize, + buffer: *mut ffi::c_void, + ) -> Status, + pub get_status: unsafe extern "efiapi" fn( + this: *const Self, + interrupt_status: *mut InterruptStatus, + transmit_buffer: *mut *mut ffi::c_void, + ) -> Status, + pub transmit: unsafe extern "efiapi" fn( + this: *const Self, + header_size: usize, + buffer_size: usize, + buffer: *const ffi::c_void, + source_address: *const MacAddress, + dest_address: *const MacAddress, + protocol: *const u16, + ) -> Status, + pub receive: unsafe extern "efiapi" fn( + this: *const Self, + header_size: *mut usize, + buffer_size: *mut usize, + buffer: *mut ffi::c_void, + source_address: *mut MacAddress, + dest_address: *mut MacAddress, + protocol: *mut u16, + ) -> Status, + pub wait_for_packet: Event, + pub mode: *mut NetworkMode, +} + +impl SimpleNetworkProtocol { + pub const GUID: Guid = guid!("a19832b9-ac25-11d3-9a2d-0090273fc14d"); +} + +bitflags! { + /// Flags to pass to receive_filters to enable/disable reception of some kinds of packets. + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct ReceiveFlags: u32 { + /// Receive unicast packets. + const UNICAST = 0x01; + /// Receive multicast packets. + const MULTICAST = 0x02; + /// Receive broadcast packets. + const BROADCAST = 0x04; + /// Receive packets in promiscuous mode. + const PROMISCUOUS = 0x08; + /// Receive packets in promiscuous multicast mode. + const PROMISCUOUS_MULTICAST = 0x10; + } +} + +bitflags! { + /// Flags returned by get_interrupt_status to indicate which interrupts have fired on the + /// interface since the last call. + #[repr(transparent)] + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] + pub struct InterruptStatus: u32 { + /// Packet received. + const RECEIVE = 0x01; + /// Packet transmitted. + const TRANSMIT = 0x02; + /// Command interrupt fired. + const COMMAND = 0x04; + /// Software interrupt fired. + const SOFTWARE = 0x08; + } +} + +/// Network Statistics +/// +/// The description of statistics on the network with the SNP's `statistics` function +/// is returned in this structure +/// +/// Any of these statistics may or may not be available on the device. So, all the +/// retriever functions of the statistics return `None` when a statistic is not supported +#[repr(C)] +#[derive(Default, Debug)] +pub struct NetworkStatistics { + pub rx_total_frames: u64, + pub rx_good_frames: u64, + pub rx_undersize_frames: u64, + pub rx_oversize_frames: u64, + pub rx_dropped_frames: u64, + pub rx_unicast_frames: u64, + pub rx_broadcast_frames: u64, + pub rx_multicast_frames: u64, + pub rx_crc_error_frames: u64, + pub rx_total_bytes: u64, + pub tx_total_frames: u64, + pub tx_good_frames: u64, + pub tx_undersize_frames: u64, + pub tx_oversize_frames: u64, + pub tx_dropped_frames: u64, + pub tx_unicast_frames: u64, + pub tx_broadcast_frames: u64, + pub tx_multicast_frames: u64, + pub tx_crc_error_frames: u64, + pub tx_total_bytes: u64, + pub collisions: u64, + pub unsupported_protocol: u64, + pub rx_duplicated_frames: u64, + pub rx_decrypt_error_frames: u64, + pub tx_error_frames: u64, + pub tx_retry_frames: u64, +} + +impl NetworkStatistics { + /// Any statistic value of -1 is not available + const fn available(&self, stat: u64) -> bool { + stat as i64 != -1 + } + + /// Takes a statistic and converts it to an option + /// + /// When the statistic is not available, `None` is returned + const fn to_option(&self, stat: u64) -> Option { + match self.available(stat) { + true => Some(stat), + false => None, + } + } + + /// The total number of frames received, including error frames + /// and dropped frames + #[must_use] + pub const fn rx_total_frames(&self) -> Option { + self.to_option(self.rx_total_frames) + } + + /// The total number of good frames received and copied + /// into receive buffers + #[must_use] + pub const fn rx_good_frames(&self) -> Option { + self.to_option(self.rx_good_frames) + } + + /// The number of frames below the minimum length for the + /// communications device + #[must_use] + pub const fn rx_undersize_frames(&self) -> Option { + self.to_option(self.rx_undersize_frames) + } + + /// The number of frames longer than the maximum length for + /// the communications length device + #[must_use] + pub const fn rx_oversize_frames(&self) -> Option { + self.to_option(self.rx_oversize_frames) + } + + /// The number of valid frames that were dropped because + /// the receive buffers were full + #[must_use] + pub const fn rx_dropped_frames(&self) -> Option { + self.to_option(self.rx_dropped_frames) + } + + /// The number of valid unicast frames received and not dropped + #[must_use] + pub const fn rx_unicast_frames(&self) -> Option { + self.to_option(self.rx_unicast_frames) + } + + /// The number of valid broadcast frames received and not dropped + #[must_use] + pub const fn rx_broadcast_frames(&self) -> Option { + self.to_option(self.rx_broadcast_frames) + } + + /// The number of valid multicast frames received and not dropped + #[must_use] + pub const fn rx_multicast_frames(&self) -> Option { + self.to_option(self.rx_multicast_frames) + } + + /// Number of frames with CRC or alignment errors + #[must_use] + pub const fn rx_crc_error_frames(&self) -> Option { + self.to_option(self.rx_crc_error_frames) + } + + /// The total number of bytes received including frames with errors + /// and dropped frames + #[must_use] + pub const fn rx_total_bytes(&self) -> Option { + self.to_option(self.rx_total_bytes) + } + + /// The total number of frames transmitted including frames + /// with errors and dropped frames + #[must_use] + pub const fn tx_total_frames(&self) -> Option { + self.to_option(self.tx_total_frames) + } + + /// The total number of valid frames transmitted and copied + /// into receive buffers + #[must_use] + pub const fn tx_good_frames(&self) -> Option { + self.to_option(self.tx_good_frames) + } + + /// The number of frames below the minimum length for + /// the media. This would be less than 64 for Ethernet + #[must_use] + pub const fn tx_undersize_frames(&self) -> Option { + self.to_option(self.tx_undersize_frames) + } + + /// The number of frames longer than the maximum length for + /// the media. This would be 1500 for Ethernet + #[must_use] + pub const fn tx_oversize_frames(&self) -> Option { + self.to_option(self.tx_oversize_frames) + } + + /// The number of valid frames that were dropped because + /// received buffers were full + #[must_use] + pub const fn tx_dropped_frames(&self) -> Option { + self.to_option(self.tx_dropped_frames) + } + + /// The number of valid unicast frames transmitted and not + /// dropped + #[must_use] + pub const fn tx_unicast_frames(&self) -> Option { + self.to_option(self.tx_unicast_frames) + } + + /// The number of valid broadcast frames transmitted and + /// not dropped + #[must_use] + pub const fn tx_broadcast_frames(&self) -> Option { + self.to_option(self.tx_broadcast_frames) + } + + /// The number of valid multicast frames transmitted + /// and not dropped + #[must_use] + pub const fn tx_multicast_frames(&self) -> Option { + self.to_option(self.tx_multicast_frames) + } + + /// The number of transmitted frames with CRC or + /// alignment errors + #[must_use] + pub const fn tx_crc_error_frames(&self) -> Option { + self.to_option(self.tx_crc_error_frames) + } + + /// The total number of bytes transmitted including + /// error frames and dropped frames + #[must_use] + pub const fn tx_total_bytes(&self) -> Option { + self.to_option(self.tx_total_bytes) + } + + /// The number of collisions detected on this subnet + #[must_use] + pub const fn collisions(&self) -> Option { + self.to_option(self.collisions) + } + + /// The number of frames destined for unsupported protocol + #[must_use] + pub const fn unsupported_protocol(&self) -> Option { + self.to_option(self.unsupported_protocol) + } + + /// The number of valid frames received that were duplicated + #[must_use] + pub const fn rx_duplicated_frames(&self) -> Option { + self.to_option(self.rx_duplicated_frames) + } + + /// The number of encrypted frames received that failed + /// to decrypt + #[must_use] + pub const fn rx_decrypt_error_frames(&self) -> Option { + self.to_option(self.rx_decrypt_error_frames) + } + + /// The number of frames that failed to transmit after + /// exceeding the retry limit + #[must_use] + pub const fn tx_error_frames(&self) -> Option { + self.to_option(self.tx_error_frames) + } + + /// The number of frames that transmitted successfully + /// after more than one attempt + #[must_use] + pub const fn tx_retry_frames(&self) -> Option { + self.to_option(self.tx_retry_frames) + } +} + +/// Information about the current configuration of an interface obtained by the +/// [`SimpleNetworkProtocol`]. +#[repr(C)] +#[derive(Debug)] +pub struct NetworkMode { + /// Reports the current state of the network interface + pub state: NetworkState, + /// The size of the network interface's hardware address in bytes + pub hw_address_size: u32, + /// The size of the network interface's media header in bytes + pub media_header_size: u32, + /// The maximum size of the packets supported by the network interface in bytes + pub max_packet_size: u32, + /// The size of the NVRAM device attached to the network interface in bytes + pub nv_ram_size: u32, + /// The size that must be used for all NVRAM reads and writes + pub nv_ram_access_size: u32, + /// The multicast receive filter settings supported by the network interface + pub receive_filter_mask: u32, + /// The current multicast receive filter settings + pub receive_filter_setting: u32, + /// The maximum number of multicast address receive filters supported by the driver + pub max_mcast_filter_count: u32, + /// The current number of multicast address receive filters + pub mcast_filter_count: u32, + /// The array containing the addresses of the current multicast address receive filters + pub mcast_filter: [MacAddress; 16], + /// The current hardware MAC address for the network interface + pub current_address: MacAddress, + /// The current hardware MAC address for broadcast packets + pub broadcast_address: MacAddress, + /// The permanent hardware MAC address for the network interface + pub permanent_address: MacAddress, + /// The interface type of the network interface + pub if_type: u8, + /// Tells if the MAC address can be changed + pub mac_address_changeable: Boolean, + /// Tells if the network interface can transmit more than one packet at a time + pub multiple_tx_supported: Boolean, + /// Tells if the presence of the media can be determined + pub media_present_supported: Boolean, + /// Tells if media are connected to the network interface + pub media_present: Boolean, +} + +newtype_enum! { + /// The state of a network interface. + pub enum NetworkState: u32 => { + /// The interface has been stopped + STOPPED = 0, + /// The interface has been started + STARTED = 1, + /// The interface has been initialized + INITIALIZED = 2, + /// No state can have a number higher than this + MAX_STATE = 4, + } +} diff --git a/uefi-test-runner/src/proto/network/snp.rs b/uefi-test-runner/src/proto/network/snp.rs index 1bdaab20e..a0c2ccba4 100644 --- a/uefi-test-runner/src/proto/network/snp.rs +++ b/uefi-test-runner/src/proto/network/snp.rs @@ -53,7 +53,9 @@ pub fn test() { .expect("Failed to set receive filters"); // Check media - if !simple_network.mode().media_present_supported || !simple_network.mode().media_present { + if !bool::from(simple_network.mode().media_present_supported) + || !bool::from(simple_network.mode().media_present) + { continue; } diff --git a/uefi/src/proto/network/snp.rs b/uefi/src/proto/network/snp.rs index d9563a832..208477d59 100644 --- a/uefi/src/proto/network/snp.rs +++ b/uefi/src/proto/network/snp.rs @@ -12,108 +12,52 @@ use super::{IpAddress, MacAddress}; use crate::data_types::Event; use crate::proto::unsafe_protocol; -use crate::{Result, Status, StatusExt}; -use bitflags::bitflags; +use crate::{Result, StatusExt}; use core::ffi::c_void; use core::ptr; use core::ptr::NonNull; +use uefi_raw::protocol::network::snp::SimpleNetworkProtocol; +use uefi_raw::Boolean; + +pub use uefi_raw::protocol::network::snp::{ + InterruptStatus, NetworkMode, NetworkState, NetworkStatistics, ReceiveFlags, +}; /// The Simple Network Protocol #[derive(Debug)] -#[repr(C)] -#[unsafe_protocol("a19832b9-ac25-11d3-9a2d-0090273fc14d")] -pub struct SimpleNetwork { - revision: u64, - start: extern "efiapi" fn(this: &Self) -> Status, - stop: extern "efiapi" fn(this: &Self) -> Status, - initialize: extern "efiapi" fn( - this: &Self, - extra_recv_buffer_size: usize, - extra_transmit_buffer_size: usize, - ) -> Status, - reset: extern "efiapi" fn(this: &Self, extended_verification: bool) -> Status, - shutdown: extern "efiapi" fn(this: &Self) -> Status, - receive_filters: extern "efiapi" fn( - this: &Self, - enable: u32, - disable: u32, - reset_mcast_filter: bool, - mcast_filter_count: usize, - mcast_filter: Option>, - ) -> Status, - station_address: - extern "efiapi" fn(this: &Self, reset: bool, new: Option<&MacAddress>) -> Status, - statistics: extern "efiapi" fn( - this: &Self, - reset: bool, - stats_size: Option<&mut usize>, - stats_table: Option<&mut NetworkStats>, - ) -> Status, - mcast_ip_to_mac: - extern "efiapi" fn(this: &Self, ipv6: bool, ip: &IpAddress, mac: &mut MacAddress) -> Status, - nv_data: extern "efiapi" fn( - this: &Self, - read_write: bool, - offset: usize, - buffer_size: usize, - buffer: *mut c_void, - ) -> Status, - get_status: extern "efiapi" fn( - this: &Self, - interrupt_status: Option<&mut InterruptStatus>, - tx_buf: Option<&mut *mut c_void>, - ) -> Status, - transmit: extern "efiapi" fn( - this: &Self, - header_size: usize, - buffer_size: usize, - buffer: *const c_void, - src_addr: Option<&MacAddress>, - dest_addr: Option<&MacAddress>, - protocol: Option<&u16>, - ) -> Status, - receive: extern "efiapi" fn( - this: &Self, - header_size: Option<&mut usize>, - buffer_size: &mut usize, - buffer: *mut c_void, - src_addr: Option<&mut MacAddress>, - dest_addr: Option<&mut MacAddress>, - protocol: Option<&mut u16>, - ) -> Status, - // On QEMU, this event seems to never fire. - wait_for_packet: Event, - mode: *const NetworkMode, -} +#[repr(transparent)] +#[unsafe_protocol(SimpleNetworkProtocol::GUID)] +pub struct SimpleNetwork(SimpleNetworkProtocol); impl SimpleNetwork { /// Change the state of a network from "Stopped" to "Started". pub fn start(&self) -> Result { - (self.start)(self).to_result() + unsafe { (self.0.start)(&self.0) }.to_result() } /// Change the state of a network interface from "Started" to "Stopped". pub fn stop(&self) -> Result { - (self.stop)(self).to_result() + unsafe { (self.0.stop)(&self.0) }.to_result() } /// Reset a network adapter and allocate the transmit and receive buffers /// required by the network interface; optionally, also request allocation of /// additional transmit and receive buffers. pub fn initialize(&self, extra_rx_buffer_size: usize, extra_tx_buffer_size: usize) -> Result { - (self.initialize)(self, extra_rx_buffer_size, extra_tx_buffer_size).to_result() + unsafe { (self.0.initialize)(&self.0, extra_rx_buffer_size, extra_tx_buffer_size) } + .to_result() } /// Reset a network adapter and reinitialize it with the parameters that were /// provided in the previous call to `initialize`. pub fn reset(&self, extended_verification: bool) -> Result { - (self.reset)(self, extended_verification).to_result() + unsafe { (self.0.reset)(&self.0, Boolean::from(extended_verification)) }.to_result() } /// Reset a network adapter, leaving it in a state that is safe /// for another driver to initialize pub fn shutdown(&self) -> Result { - (self.shutdown)(self).to_result() + unsafe { (self.0.shutdown)(&self.0) }.to_result() } /// Manage the multicast receive filters of a network. @@ -124,76 +68,104 @@ impl SimpleNetwork { reset_mcast_filter: bool, mcast_filter: Option<&[MacAddress]>, ) -> Result { - if let Some(mcast_filter) = mcast_filter { - (self.receive_filters)( - self, - enable.bits(), - disable.bits(), - reset_mcast_filter, - mcast_filter.len(), - NonNull::new(mcast_filter.as_ptr() as *mut _), - ) - .to_result() - } else { - (self.receive_filters)( - self, - enable.bits(), - disable.bits(), - reset_mcast_filter, - 0, - None, + let filter_count = mcast_filter.map(|filters| filters.len()).unwrap_or(0); + let filters = mcast_filter + .map(|filters| filters.as_ptr()) + .unwrap_or(core::ptr::null_mut()); + + unsafe { + (self.0.receive_filters)( + &self.0, + enable, + disable, + Boolean::from(reset_mcast_filter), + filter_count, + filters, ) - .to_result() } + .to_result() } /// Modify or reset the current station address, if supported. pub fn station_address(&self, reset: bool, new: Option<&MacAddress>) -> Result { - (self.station_address)(self, reset, new).to_result() + unsafe { + (self.0.station_address)( + &self.0, + Boolean::from(reset), + new.map(ptr::from_ref).unwrap_or(ptr::null()), + ) + } + .to_result() } /// Reset statistics on a network interface. pub fn reset_statistics(&self) -> Result { - (self.statistics)(self, true, None, None).to_result() + unsafe { + (self.0.statistics)( + &self.0, + Boolean::from(true), + ptr::null_mut(), + ptr::null_mut(), + ) + } + .to_result() } /// Collect statistics on a network interface. - pub fn collect_statistics(&self) -> Result { - let mut stats_table: NetworkStats = Default::default(); - let mut stats_size = size_of::(); - let status = (self.statistics)(self, false, Some(&mut stats_size), Some(&mut stats_table)); + pub fn collect_statistics(&self) -> Result { + let mut stats_table: NetworkStatistics = Default::default(); + let mut stats_size = size_of::(); + let status = unsafe { + (self.0.statistics)( + &self.0, + Boolean::from(false), + &mut stats_size, + &mut stats_table, + ) + }; status.to_result_with_val(|| stats_table) } /// Convert a multicast IP address to a multicast HW MAC Address. pub fn mcast_ip_to_mac(&self, ipv6: bool, ip: IpAddress) -> Result { let mut mac_address = MacAddress([0; 32]); - let status = (self.mcast_ip_to_mac)(self, ipv6, &ip, &mut mac_address); + let status = unsafe { + (self.0.multicast_ip_to_mac)( + &self.0, + Boolean::from(ipv6), + ip.as_raw_ptr(), + &mut mac_address, + ) + }; status.to_result_with_val(|| mac_address) } /// Perform read operations on the NVRAM device attached to /// a network interface. pub fn read_nv_data(&self, offset: usize, buffer: &[u8]) -> Result { - (self.nv_data)( - self, - true, - offset, - buffer.len(), - buffer.as_ptr() as *mut c_void, - ) + unsafe { + (self.0.non_volatile_data)( + &self.0, + Boolean::from(true), + offset, + buffer.len(), + buffer.as_ptr() as *mut c_void, + ) + } .to_result() } /// Perform write operations on the NVRAM device attached to a network interface. pub fn write_nv_data(&self, offset: usize, buffer: &mut [u8]) -> Result { - (self.nv_data)( - self, - false, - offset, - buffer.len(), - buffer.as_mut_ptr().cast(), - ) + unsafe { + (self.0.non_volatile_data)( + &self.0, + Boolean::from(false), + offset, + buffer.len(), + buffer.as_mut_ptr().cast(), + ) + } .to_result() } @@ -201,7 +173,8 @@ impl SimpleNetwork { /// status from a network interface. pub fn get_interrupt_status(&self) -> Result { let mut interrupt_status = InterruptStatus::empty(); - let status = (self.get_status)(self, Some(&mut interrupt_status), None); + let status = + unsafe { (self.0.get_status)(&self.0, &mut interrupt_status, ptr::null_mut()) }; status.to_result_with_val(|| interrupt_status) } @@ -209,7 +182,7 @@ impl SimpleNetwork { /// network interface. pub fn get_recycled_transmit_buffer_status(&self) -> Result>> { let mut tx_buf: *mut c_void = ptr::null_mut(); - let status = (self.get_status)(self, None, Some(&mut tx_buf)); + let status = unsafe { (self.0.get_status)(&self.0, ptr::null_mut(), &mut tx_buf) }; status.to_result_with_val(|| NonNull::new(tx_buf.cast())) } @@ -222,15 +195,17 @@ impl SimpleNetwork { dest_addr: Option, protocol: Option, ) -> Result { - (self.transmit)( - self, - header_size, - buffer.len(), - buffer.as_ptr().cast(), - src_addr.as_ref(), - dest_addr.as_ref(), - protocol.as_ref(), - ) + unsafe { + (self.0.transmit)( + &self.0, + header_size, + buffer.len(), + buffer.as_ptr().cast(), + src_addr.as_ref().map(ptr::from_ref).unwrap_or(ptr::null()), + dest_addr.as_ref().map(ptr::from_ref).unwrap_or(ptr::null()), + protocol.as_ref().map(ptr::from_ref).unwrap_or(ptr::null()), + ) + } .to_result() } @@ -246,15 +221,17 @@ impl SimpleNetwork { protocol: Option<&mut u16>, ) -> Result { let mut buffer_size = buffer.len(); - let status = (self.receive)( - self, - header_size, - &mut buffer_size, - buffer.as_mut_ptr().cast(), - src_addr, - dest_addr, - protocol, - ); + let status = unsafe { + (self.0.receive)( + &self.0, + header_size.map(ptr::from_mut).unwrap_or(ptr::null_mut()), + &mut buffer_size, + buffer.as_mut_ptr().cast(), + src_addr.map(ptr::from_mut).unwrap_or(ptr::null_mut()), + dest_addr.map(ptr::from_mut).unwrap_or(ptr::null_mut()), + protocol.map(ptr::from_mut).unwrap_or(ptr::null_mut()), + ) + }; status.to_result_with_val(|| buffer_size) } @@ -264,335 +241,12 @@ impl SimpleNetwork { /// of UEFI properly implements this event before using it. #[must_use] pub const fn wait_for_packet(&self) -> &Event { - &self.wait_for_packet + unsafe { &*(ptr::from_ref(&self.0.wait_for_packet).cast::()) } } /// Returns a reference to the Simple Network mode. #[must_use] - pub const fn mode(&self) -> &NetworkMode { - unsafe { &*self.mode } - } -} - -bitflags! { - /// Flags to pass to receive_filters to enable/disable reception of some kinds of packets. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct ReceiveFlags : u32 { - /// Receive unicast packets. - const UNICAST = 0x01; - /// Receive multicast packets. - const MULTICAST = 0x02; - /// Receive broadcast packets. - const BROADCAST = 0x04; - /// Receive packets in promiscuous mode. - const PROMISCUOUS = 0x08; - /// Receive packets in promiscuous multicast mode. - const PROMISCUOUS_MULTICAST = 0x10; - } -} - -bitflags! { - /// Flags returned by get_interrupt_status to indicate which interrupts have fired on the - /// interface since the last call. - #[repr(transparent)] - #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] - pub struct InterruptStatus : u32 { - /// Packet received. - const RECEIVE = 0x01; - /// Packet transmitted. - const TRANSMIT = 0x02; - /// Command interrupt fired. - const COMMAND = 0x04; - /// Software interrupt fired. - const SOFTWARE = 0x08; - } -} - -/// Network Statistics -/// -/// The description of statistics on the network with the SNP's `statistics` function -/// is returned in this structure -/// -/// Any of these statistics may or may not be available on the device. So, all the -/// retriever functions of the statistics return `None` when a statistic is not supported -#[repr(C)] -#[derive(Default, Debug)] -pub struct NetworkStats { - rx_total_frames: u64, - rx_good_frames: u64, - rx_undersize_frames: u64, - rx_oversize_frames: u64, - rx_dropped_frames: u64, - rx_unicast_frames: u64, - rx_broadcast_frames: u64, - rx_multicast_frames: u64, - rx_crc_error_frames: u64, - rx_total_bytes: u64, - tx_total_frames: u64, - tx_good_frames: u64, - tx_undersize_frames: u64, - tx_oversize_frames: u64, - tx_dropped_frames: u64, - tx_unicast_frames: u64, - tx_broadcast_frames: u64, - tx_multicast_frames: u64, - tx_crc_error_frames: u64, - tx_total_bytes: u64, - collisions: u64, - unsupported_protocol: u64, - rx_duplicated_frames: u64, - rx_decrypt_error_frames: u64, - tx_error_frames: u64, - tx_retry_frames: u64, -} - -impl NetworkStats { - /// Any statistic value of -1 is not available - const fn available(&self, stat: u64) -> bool { - stat as i64 != -1 - } - - /// Takes a statistic and converts it to an option - /// - /// When the statistic is not available, `None` is returned - const fn to_option(&self, stat: u64) -> Option { - match self.available(stat) { - true => Some(stat), - false => None, - } - } - - /// The total number of frames received, including error frames - /// and dropped frames - #[must_use] - pub const fn rx_total_frames(&self) -> Option { - self.to_option(self.rx_total_frames) - } - - /// The total number of good frames received and copied - /// into receive buffers - #[must_use] - pub const fn rx_good_frames(&self) -> Option { - self.to_option(self.rx_good_frames) - } - - /// The number of frames below the minimum length for the - /// communications device - #[must_use] - pub const fn rx_undersize_frames(&self) -> Option { - self.to_option(self.rx_undersize_frames) - } - - /// The number of frames longer than the maximum length for - /// the communications length device - #[must_use] - pub const fn rx_oversize_frames(&self) -> Option { - self.to_option(self.rx_oversize_frames) - } - - /// The number of valid frames that were dropped because - /// the receive buffers were full - #[must_use] - pub const fn rx_dropped_frames(&self) -> Option { - self.to_option(self.rx_dropped_frames) - } - - /// The number of valid unicast frames received and not dropped - #[must_use] - pub const fn rx_unicast_frames(&self) -> Option { - self.to_option(self.rx_unicast_frames) - } - - /// The number of valid broadcast frames received and not dropped - #[must_use] - pub const fn rx_broadcast_frames(&self) -> Option { - self.to_option(self.rx_broadcast_frames) - } - - /// The number of valid multicast frames received and not dropped - #[must_use] - pub const fn rx_multicast_frames(&self) -> Option { - self.to_option(self.rx_multicast_frames) - } - - /// Number of frames with CRC or alignment errors - #[must_use] - pub const fn rx_crc_error_frames(&self) -> Option { - self.to_option(self.rx_crc_error_frames) - } - - /// The total number of bytes received including frames with errors - /// and dropped frames - #[must_use] - pub const fn rx_total_bytes(&self) -> Option { - self.to_option(self.rx_total_bytes) - } - - /// The total number of frames transmitted including frames - /// with errors and dropped frames - #[must_use] - pub const fn tx_total_frames(&self) -> Option { - self.to_option(self.tx_total_frames) - } - - /// The total number of valid frames transmitted and copied - /// into receive buffers - #[must_use] - pub const fn tx_good_frames(&self) -> Option { - self.to_option(self.tx_good_frames) - } - - /// The number of frames below the minimum length for - /// the media. This would be less than 64 for Ethernet - #[must_use] - pub const fn tx_undersize_frames(&self) -> Option { - self.to_option(self.tx_undersize_frames) - } - - /// The number of frames longer than the maximum length for - /// the media. This would be 1500 for Ethernet - #[must_use] - pub const fn tx_oversize_frames(&self) -> Option { - self.to_option(self.tx_oversize_frames) - } - - /// The number of valid frames that were dropped because - /// received buffers were full - #[must_use] - pub const fn tx_dropped_frames(&self) -> Option { - self.to_option(self.tx_dropped_frames) - } - - /// The number of valid unicast frames transmitted and not - /// dropped - #[must_use] - pub const fn tx_unicast_frames(&self) -> Option { - self.to_option(self.tx_unicast_frames) - } - - /// The number of valid broadcast frames transmitted and - /// not dropped - #[must_use] - pub const fn tx_broadcast_frames(&self) -> Option { - self.to_option(self.tx_broadcast_frames) - } - - /// The number of valid multicast frames transmitted - /// and not dropped - #[must_use] - pub const fn tx_multicast_frames(&self) -> Option { - self.to_option(self.tx_multicast_frames) - } - - /// The number of transmitted frames with CRC or - /// alignment errors - #[must_use] - pub const fn tx_crc_error_frames(&self) -> Option { - self.to_option(self.tx_crc_error_frames) - } - - /// The total number of bytes transmitted including - /// error frames and dropped frames - #[must_use] - pub const fn tx_total_bytes(&self) -> Option { - self.to_option(self.tx_total_bytes) - } - - /// The number of collisions detected on this subnet - #[must_use] - pub const fn collisions(&self) -> Option { - self.to_option(self.collisions) - } - - /// The number of frames destined for unsupported protocol - #[must_use] - pub const fn unsupported_protocol(&self) -> Option { - self.to_option(self.unsupported_protocol) - } - - /// The number of valid frames received that were duplicated - #[must_use] - pub const fn rx_duplicated_frames(&self) -> Option { - self.to_option(self.rx_duplicated_frames) - } - - /// The number of encrypted frames received that failed - /// to decrypt - #[must_use] - pub const fn rx_decrypt_error_frames(&self) -> Option { - self.to_option(self.rx_decrypt_error_frames) - } - - /// The number of frames that failed to transmit after - /// exceeding the retry limit - #[must_use] - pub const fn tx_error_frames(&self) -> Option { - self.to_option(self.tx_error_frames) - } - - /// The number of frames that transmitted successfully - /// after more than one attempt - #[must_use] - pub const fn tx_retry_frames(&self) -> Option { - self.to_option(self.tx_retry_frames) - } -} - -/// The Simple Network Mode -#[repr(C)] -#[derive(Debug)] -pub struct NetworkMode { - /// Reports the current state of the network interface - pub state: NetworkState, - /// The size of the network interface's hardware address in bytes - pub hw_address_size: u32, - /// The size of the network interface's media header in bytes - pub media_header_size: u32, - /// The maximum size of the packets supported by the network interface in bytes - pub max_packet_size: u32, - /// The size of the NVRAM device attached to the network interface in bytes - pub nv_ram_size: u32, - /// The size that must be used for all NVRAM reads and writes - pub nv_ram_access_size: u32, - /// The multicast receive filter settings supported by the network interface - pub receive_filter_mask: u32, - /// The current multicast receive filter settings - pub receive_filter_setting: u32, - /// The maximum number of multicast address receive filters supported by the driver - pub max_mcast_filter_count: u32, - /// The current number of multicast address receive filters - pub mcast_filter_count: u32, - /// The array containing the addresses of the current multicast address receive filters - pub mcast_filter: [MacAddress; 16], - /// The current hardware MAC address for the network interface - pub current_address: MacAddress, - /// The current hardware MAC address for broadcast packets - pub broadcast_address: MacAddress, - /// The permanent hardware MAC address for the network interface - pub permanent_address: MacAddress, - /// The interface type of the network interface - pub if_type: u8, - /// Tells if the MAC address can be changed - pub mac_address_changeable: bool, - /// Tells if the network interface can transmit more than one packet at a time - pub multiple_tx_supported: bool, - /// Tells if the presence of the media can be determined - pub media_present_supported: bool, - /// Tells if media are connected to the network interface - pub media_present: bool, -} - -newtype_enum! { - /// The state of a network interface. - pub enum NetworkState: u32 => { - /// The interface has been stopped - STOPPED = 0, - /// The interface has been started - STARTED = 1, - /// The interface has been initialized - INITIALIZED = 2, - /// No state can have a number higher than this - MAX_STATE = 4, + pub fn mode(&self) -> &NetworkMode { + unsafe { &*self.0.mode } } }