Skip to content

uefi-raw: move types to new net module, improve convenience #1699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions uefi-raw/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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::*`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think moving the implementation to a new module makes sense, but I think for the public API it might make sense to let that be an internal detail, i.e. keep the net module private and pub-export the types from the crate root. These types are listed in the Common UEFI Data Types portion of the spec, which to mind means they fit best at the top level (and this would also avoid making the change API breaking).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, makes sense!


# uefi-raw - 0.11.0 (2025-05-04)

Expand Down
162 changes: 1 addition & 161 deletions uefi-raw/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -106,140 +106,10 @@ impl From<Boolean> 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<core::net::Ipv4Addr> for Ipv4Address {
fn from(ip: core::net::Ipv4Addr) -> Self {
Self(ip.octets())
}
}

impl From<Ipv4Address> 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<core::net::Ipv6Addr> for Ipv6Address {
fn from(ip: core::net::Ipv6Addr) -> Self {
Self(ip.octets())
}
}

impl From<Ipv6Address> 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<core::net::IpAddr> 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<MacAddress> 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.
Expand All @@ -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);
}
}
Loading