From 6811f02a1598a3fce4cb8170012a67a9ab424aa8 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Sat, 14 Jun 2025 21:24:08 +0200 Subject: [PATCH] uefi-raw: move types to net module We have enough network-related types to justify a dedicated module: - IpAddress - Ipv4Address - Ipv6Address - MacAddress --- uefi-raw/src/lib.rs | 163 +---------------------------------------- uefi-raw/src/net.rs | 171 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 161 deletions(-) create mode 100644 uefi-raw/src/net.rs diff --git a/uefi-raw/src/lib.rs b/uefi-raw/src/lib.rs index a67ac564d..1eab855a2 100644 --- a/uefi-raw/src/lib.rs +++ b/uefi-raw/src/lib.rs @@ -31,13 +31,14 @@ pub mod protocol; pub mod table; pub mod time; +mod net; mod status; +pub use net::*; pub use status::Status; pub use uguid::{Guid, guid}; use core::ffi::c_void; -use core::fmt::{self, Debug, Formatter}; /// Handle to an event structure. pub type Event = *mut c_void; @@ -106,140 +107,10 @@ impl From for bool { } } -/// An IPv4 internet protocol address. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[repr(transparent)] -pub struct Ipv4Address(pub [u8; 4]); - -impl From for Ipv4Address { - fn from(ip: core::net::Ipv4Addr) -> Self { - Self(ip.octets()) - } -} - -impl From for core::net::Ipv4Addr { - fn from(ip: Ipv4Address) -> Self { - Self::from(ip.0) - } -} - -/// An IPv6 internet protocol address. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[repr(transparent)] -pub struct Ipv6Address(pub [u8; 16]); - -impl From for Ipv6Address { - fn from(ip: core::net::Ipv6Addr) -> Self { - Self(ip.octets()) - } -} - -impl From for core::net::Ipv6Addr { - fn from(ip: Ipv6Address) -> Self { - Self::from(ip.0) - } -} - -/// An IPv4 or IPv6 internet protocol address. -/// -/// Corresponds to the `EFI_IP_ADDRESS` type in the UEFI specification. This -/// type is defined in the same way as edk2 for compatibility with C code. Note -/// that this is an untagged union, so there's no way to tell which type of -/// address an `IpAddress` value contains without additional context. -#[derive(Clone, Copy)] -#[repr(C)] -pub union IpAddress { - /// This member serves to align the whole type to a 4 bytes as required by - /// the spec. Note that this is slightly different from `repr(align(4))`, - /// which would prevent placing this type in a packed structure. - pub addr: [u32; 4], - - /// An IPv4 internet protocol address. - pub v4: Ipv4Address, - - /// An IPv6 internet protocol address. - pub v6: Ipv6Address, -} - -impl IpAddress { - /// Construct a new IPv4 address. - #[must_use] - pub const fn new_v4(ip_addr: [u8; 4]) -> Self { - Self { - v4: Ipv4Address(ip_addr), - } - } - - /// Construct a new IPv6 address. - #[must_use] - pub const fn new_v6(ip_addr: [u8; 16]) -> Self { - Self { - v6: Ipv6Address(ip_addr), - } - } -} - -impl Debug for IpAddress { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - // The type is an untagged union, so we don't know whether it contains - // an IPv4 or IPv6 address. It's also not safe to just print the whole - // 16 bytes, since they might not all be initialized. - f.debug_struct("IpAddress").finish() - } -} - -impl Default for IpAddress { - fn default() -> Self { - Self { addr: [0u32; 4] } - } -} - -impl From for IpAddress { - fn from(t: core::net::IpAddr) -> Self { - match t { - core::net::IpAddr::V4(ip) => Self { - v4: Ipv4Address::from(ip), - }, - core::net::IpAddr::V6(ip) => Self { - v6: Ipv6Address::from(ip), - }, - } - } -} - -/// A Media Access Control (MAC) address. -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[repr(transparent)] -pub struct MacAddress(pub [u8; 32]); - -impl From<[u8; 6]> for MacAddress { - fn from(octets: [u8; 6]) -> Self { - let mut buffer = [0; 32]; - buffer[0] = octets[0]; - buffer[1] = octets[1]; - buffer[2] = octets[2]; - buffer[3] = octets[3]; - buffer[4] = octets[4]; - buffer[5] = octets[5]; - Self(buffer) - } -} - -impl From for [u8; 6] { - fn from(MacAddress(o): MacAddress) -> Self { - [o[0], o[1], o[2], o[3], o[4], o[5]] - } -} - #[cfg(test)] mod tests { use super::*; - const TEST_IPV4: [u8; 4] = [91, 92, 93, 94]; - const TEST_IPV6: [u8; 16] = [ - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - ]; - #[test] /// Test the properties promised in [0]. This also applies for the other /// architectures. @@ -257,34 +128,4 @@ mod tests { assert!(bool::from(Boolean(0b11111110))); assert!(bool::from(Boolean(0b11111111))); } - - /// Test round-trip conversion between `Ipv4Address` and `core::net::Ipv4Addr`. - #[test] - fn test_ip_addr4_conversion() { - let uefi_addr = Ipv4Address(TEST_IPV4); - let core_addr = core::net::Ipv4Addr::from(uefi_addr); - assert_eq!(uefi_addr, Ipv4Address::from(core_addr)); - } - - /// Test round-trip conversion between `Ipv6Address` and `core::net::Ipv6Addr`. - #[test] - fn test_ip_addr6_conversion() { - let uefi_addr = Ipv6Address(TEST_IPV6); - let core_addr = core::net::Ipv6Addr::from(uefi_addr); - assert_eq!(uefi_addr, Ipv6Address::from(core_addr)); - } - - /// Test conversion from `core::net::IpAddr` to `IpvAddress`. - /// - /// Note that conversion in the other direction is not possible. - #[test] - fn test_ip_addr_conversion() { - let core_addr = core::net::IpAddr::V4(core::net::Ipv4Addr::from(TEST_IPV4)); - let uefi_addr = IpAddress::from(core_addr); - assert_eq!(unsafe { uefi_addr.v4.0 }, TEST_IPV4); - - let core_addr = core::net::IpAddr::V6(core::net::Ipv6Addr::from(TEST_IPV6)); - let uefi_addr = IpAddress::from(core_addr); - assert_eq!(unsafe { uefi_addr.v6.0 }, TEST_IPV6); - } } diff --git a/uefi-raw/src/net.rs b/uefi-raw/src/net.rs new file mode 100644 index 000000000..71662aefe --- /dev/null +++ b/uefi-raw/src/net.rs @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! UEFI network types. + +use core::fmt; +use core::fmt::{Debug, Formatter}; + +/// An IPv4 internet protocol address. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub struct Ipv4Address(pub [u8; 4]); + +impl From for Ipv4Address { + fn from(ip: core::net::Ipv4Addr) -> Self { + Self(ip.octets()) + } +} + +impl From for core::net::Ipv4Addr { + fn from(ip: Ipv4Address) -> Self { + Self::from(ip.0) + } +} + +/// An IPv6 internet protocol address. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub struct Ipv6Address(pub [u8; 16]); + +impl From for Ipv6Address { + fn from(ip: core::net::Ipv6Addr) -> Self { + Self(ip.octets()) + } +} + +impl From for core::net::Ipv6Addr { + fn from(ip: Ipv6Address) -> Self { + Self::from(ip.0) + } +} + +/// An IPv4 or IPv6 internet protocol address. +/// +/// Corresponds to the `EFI_IP_ADDRESS` type in the UEFI specification. This +/// type is defined in the same way as edk2 for compatibility with C code. Note +/// that this is an untagged union, so there's no way to tell which type of +/// address an `IpAddress` value contains without additional context. +#[derive(Clone, Copy)] +#[repr(C)] +pub union IpAddress { + /// This member serves to align the whole type to a 4 bytes as required by + /// the spec. Note that this is slightly different from `repr(align(4))`, + /// which would prevent placing this type in a packed structure. + pub addr: [u32; 4], + + /// An IPv4 internet protocol address. + pub v4: Ipv4Address, + + /// An IPv6 internet protocol address. + pub v6: Ipv6Address, +} + +impl IpAddress { + /// Construct a new IPv4 address. + #[must_use] + pub const fn new_v4(ip_addr: [u8; 4]) -> Self { + Self { + v4: Ipv4Address(ip_addr), + } + } + + /// Construct a new IPv6 address. + #[must_use] + pub const fn new_v6(ip_addr: [u8; 16]) -> Self { + Self { + v6: Ipv6Address(ip_addr), + } + } +} + +impl Debug for IpAddress { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + // The type is an untagged union, so we don't know whether it contains + // an IPv4 or IPv6 address. It's also not safe to just print the whole + // 16 bytes, since they might not all be initialized. + f.debug_struct("IpAddress").finish() + } +} + +impl Default for IpAddress { + fn default() -> Self { + Self { addr: [0u32; 4] } + } +} + +impl From for IpAddress { + fn from(t: core::net::IpAddr) -> Self { + match t { + core::net::IpAddr::V4(ip) => Self { + v4: Ipv4Address::from(ip), + }, + core::net::IpAddr::V6(ip) => Self { + v6: Ipv6Address::from(ip), + }, + } + } +} + +/// A Media Access Control (MAC) address. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub struct MacAddress(pub [u8; 32]); + +impl From<[u8; 6]> for MacAddress { + fn from(octets: [u8; 6]) -> Self { + let mut buffer = [0; 32]; + buffer[0] = octets[0]; + buffer[1] = octets[1]; + buffer[2] = octets[2]; + buffer[3] = octets[3]; + buffer[4] = octets[4]; + buffer[5] = octets[5]; + Self(buffer) + } +} + +impl From for [u8; 6] { + fn from(MacAddress(o): MacAddress) -> Self { + [o[0], o[1], o[2], o[3], o[4], o[5]] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const TEST_IPV4: [u8; 4] = [91, 92, 93, 94]; + const TEST_IPV6: [u8; 16] = [ + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + ]; + + /// Test round-trip conversion between `Ipv4Address` and `core::net::Ipv4Addr`. + #[test] + fn test_ip_addr4_conversion() { + let uefi_addr = Ipv4Address(TEST_IPV4); + let core_addr = core::net::Ipv4Addr::from(uefi_addr); + assert_eq!(uefi_addr, Ipv4Address::from(core_addr)); + } + + /// Test round-trip conversion between `Ipv6Address` and `core::net::Ipv6Addr`. + #[test] + fn test_ip_addr6_conversion() { + let uefi_addr = Ipv6Address(TEST_IPV6); + let core_addr = core::net::Ipv6Addr::from(uefi_addr); + assert_eq!(uefi_addr, Ipv6Address::from(core_addr)); + } + + /// Test conversion from `core::net::IpAddr` to `IpvAddress`. + /// + /// Note that conversion in the other direction is not possible. + #[test] + fn test_ip_addr_conversion() { + let core_addr = core::net::IpAddr::V4(core::net::Ipv4Addr::from(TEST_IPV4)); + let uefi_addr = IpAddress::from(core_addr); + assert_eq!(unsafe { uefi_addr.v4.0 }, TEST_IPV4); + + let core_addr = core::net::IpAddr::V6(core::net::Ipv6Addr::from(TEST_IPV6)); + let uefi_addr = IpAddress::from(core_addr); + assert_eq!(unsafe { uefi_addr.v6.0 }, TEST_IPV6); + } +}