Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions uefi-raw/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
- Added `::ZERO` constant for `IpAddress`
- `Ipv4Address` and `Ipv6Address` now implement `Display`. They
use the same formatting as `core::net::{Ipv4Addr, Ipv6Addr}`
- Added comprehensive integration with `core::net::{IpAddr, Ipv4Addr, Ipv6Addr}`
via `From` impls to better integrate uefi-raw types `IpAddress`,
`Ipv4Address`, and `Ipv6Address` with the Rust ecosystem.
- Added convenient `From` impls:
- `[u8; 6]` <--> `MacAddress`
- `[u8; 32]` --> `MacAddress`
- `[u8; 4]` --> `Ipv4Address`, `IpAddress`
- `[u8; 16]` --> `Ipv6Address`, `IpAddress`

## Changed
- **Breaking:** The MSRV is now 1.85.1 and the crate uses the Rust 2024 edition.
Expand Down
138 changes: 137 additions & 1 deletion uefi-raw/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
use core::fmt::{self, Debug, Display, Formatter};

/// An IPv4 internet protocol address.
///
/// # Conversions and Relation to [`core::net`]
///
/// The following [`From`] implementations exist:
/// - `[u8; 4]` -> [`Ipv4Address`]
/// - [`core::net::Ipv4Addr`] -> [`Ipv4Address`]
/// - [`core::net::IpAddr`] -> [`Ipv4Address`]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Ipv4Address(pub [u8; 4]);
Expand All @@ -35,6 +42,12 @@ impl From<Ipv4Address> for core::net::Ipv4Addr {
}
}

impl From<[u8; 4]> for Ipv4Address {
fn from(octets: [u8; 4]) -> Self {
Self(octets)
}
}

impl Display for Ipv4Address {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let ip = core::net::Ipv4Addr::from(*self);
Expand All @@ -43,6 +56,13 @@ impl Display for Ipv4Address {
}

/// An IPv6 internet protocol address.
///
/// # Conversions and Relation to [`core::net`]
///
/// The following [`From`] implementations exist:
/// - `[u8; 16]` -> [`Ipv6Address`]
/// - [`core::net::Ipv6Addr`] -> [`Ipv6Address`]
/// - [`core::net::IpAddr`] -> [`Ipv6Address`]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Ipv6Address(pub [u8; 16]);
Expand All @@ -67,6 +87,12 @@ impl From<Ipv6Address> for core::net::Ipv6Addr {
}
}

impl From<[u8; 16]> for Ipv6Address {
fn from(octets: [u8; 16]) -> Self {
Self(octets)
}
}

impl Display for Ipv6Address {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let ip = core::net::Ipv6Addr::from(*self);
Expand All @@ -80,6 +106,15 @@ impl Display for Ipv6Address {
/// 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.
///
/// # Conversions and Relation to [`core::net`]
///
/// The following [`From`] implementations exist:
/// - `[u8; 4]` -> [`IpAddress`]
/// - `[u8; 16]` -> [`IpAddress`]
/// - [`core::net::Ipv4Addr`] -> [`IpAddress`]
/// - [`core::net::Ipv6Addr`] -> [`IpAddress`]
/// - [`core::net::IpAddr`] -> [`IpAddress`]
#[derive(Clone, Copy)]
#[repr(C)]
pub union IpAddress {
Expand Down Expand Up @@ -170,6 +205,30 @@ impl From<core::net::IpAddr> for IpAddress {
}
}

impl From<core::net::Ipv4Addr> for IpAddress {
fn from(value: core::net::Ipv4Addr) -> Self {
Self::new_v4(value.octets())
}
}

impl From<core::net::Ipv6Addr> for IpAddress {
fn from(value: core::net::Ipv6Addr) -> Self {
Self::new_v6(value.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)
}
}

/// UEFI Media Access Control (MAC) address.
///
/// UEFI supports multiple network protocols and hardware types, not just
Expand All @@ -179,6 +238,13 @@ impl From<core::net::IpAddr> for IpAddress {
///
/// In most cases, this is just a typical `[u8; 6]` Ethernet style MAC
/// address with the rest of the bytes being zero.
///
/// # Conversions and Relation to [`core::net`]
///
/// There is no matching type in [`core::net`] but the following [`From`]
/// implementations exist:
/// - `[u8; 6]` <-> [`MacAddress`]
/// - `[u8; 32]` -> [`MacAddress`]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct MacAddress(pub [u8; 32]);
Expand All @@ -200,7 +266,7 @@ impl MacAddress {
}
}

// Normal/typical MAC addresses, such as in Ethernet.
// Normal Ethernet MAC address.
impl From<[u8; 6]> for MacAddress {
fn from(octets: [u8; 6]) -> Self {
let mut buffer = [0; 32];
Expand All @@ -209,12 +275,20 @@ impl From<[u8; 6]> for MacAddress {
}
}

// Normal Ethernet MAC address.
impl From<MacAddress> for [u8; 6] {
fn from(MacAddress(o): MacAddress) -> Self {
[o[0], o[1], o[2], o[3], o[4], o[5]]
}
}

// UEFI MAC addresses.
impl From<[u8; 32]> for MacAddress {
fn from(octets: [u8; 32]) -> Self {
Self(octets)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -267,4 +341,66 @@ mod tests {
assert_eq!(align_of::<PackedHelper<IpAddress>>(), 1);
assert_eq!(size_of::<PackedHelper<IpAddress>>(), 16);
}

/// Tests the From-impls from the documentation.
#[test]
fn test_promised_from_impls() {
// octets -> Ipv4Address
{
let octets = [0_u8, 1, 2, 3];
assert_eq!(Ipv4Address::from(octets), Ipv4Address(octets));
let uefi_addr = IpAddress::from(octets);
assert_eq!(&octets, &unsafe { uefi_addr.v4.octets() });
}
// octets -> Ipv6Address
{
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, &unsafe { uefi_addr.v6.octets() });
}
// StdIpv4Addr -> Ipv4Address
{
let octets = [7, 5, 3, 1];
let core_ipv4_addr = core::net::Ipv4Addr::from(octets);
assert_eq!(Ipv4Address::from(core_ipv4_addr).octets(), octets);
assert_eq!(
unsafe { IpAddress::from(core_ipv4_addr).v4.octets() },
octets
);
}
// StdIpv6Addr -> Ipv6Address
{
let octets = [7, 5, 3, 1, 6, 3, 8, 5, 2, 5, 2, 7, 3, 5, 2, 6];
let core_ipv6_addr = core::net::Ipv6Addr::from(octets);
assert_eq!(Ipv6Address::from(core_ipv6_addr).octets(), octets);
assert_eq!(
unsafe { IpAddress::from(core_ipv6_addr).v6.octets() },
octets
);
}
// StdIpAddr -> IpAddress
{
let octets = [8, 8, 2, 6];
let core_ip_addr = core::net::IpAddr::from(octets);
assert_eq!(unsafe { IpAddress::from(core_ip_addr).v4.octets() }, octets);
}
// octets <-> MacAddress
{
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 octets2: [u8; 6] = uefi_mac_addr.into();
assert_eq!(octets2, octets)
}
// octets -> MacAddress
{
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);
}
}
}