use super::{IpAddress, MacAddress};
use crate::data_types::Event;
use crate::{Result, Status};
use bitflags::bitflags;
use core::ffi::c_void;
use core::ptr;
use core::ptr::NonNull;
use uefi_macros::unsafe_protocol;
#[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<NonNull<MacAddress>>,
) -> 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,
wait_for_packet: Event,
mode: *const NetworkMode,
}
impl SimpleNetwork {
pub fn start(&self) -> Result {
(self.start)(self).into()
}
pub fn stop(&self) -> Result {
(self.stop)(self).into()
}
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).into()
}
pub fn reset(&self, extended_verification: bool) -> Result {
(self.reset)(self, extended_verification).into()
}
pub fn shutdown(&self) -> Result {
(self.shutdown)(self).into()
}
pub fn receive_filters(
&self,
enable: ReceiveFlags,
disable: ReceiveFlags,
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 _),
)
.into()
} else {
(self.receive_filters)(self, enable.bits, disable.bits, reset_mcast_filter, 0, None)
.into()
}
}
pub fn station_address(&self, reset: bool, new: Option<&MacAddress>) -> Result {
(self.station_address)(self, reset, new).into()
}
pub fn reset_statistics(&self) -> Result {
(self.statistics)(self, true, None, None).into()
}
pub fn collect_statistics(&self) -> Result<NetworkStats> {
let mut stats_table: NetworkStats = Default::default();
let mut stats_size = core::mem::size_of::<NetworkStats>();
let status = (self.statistics)(self, false, Some(&mut stats_size), Some(&mut stats_table));
Result::from(status)?;
Ok(stats_table)
}
pub fn mcast_ip_to_mac(&self, ipv6: bool, ip: IpAddress) -> Result<MacAddress> {
let mut mac_address = MacAddress([0; 32]);
let status = (self.mcast_ip_to_mac)(self, ipv6, &ip, &mut mac_address);
Result::from(status)?;
Ok(mac_address)
}
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,
)
.into()
}
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(),
)
.into()
}
pub fn get_interrupt_status(&self) -> Result<InterruptStatus> {
let mut interrupt_status = InterruptStatus::empty();
let status = (self.get_status)(self, Some(&mut interrupt_status), None);
Result::from(status)?;
Ok(interrupt_status)
}
pub fn get_recycled_transmit_buffer_status(&self) -> Result<Option<NonNull<u8>>> {
let mut tx_buf: *mut c_void = ptr::null_mut();
let status = (self.get_status)(self, None, Some(&mut tx_buf));
Result::from(status)?;
Ok(NonNull::new(tx_buf.cast()))
}
pub fn transmit(
&self,
header_size: usize,
buffer: &[u8],
src_addr: Option<MacAddress>,
dest_addr: Option<MacAddress>,
protocol: Option<u16>,
) -> Result {
(self.transmit)(
self,
header_size,
buffer.len() + header_size,
buffer.as_ptr().cast(),
src_addr.as_ref(),
dest_addr.as_ref(),
protocol.as_ref(),
)
.into()
}
pub fn receive(
&self,
buffer: &mut [u8],
header_size: Option<&mut usize>,
src_addr: Option<&mut MacAddress>,
dest_addr: Option<&mut MacAddress>,
protocol: Option<&mut u16>,
) -> Result<usize> {
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,
);
Result::from(status)?;
Ok(buffer_size)
}
#[must_use]
pub fn wait_for_packet(&self) -> &Event {
&self.wait_for_packet
}
#[must_use]
pub fn mode(&self) -> &NetworkMode {
unsafe { &*self.mode }
}
}
bitflags! {
pub struct ReceiveFlags : u32 {
const UNICAST = 0x01;
const MULTICAST = 0x02;
const BROADCAST = 0x04;
const PROMISCUOUS = 0x08;
const PROMISCUOUS_MULTICAST = 0x10;
}
}
bitflags! {
pub struct InterruptStatus : u32 {
const RECEIVE = 0x01;
const TRANSMIT = 0x02;
const COMMAND = 0x04;
const SOFTWARE = 0x08;
}
}
#[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 {
fn available(&self, stat: u64) -> bool {
stat as i64 != -1
}
fn to_option(&self, stat: u64) -> Option<u64> {
match self.available(stat) {
true => Some(stat),
false => None,
}
}
#[must_use]
pub fn rx_total_frames(&self) -> Option<u64> {
self.to_option(self.rx_total_frames)
}
#[must_use]
pub fn rx_good_frames(&self) -> Option<u64> {
self.to_option(self.rx_good_frames)
}
#[must_use]
pub fn rx_undersize_frames(&self) -> Option<u64> {
self.to_option(self.rx_undersize_frames)
}
#[must_use]
pub fn rx_oversize_frames(&self) -> Option<u64> {
self.to_option(self.rx_oversize_frames)
}
#[must_use]
pub fn rx_dropped_frames(&self) -> Option<u64> {
self.to_option(self.rx_dropped_frames)
}
#[must_use]
pub fn rx_unicast_frames(&self) -> Option<u64> {
self.to_option(self.rx_unicast_frames)
}
#[must_use]
pub fn rx_broadcast_frames(&self) -> Option<u64> {
self.to_option(self.rx_broadcast_frames)
}
#[must_use]
pub fn rx_multicast_frames(&self) -> Option<u64> {
self.to_option(self.rx_multicast_frames)
}
#[must_use]
pub fn rx_crc_error_frames(&self) -> Option<u64> {
self.to_option(self.rx_crc_error_frames)
}
#[must_use]
pub fn rx_total_bytes(&self) -> Option<u64> {
self.to_option(self.rx_total_bytes)
}
#[must_use]
pub fn tx_total_frames(&self) -> Option<u64> {
self.to_option(self.tx_total_frames)
}
#[must_use]
pub fn tx_good_frames(&self) -> Option<u64> {
self.to_option(self.tx_good_frames)
}
#[must_use]
pub fn tx_undersize_frames(&self) -> Option<u64> {
self.to_option(self.tx_undersize_frames)
}
#[must_use]
pub fn tx_oversize_frames(&self) -> Option<u64> {
self.to_option(self.tx_oversize_frames)
}
#[must_use]
pub fn tx_dropped_frames(&self) -> Option<u64> {
self.to_option(self.tx_dropped_frames)
}
#[must_use]
pub fn tx_unicast_frames(&self) -> Option<u64> {
self.to_option(self.tx_unicast_frames)
}
#[must_use]
pub fn tx_broadcast_frames(&self) -> Option<u64> {
self.to_option(self.tx_broadcast_frames)
}
#[must_use]
pub fn tx_multicast_frames(&self) -> Option<u64> {
self.to_option(self.tx_multicast_frames)
}
#[must_use]
pub fn tx_crc_error_frames(&self) -> Option<u64> {
self.to_option(self.tx_crc_error_frames)
}
#[must_use]
pub fn tx_total_bytes(&self) -> Option<u64> {
self.to_option(self.tx_total_bytes)
}
#[must_use]
pub fn collisions(&self) -> Option<u64> {
self.to_option(self.collisions)
}
#[must_use]
pub fn unsupported_protocol(&self) -> Option<u64> {
self.to_option(self.unsupported_protocol)
}
#[must_use]
pub fn rx_duplicated_frames(&self) -> Option<u64> {
self.to_option(self.rx_duplicated_frames)
}
#[must_use]
pub fn rx_decrypt_error_frames(&self) -> Option<u64> {
self.to_option(self.rx_decrypt_error_frames)
}
#[must_use]
pub fn tx_error_frames(&self) -> Option<u64> {
self.to_option(self.tx_error_frames)
}
#[must_use]
pub fn tx_retry_frames(&self) -> Option<u64> {
self.to_option(self.tx_retry_frames)
}
}
#[repr(C)]
pub struct NetworkMode {
pub state: NetworkState,
pub hw_address_size: u32,
pub media_header_size: u32,
pub max_packet_size: u32,
pub nv_ram_size: u32,
pub nv_ram_access_size: u32,
pub receive_filter_mask: u32,
pub receive_filter_setting: u32,
pub max_mcast_filter_count: u32,
pub mcast_filter_count: u32,
pub mcast_filter: [MacAddress; 16],
pub current_address: MacAddress,
pub broadcast_address: MacAddress,
pub permanent_address: MacAddress,
pub if_type: u8,
pub mac_address_changeable: bool,
pub multiple_tx_supported: bool,
pub media_present_supported: bool,
pub media_present: bool,
}
newtype_enum! {
pub enum NetworkState: u32 => {
STOPPED = 0,
STARTED = 1,
INITIALIZED = 2,
MAX_STATE = 4,
}
}