diff --git a/uefi-raw/CHANGELOG.md b/uefi-raw/CHANGELOG.md index 000e7590c..e2a97a57a 100644 --- a/uefi-raw/CHANGELOG.md +++ b/uefi-raw/CHANGELOG.md @@ -5,7 +5,14 @@ - Added `PciRootBridgeIoProtocol`. - Added `ConfigKeywordHandlerProtocol`. - Added `HiiConfigAccessProtocol`. +- Added lots of convenient methods and `From` implementations to better + integrate the `uefi_raw::net::*` types with the types from `core::net::*`. + Further, more associated functions for an improved convenience have been + added to the types of that module. +## Changed +- Types `MacAddress`, `IpAddress`, `Ipv4Address`, and `Ipv6Address` were moved + from `uefi_raw::*` to `uefi_raw::net::*`. # uefi-raw - 0.11.0 (2025-05-04) diff --git a/uefi-raw/src/lib.rs b/uefi-raw/src/lib.rs index a67ac564d..95b36210d 100644 --- a/uefi-raw/src/lib.rs +++ b/uefi-raw/src/lib.rs @@ -27,6 +27,7 @@ mod enums; pub mod capsule; pub mod firmware_storage; +pub mod net; pub mod protocol; pub mod table; pub mod time; @@ -37,7 +38,6 @@ 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 +106,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 +127,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..13fdb1b06 --- /dev/null +++ b/uefi-raw/src/net.rs @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! UEFI network types. +//! +//! The main exports of this module are: +//! - [`MacAddress`] +//! - [`IpAddress`] +//! - [`Ipv4Address`] +//! - [`Ipv6Address`] +//! +//! ## Relation to Rust Standard Library Net Types +//! +//! Some of these types may overlap with those in the Rust standard library +//! ([`core::net`]). To ensure a streamlined API and maintain ABI compatibility, +//! this results in some necessary duplication. +//! +//! All types are tightly integrated with the corresponding [`core::net`] types +//! and other convenient conversions using [`From`] implementations: +//! - `[u8; 4]` -> [`Ipv4Address`], [`IpAddress`] +//! - `[u8; 16]` -> [`Ipv6Address`], [`IpAddress`] +//! - [`core::net::Ipv4Addr`] -> [`Ipv4Address`], [`IpAddress`] +//! - [`core::net::Ipv6Addr`] -> [`Ipv6Address`], [`IpAddress`] +//! - [`core::net::IpAddr`] -> [`IpAddress`] +//! - [`Ipv4Address`] -> [`core::net::Ipv4Addr`] +//! - [`Ipv6Address`] -> [`core::net::Ipv6Addr`] +//! +//! Further, these [`From`] implementations exist: +//! - `[u8; 6]` -> [`MacAddress`] +//! - `[u8; 32]` -> [`MacAddress`] + +use core::net::{IpAddr as StdIpAddr, Ipv4Addr as StdIpv4Addr, Ipv6Addr as StdIpv6Addr}; + +/// An IPv4 internet protocol address. +/// +/// See the [module documentation] to get an overview over the relation to the +/// types from [`core::net`]. +/// +/// [module documentation]: self +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub struct Ipv4Address(pub [u8; 4]); + +impl Ipv4Address { + /// Returns the octets of the IP address. + #[must_use] + pub const fn octets(self) -> [u8; 4] { + self.0 + } +} + +impl From for Ipv4Address { + fn from(ip: StdIpv4Addr) -> Self { + Self(ip.octets()) + } +} + +impl From for StdIpv4Addr { + fn from(ip: Ipv4Address) -> Self { + Self::from(ip.0) + } +} + +/// An IPv6 internet protocol address. +/// +/// See the [module documentation] to get an overview over the relation to the +/// types from [`core::net`]. +/// +/// [module documentation]: self +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub struct Ipv6Address(pub [u8; 16]); + +impl Ipv6Address { + /// Returns the octets of the IP address. + #[must_use] + pub const fn octets(self) -> [u8; 16] { + self.0 + } +} + +impl From for Ipv6Address { + fn from(ip: StdIpv6Addr) -> Self { + Self(ip.octets()) + } +} + +impl From for StdIpv6Addr { + fn from(ip: Ipv6Address) -> Self { + Self::from(ip.0) + } +} + +/// EFI ABI-compatible union of an IPv4 or IPv6 internet protocol address, +/// corresponding to `EFI_IP_ADDRESS` type in the UEFI specification. +/// +/// See the [module documentation] to get an overview over the relation to the +/// types from [`core::net`]. +/// +/// # UEFI Information +/// Corresponds to the `EFI_IP_ADDRESS` type in the UEFI specification. Instead +/// of using an untagged C union, we use this more rusty type. ABI-wise it is +/// the same but less cumbersome to work with in Rust. +/// +/// [module documentation]: self +#[derive(Debug, Clone, Copy)] +#[repr(C, align(4))] +pub struct IpAddress(pub [u8; 16]); + +impl IpAddress { + /// Construct a new zeroed address. + #[must_use] + pub const fn new_zeroed() -> Self { + Self([0; 16]) + } + + /// Construct a new IPv4 address. + /// + /// The type won't know that it is an IPv6 address and additional context + /// is needed. + #[must_use] + pub const fn new_v4(octets: [u8; 4]) -> Self { + Self([ + octets[0], octets[1], octets[2], octets[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]) + } + + /// Construct a new IPv6 address. + /// + /// The type won't know that it is an IPv6 address and additional context + /// is needed. + #[must_use] + pub const fn new_v6(octets: [u8; 16]) -> Self { + Self(octets) + } + + /// Returns the octets of the union. Without additional context, it is not + /// clear whether the octets represent an IPv4 or IPv6 address. + #[must_use] + pub const fn octets(&self) -> [u8; 16] { + self.0 + } + + /// Returns a raw pointer to the IP address. + #[must_use] + pub const fn as_ptr(&self) -> *const Self { + core::ptr::addr_of!(*self) + } + + /// Returns a raw mutable pointer to the IP address. + #[must_use] + pub const fn as_ptr_mut(&mut self) -> *mut Self { + core::ptr::addr_of_mut!(*self) + } + + /// Transforms this EFI type to the Rust standard library's type. + /// + /// # Arguments + /// - `is_ipv6`: Whether the internal data should be interpreted as IPv6 or + /// IPv4 address. + /// + /// # Panics + /// Panics if `is_ipv6` is false but there are additional bytes + /// indicating it's a IPv6 address. + #[must_use] + pub fn to_std_ip_addr(self, is_ipv6: bool) -> StdIpAddr { + if is_ipv6 { + StdIpAddr::V6(StdIpv6Addr::from(self.octets())) + } else { + let has_extra_bytes = self.octets()[4..].iter().any(|&x| x != 0); + assert!(!has_extra_bytes); + let octets: [u8; 4] = self.octets()[..4].try_into().unwrap(); + StdIpAddr::V4(StdIpv4Addr::from(octets)) + } + } + + /// Returns the underlying data as [`Ipv4Address`], if only the first four + /// octets are used. + /// + /// # Safety + /// This function is not unsafe memory-wise but callers need to ensure with + /// additional context that the IP is indeed an IPv4 address. + pub unsafe fn try_as_ipv4(&self) -> Result { + let extra = self.octets()[4..].iter().any(|&x| x != 0); + if !extra { + let octets: [u8; 4] = self.octets()[..4].try_into().unwrap(); + Ok(Ipv4Address(octets)) + } else { + Err(Ipv6Address(self.octets())) + } + } + + /// Returns the underlying data as [`Ipv6Address`]. + /// + /// # Safety + /// This function is not unsafe memory-wise but callers need to ensure with + /// additional context that the IP is indeed an IPv6 address. + #[must_use] + pub unsafe fn as_ipv6(&self) -> Ipv6Address { + Ipv6Address::from(self.octets()) + } +} + +impl Default for IpAddress { + fn default() -> Self { + Self::new_zeroed() + } +} + +impl From for IpAddress { + fn from(t: StdIpAddr) -> Self { + match t { + StdIpAddr::V4(ip) => Self::new_v4(ip.octets()), + StdIpAddr::V6(ip) => Self::new_v6(ip.octets()), + } + } +} + +impl From<[u8; 4]> for IpAddress { + fn from(octets: [u8; 4]) -> Self { + Self::new_v4(octets) + } +} + +impl From<[u8; 16]> for IpAddress { + fn from(octets: [u8; 16]) -> Self { + Self::new_v6(octets) + } +} + +impl From<[u8; 4]> for Ipv4Address { + fn from(octets: [u8; 4]) -> Self { + Self(octets) + } +} + +impl From<[u8; 16]> for Ipv6Address { + fn from(octets: [u8; 16]) -> Self { + Self(octets) + } +} + +impl From for IpAddress { + fn from(value: StdIpv4Addr) -> Self { + Self::new_v4(value.octets()) + } +} + +impl From for IpAddress { + fn from(value: StdIpv6Addr) -> Self { + Self::new_v6(value.octets()) + } +} + +/// UEFI Media Access Control (MAC) address. +/// +/// UEFI supports multiple network protocols and hardware types, not just +/// Ethernet. Some of them may use MAC addresses longer than 6 bytes. To be +/// protocol-agnostic and future-proof, the UEFI spec chooses a maximum size +/// that can hold any supported media access control address. +/// +/// In most cases, this is just a typical `[u8; 6]` Ethernet style MAC +/// address with the rest of the bytes being zero. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub struct MacAddress(pub [u8; 32]); + +impl MacAddress { + /// Returns the octets of the MAC address. + #[must_use] + pub const fn octets(self) -> [u8; 32] { + self.0 + } + + /// Tries to interpret the MAC address as normal 6-byte MAC address, as used + /// in ethernet. + pub fn try_as_ethernet_mac_addr(self) -> Result<[u8; 6], [u8; 32]> { + let extra = self.octets()[4..].iter().any(|&x| x != 0); + if extra { + Err(self.0) + } else { + Ok(self.octets()[..4].try_into().unwrap()) + } + } +} + +impl From<[u8; 6]> for MacAddress { + fn from(octets: [u8; 6]) -> Self { + let mut buffer = [0; 32]; + buffer[..6].copy_from_slice(&octets); + Self(buffer) + } +} + +impl From<[u8; 32]> for MacAddress { + fn from(octets: [u8; 32]) -> Self { + Self(octets) + } +} + +#[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, + ]; + + /// Ensures ABI-compatibility, as described here: + /// + #[test] + fn test_abi() { + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 4); + assert_eq!(size_of::(), 4); + assert_eq!(align_of::(), 1); + assert_eq!(size_of::(), 16); + assert_eq!(align_of::(), 1); + } + + /// Test round-trip conversion between `Ipv4Address` and `StdIpv4Addr`. + #[test] + fn test_ip_addr4_conversion() { + let uefi_addr = Ipv4Address(TEST_IPV4); + let core_addr = StdIpv4Addr::from(uefi_addr); + assert_eq!(uefi_addr, Ipv4Address::from(core_addr)); + } + + /// Test round-trip conversion between [`Ipv6Address`] and [`StdIpv6Addr`]. + #[test] + fn test_ip_addr6_conversion() { + let uefi_addr = Ipv6Address(TEST_IPV6); + let core_addr = StdIpv6Addr::from(uefi_addr); + assert_eq!(uefi_addr, Ipv6Address::from(core_addr)); + } + + /// Test conversion from [`StdIpAddr`] to [`IpvAddress`]. + /// + /// Note that conversion in the other direction is not possible. + #[test] + fn test_ip_addr_conversion() { + let core_addr = StdIpAddr::V4(StdIpv4Addr::from(TEST_IPV4)); + let uefi_addr = IpAddress::from(core_addr); + assert_eq!( + unsafe { uefi_addr.try_as_ipv4().unwrap() }.octets(), + TEST_IPV4 + ); + + let core_addr = StdIpAddr::V6(StdIpv6Addr::from(TEST_IPV6)); + let uefi_addr = IpAddress::from(core_addr); + assert_eq!(unsafe { uefi_addr.as_ipv6() }.octets(), TEST_IPV6); + } + + /// Tests the From-impls as described in the module description. + #[test] + fn test_module_description_from_impls() { + { + let octets = [0_u8, 1, 2, 3]; + assert_eq!(Ipv4Address::from(octets), Ipv4Address(octets)); + let uefi_addr = IpAddress::from(octets); + assert_eq!(&octets, &uefi_addr.octets()[0..4]); + } + { + let octets = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + assert_eq!(Ipv6Address::from(octets), Ipv6Address(octets)); + let uefi_addr = IpAddress::from(octets); + assert_eq!(&octets, &uefi_addr.octets()); + } + { + let octets = [7, 5, 3, 1]; + let core_ipv4_addr = StdIpv4Addr::from(octets); + assert_eq!(Ipv4Address::from(core_ipv4_addr).octets(), octets); + assert_eq!(IpAddress::from(core_ipv4_addr).octets()[0..4], octets); + } + { + let octets = [7, 5, 3, 1, 6, 3, 8, 5, 2, 5, 2, 7, 3, 5, 2, 6]; + let core_ipv6_addr = StdIpv6Addr::from(octets); + assert_eq!(Ipv6Address::from(core_ipv6_addr).octets(), octets); + assert_eq!(IpAddress::from(core_ipv6_addr).octets(), octets); + } + { + let octets = [8, 8, 2, 6]; + let core_ip_addr = StdIpAddr::from(octets); + assert_eq!(IpAddress::from(core_ip_addr).octets()[0..4], octets); + } + { + let octets = [8, 8, 2, 6, 6, 7]; + let uefi_mac_addr = MacAddress::from(octets); + assert_eq!(uefi_mac_addr.octets()[0..6], octets); + } + { + let octets = [ + 8_u8, 8, 2, 6, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0, + 0, 0, 0, 0, 42, + ]; + let uefi_mac_addr = MacAddress::from(octets); + assert_eq!(uefi_mac_addr.octets(), octets); + } + } + + /// Tests the expected flow of types in a higher-level UEFI API. + #[test] + fn test_uefi_flow() { + fn efi_retrieve_efi_ip_addr(addr: &mut IpAddress, is_ipv6: bool) { + addr.0[0] = 42; + addr.0[1] = 42; + addr.0[2] = 42; + addr.0[3] = 42; + + if is_ipv6 { + addr.0[14] = 42; + addr.0[15] = 42; + } + } + + fn high_level_retrieve_ip(is_ipv6: bool) -> StdIpAddr { + let mut efi_ip_addr = IpAddress::new_zeroed(); + efi_retrieve_efi_ip_addr(&mut efi_ip_addr, is_ipv6); + efi_ip_addr.to_std_ip_addr(is_ipv6) + } + + let ipv4_addr = high_level_retrieve_ip(false); + let ipv4_addr: StdIpv4Addr = match ipv4_addr { + StdIpAddr::V4(ipv4_addr) => ipv4_addr, + StdIpAddr::V6(_) => panic!("should not happen"), + }; + assert_eq!(ipv4_addr.octets(), [42, 42, 42, 42]); + + let ipv6_addr = high_level_retrieve_ip(true); + let ipv6_addr: StdIpv6Addr = match ipv6_addr { + StdIpAddr::V6(ipv6_addr) => ipv6_addr, + StdIpAddr::V4(_) => panic!("should not happen"), + }; + let expected = [42, 42, 42, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 42]; + assert_eq!(ipv6_addr.octets(), expected); + } +} diff --git a/uefi-raw/src/protocol/device_path/device_path_gen.rs b/uefi-raw/src/protocol/device_path/device_path_gen.rs index 825a27929..f31289d87 100644 --- a/uefi-raw/src/protocol/device_path/device_path_gen.rs +++ b/uefi-raw/src/protocol/device_path/device_path_gen.rs @@ -8,9 +8,10 @@ // See `/xtask/src/device_path/README.md` for more details. #![allow(clippy::missing_const_for_fn)] #![allow(missing_debug_implementations)] +use crate::net::IpAddress; use crate::protocol::device_path; use crate::table::boot::MemoryType; -use crate::{Guid, IpAddress, guid}; +use crate::{Guid, guid}; use bitflags::bitflags; use device_path::DevicePathProtocol as DevicePathHeader; #[cfg(doc)] diff --git a/uefi-raw/src/protocol/network/dhcp4.rs b/uefi-raw/src/protocol/network/dhcp4.rs index c8ee47098..0e15b991b 100644 --- a/uefi-raw/src/protocol/network/dhcp4.rs +++ b/uefi-raw/src/protocol/network/dhcp4.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::{Boolean, Char8, Event, Guid, Ipv4Address, MacAddress, Status, guid}; +use crate::net::{Ipv4Address, MacAddress}; +use crate::{Boolean, Char8, Event, Guid, Status, guid}; use core::ffi::c_void; newtype_enum! { diff --git a/uefi-raw/src/protocol/network/http.rs b/uefi-raw/src/protocol/network/http.rs index 115f5fe18..260e64371 100644 --- a/uefi-raw/src/protocol/network/http.rs +++ b/uefi-raw/src/protocol/network/http.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::{Boolean, Char8, Char16, Event, Guid, Ipv4Address, Ipv6Address, Status, guid}; +use crate::net::{Ipv4Address, Ipv6Address}; +use crate::{Boolean, Char8, Char16, Event, Guid, Status, guid}; use core::ffi::c_void; use core::fmt::{self, Debug, Formatter}; use core::ptr; diff --git a/uefi-raw/src/protocol/network/ip4.rs b/uefi-raw/src/protocol/network/ip4.rs index 88fb04d65..fe3723dd4 100644 --- a/uefi-raw/src/protocol/network/ip4.rs +++ b/uefi-raw/src/protocol/network/ip4.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::Ipv4Address; +use crate::net::Ipv4Address; #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(C)] diff --git a/uefi-raw/src/protocol/network/ip4_config2.rs b/uefi-raw/src/protocol/network/ip4_config2.rs index 2bed6937d..3d852c5fd 100644 --- a/uefi-raw/src/protocol/network/ip4_config2.rs +++ b/uefi-raw/src/protocol/network/ip4_config2.rs @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 +use crate::net::{Ipv4Address, MacAddress}; use crate::protocol::network::ip4::Ip4RouteTable; -use crate::{Char16, Event, Guid, Ipv4Address, MacAddress, Status, guid}; +use crate::{Char16, Event, Guid, Status, guid}; use core::ffi::c_void; newtype_enum! { diff --git a/uefi-raw/src/protocol/network/pxe.rs b/uefi-raw/src/protocol/network/pxe.rs index 15d1a39b6..fc917718b 100644 --- a/uefi-raw/src/protocol/network/pxe.rs +++ b/uefi-raw/src/protocol/network/pxe.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::{Boolean, Char8, Guid, IpAddress, MacAddress, Status, guid}; +use crate::net::{IpAddress, MacAddress}; +use crate::{Boolean, Char8, Guid, Status, guid}; use bitflags::bitflags; use core::ffi::c_void; use core::fmt::{self, Debug, Formatter}; diff --git a/uefi-raw/src/protocol/network/snp.rs b/uefi-raw/src/protocol/network/snp.rs index 744cacd50..9a0d21695 100644 --- a/uefi-raw/src/protocol/network/snp.rs +++ b/uefi-raw/src/protocol/network/snp.rs @@ -4,7 +4,8 @@ use core::ffi; use bitflags::bitflags; -use crate::{Boolean, Event, Guid, IpAddress, MacAddress, Status, guid}; +use crate::net::{IpAddress, MacAddress}; +use crate::{Boolean, Event, Guid, Status, guid}; #[derive(Debug)] #[repr(C)] diff --git a/uefi/src/proto/network/ip4config2.rs b/uefi/src/proto/network/ip4config2.rs index 66b99bfae..8323de15b 100644 --- a/uefi/src/proto/network/ip4config2.rs +++ b/uefi/src/proto/network/ip4config2.rs @@ -13,7 +13,7 @@ use uefi::boot::ScopedProtocol; use uefi::prelude::*; use uefi::proto::unsafe_protocol; use uefi::{print, println}; -use uefi_raw::Ipv4Address; +use uefi_raw::net::Ipv4Address; use uefi_raw::protocol::network::ip4_config2::{ Ip4Config2DataType, Ip4Config2InterfaceInfo, Ip4Config2Policy, Ip4Config2Protocol, }; diff --git a/uefi/src/proto/network/mod.rs b/uefi/src/proto/network/mod.rs index 925287f2c..7bf0ecc2e 100644 --- a/uefi/src/proto/network/mod.rs +++ b/uefi/src/proto/network/mod.rs @@ -9,7 +9,7 @@ pub mod ip4config2; pub mod pxe; pub mod snp; -pub use uefi_raw::MacAddress; +pub use uefi_raw::net::MacAddress; /// Represents an IPv4/v6 address. /// @@ -42,23 +42,23 @@ impl IpAddress { /// /// `is_ipv6` must accurately reflect how the union was initialized. #[must_use] - const unsafe fn from_raw(ip_addr: uefi_raw::IpAddress, is_ipv6: bool) -> Self { + const unsafe fn from_raw(ip_addr: uefi_raw::net::IpAddress, is_ipv6: bool) -> Self { if is_ipv6 { - Self::new_v6(unsafe { ip_addr.v6.0 }) + Self::new_v6(ip_addr.0) } else { - Self::new_v4(unsafe { ip_addr.v4.0 }) + Self::new_v4([ip_addr.0[0], ip_addr.0[1], ip_addr.0[2], ip_addr.0[3]]) } } #[must_use] - const fn as_raw_ptr(&self) -> *const uefi_raw::IpAddress { + const fn as_raw_ptr(&self) -> *const uefi_raw::net::IpAddress { // The uefi-raw type is defined differently, but the layout is // compatible. self.0.as_ptr().cast() } #[must_use] - const fn as_raw_ptr_mut(&mut self) -> *mut uefi_raw::IpAddress { + const fn as_raw_ptr_mut(&mut self) -> *mut uefi_raw::net::IpAddress { // The uefi-raw type is defined differently, but the layout is // compatible. self.0.as_mut_ptr().cast() diff --git a/uefi/src/proto/network/pxe.rs b/uefi/src/proto/network/pxe.rs index a46162151..77fd25a0f 100644 --- a/uefi/src/proto/network/pxe.rs +++ b/uefi/src/proto/network/pxe.rs @@ -559,12 +559,12 @@ fn opt_bool_to_ptr(arg: &Option) -> *const Boolean { } /// Convert an `Option<&IpAddress>` to a `*const uefi_raw::IpAddress`. -fn opt_ip_addr_to_ptr(arg: Option<&IpAddress>) -> *const uefi_raw::IpAddress { +fn opt_ip_addr_to_ptr(arg: Option<&IpAddress>) -> *const uefi_raw::net::IpAddress { arg.map(|arg| arg.as_raw_ptr()).unwrap_or_else(null) } /// Convert an `Option<&mut IpAddress>` to a `*mut uefi_raw::IpAddress`. -fn opt_ip_addr_to_ptr_mut(arg: Option<&mut IpAddress>) -> *mut uefi_raw::IpAddress { +fn opt_ip_addr_to_ptr_mut(arg: Option<&mut IpAddress>) -> *mut uefi_raw::net::IpAddress { arg.map(|arg| arg.as_raw_ptr_mut()).unwrap_or_else(null_mut) } diff --git a/xtask/src/check_raw.rs b/xtask/src/check_raw.rs index 0930e639a..5a415d7f6 100644 --- a/xtask/src/check_raw.rs +++ b/xtask/src/check_raw.rs @@ -45,7 +45,7 @@ enum ErrorKind { ForbiddenAbi, ForbiddenAttr, ForbiddenItemKind(ItemKind), - ForbiddenRepr, + ForbiddenRepr(Vec), ForbiddenType, MalformedAttrs, MissingPub, @@ -57,25 +57,26 @@ enum ErrorKind { impl Display for ErrorKind { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - Self::ForbiddenAbi => "forbidden ABI", - Self::ForbiddenAttr => "forbidden attribute", - Self::ForbiddenItemKind(ItemKind::Enum) => - "forbidden use of enum; use the `newtype_enum!` macro instead", - Self::ForbiddenItemKind(_) => "forbidden type of item", - Self::ForbiddenRepr => "forbidden repr", - Self::ForbiddenType => "forbidden type", - Self::MalformedAttrs => "malformed attribute contents", - Self::MissingPub => "missing pub", - Self::MissingRepr => "missing repr", - Self::MissingUnsafe => "missing unsafe", - Self::UnderscoreField => "field name starts with `_`", - Self::UnknownRepr => "unknown repr", - } - ) + match self { + Self::ForbiddenAbi => write!(f, "forbidden ABI"), + Self::ForbiddenAttr => write!(f, "forbidden attribute"), + Self::ForbiddenItemKind(ItemKind::Enum) => write!( + f, + "forbidden use of enum; use the `newtype_enum!` macro instead" + ), + Self::ForbiddenItemKind(_) => write!(f, "forbidden type of item"), + Self::ForbiddenRepr(reprs) => write!( + f, + "the following combination of repr attributes is forbidden: {reprs:?}" + ), + Self::ForbiddenType => write!(f, "forbidden type"), + Self::MalformedAttrs => write!(f, "malformed attribute contents"), + Self::MissingPub => write!(f, "missing pub"), + Self::MissingRepr => write!(f, "missing repr"), + Self::MissingUnsafe => write!(f, "missing unsafe"), + Self::UnderscoreField => write!(f, "field name starts with `_`"), + Self::UnknownRepr => write!(f, "unknown repr"), + } } } @@ -279,7 +280,12 @@ fn check_fields(fields: &Punctuated, src: &Path) -> Result<(), Err } /// List with allowed combinations of representations (see [`Repr`]). -const ALLOWED_REPRS: &[&[Repr]] = &[&[Repr::C], &[Repr::C, Repr::Packed], &[Repr::Transparent]]; +const ALLOWED_REPRS: &[&[Repr]] = &[ + &[Repr::C], + &[Repr::C, Repr::Packed], + &[Repr::Transparent], + &[Repr::Align(4), Repr::C], +]; fn check_type_attrs(attrs: &[Attribute], spanned: &dyn Spanned, src: &Path) -> Result<(), Error> { let attrs = parse_attrs(attrs, src)?; @@ -290,7 +296,7 @@ fn check_type_attrs(attrs: &[Attribute], spanned: &dyn Spanned, src: &Path) -> R } else if ALLOWED_REPRS.contains(&reprs.as_slice()) { Ok(()) } else { - Err(Error::new(ErrorKind::ForbiddenRepr, src, spanned)) + Err(Error::new(ErrorKind::ForbiddenRepr(reprs), src, spanned)) } } @@ -347,7 +353,7 @@ fn check_macro(item: &ItemMacro, src: &Path) -> Result<(), Error> { let reprs = get_reprs(&attrs); let allowed_reprs: &[&[Repr]] = &[&[Repr::Transparent]]; if !allowed_reprs.contains(&reprs.as_slice()) { - return Err(Error::new(ErrorKind::ForbiddenRepr, src, mac)); + return Err(Error::new(ErrorKind::ForbiddenRepr(reprs), src, mac)); } } @@ -481,7 +487,7 @@ mod tests { } } }, - ErrorKind::ForbiddenRepr, + ErrorKind::ForbiddenRepr(vec![Repr::C]), ); } @@ -613,7 +619,7 @@ mod tests { pub f: u32, } }, - ErrorKind::ForbiddenRepr, + ErrorKind::ForbiddenRepr(vec![Repr::Rust]), ); // Forbidden attr. diff --git a/xtask/src/device_path/mod.rs b/xtask/src/device_path/mod.rs index 821a705b6..740477018 100644 --- a/xtask/src/device_path/mod.rs +++ b/xtask/src/device_path/mod.rs @@ -54,7 +54,8 @@ fn gen_uefi_raw_code_as_string(groups: &[NodeGroup]) -> Result { use bitflags::bitflags; use crate::protocol::device_path; use crate::table::boot::MemoryType; - use crate::{Guid, IpAddress, guid}; + use crate::{Guid, guid}; + use crate::net::IpAddress; use device_path::DevicePathProtocol as DevicePathHeader; #[cfg(doc)] use device_path::DeviceType;