diff --git a/uefi-raw/CHANGELOG.md b/uefi-raw/CHANGELOG.md index 3d0d44b0d..2aae02f98 100644 --- a/uefi-raw/CHANGELOG.md +++ b/uefi-raw/CHANGELOG.md @@ -15,8 +15,13 @@ - Added `UsbIoProtocol`. - Added `Usb2HostControllerProtocol`. - Added `DevicePathProtocol::length()` properly constructing the `u16` value +- Type `IpAddress` is now tightly integrated with `core::net::IpAddr`, e.g., + various `From` implementations are available. ## Changed +- **Breaking:** Types `Ipv4Address` and `Ipv6Address` have been removed. They + were replaced by `core::net::Ipv4Addr` and `core::net::Ipv6Addr`, as they are + ABI compatible. This mainly affects the `IpAddress` wrapper type. - `DevicePathProtocol` now derives `Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash` diff --git a/uefi-raw/src/lib.rs b/uefi-raw/src/lib.rs index 7f8050b56..8df4bdc13 100644 --- a/uefi-raw/src/lib.rs +++ b/uefi-raw/src/lib.rs @@ -38,6 +38,7 @@ pub use uguid::{guid, Guid}; use core::ffi::c_void; use core::fmt::{self, Debug, Formatter}; +use core::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// Handle to an event structure. pub type Event = *mut c_void; @@ -106,108 +107,182 @@ 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 +/// that this is an **untagged union**, so there's no way to tell which type of /// address an `IpAddress` value contains without additional context. +/// +/// For convenience, this type is tightly integrated with the Rust standard +/// library types [`IpAddr`], [`Ipv4Addr`], and [`Ipv6Addr`]. +/// +/// The constructors ensure that all unused bytes of these type are always +/// initialized to zero. #[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, + pub v4: Ipv4Addr, /// An IPv6 internet protocol address. - pub v6: Ipv6Address, + pub v6: Ipv6Addr, + + /// This member serves to align the whole type to 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 _align_helper: [u32; 4], } impl IpAddress { /// Construct a new IPv4 address. #[must_use] - pub const fn new_v4(ip_addr: [u8; 4]) -> Self { - Self { - v4: Ipv4Address(ip_addr), - } + pub fn new_v4(ip_addr: [u8; 4]) -> Self { + // Initialize all bytes to zero first. + let mut obj = Self::default(); + obj.v4 = Ipv4Addr::from(ip_addr); + obj } /// Construct a new IPv6 address. #[must_use] - pub const fn new_v6(ip_addr: [u8; 16]) -> Self { + pub fn new_v6(ip_addr: [u8; 16]) -> Self { Self { - v6: Ipv6Address(ip_addr), + v6: Ipv6Addr::from(ip_addr), } } + + /// 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] { + unsafe { self.v6.octets() } + } + + /// 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 fn as_ptr_mut(&mut self) -> *mut Self { + core::ptr::addr_of_mut!(*self) + } + + /// Transforms this EFI type to the Rust standard libraries type. + /// + /// # Arguments + /// - `is_ipv6`: Whether the internal data should be interpreted as IPv6 or + /// IPv4 address. + #[must_use] + pub fn to_ip_addr(self, is_ipv6: bool) -> IpAddr { + if is_ipv6 { + IpAddr::V6(Ipv6Addr::from(unsafe { self.v6.octets() })) + } else { + IpAddr::V4(Ipv4Addr::from(unsafe { self.v4.octets() })) + } + } + + /// Returns the underlying data as [`Ipv4Addr`], 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 as_ipv4(&self) -> Result { + let extra = self.octets()[4..].iter().any(|&x| x != 0); + if !extra { + Ok(Ipv4Addr::from(unsafe { self.v4.octets() })) + } else { + Err(Ipv6Addr::from(unsafe { self.v6.octets() })) + } + } + + /// Returns the underlying data as [`Ipv6Addr`]. + /// + /// # 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) -> Ipv6Addr { + Ipv6Addr::from(unsafe { self.v6.octets() }) + } } 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() + f.debug_tuple("IpAddress").field(&self.octets()).finish() } } impl Default for IpAddress { fn default() -> Self { - Self { addr: [0u32; 4] } + Self { + // Initialize all fields to zero + _align_helper: [0u32; 4], + } } } -impl From for IpAddress { - fn from(t: core::net::IpAddr) -> Self { +impl From for IpAddress { + fn from(t: IpAddr) -> Self { match t { - core::net::IpAddr::V4(ip) => Self { - v4: Ipv4Address::from(ip), - }, - core::net::IpAddr::V6(ip) => Self { - v6: Ipv6Address::from(ip), - }, + IpAddr::V4(ip) => Self::new_v4(ip.octets()), + IpAddr::V6(ip) => Self::new_v6(ip.octets()), } } } -/// A Media Access Control (MAC) address. +impl From<&IpAddr> for IpAddress { + fn from(t: &IpAddr) -> Self { + match t { + IpAddr::V4(ip) => Self::new_v4(ip.octets()), + IpAddr::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 for [u8; 16] { + fn from(value: IpAddress) -> Self { + value.octets() + } +} + +impl From for IpAddress { + fn from(value: Ipv4Addr) -> Self { + Self::new_v4(value.octets()) + } +} + +impl From for IpAddress { + fn from(value: Ipv6Addr) -> 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]); @@ -215,12 +290,7 @@ 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]; + buffer.copy_from_slice(&octets); Self(buffer) } } @@ -258,33 +328,65 @@ mod tests { assert!(bool::from(Boolean(0b11111111))); } - /// Test round-trip conversion between `Ipv4Address` and `core::net::Ipv4Addr`. + /// We test that the core::net-types are ABI compatible with the EFI types. + /// As long as this is the case, we can reuse core functionality and + /// prevent type duplication. #[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)); + fn net_abi() { + 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 `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)); + fn ip_ptr() { + let mut ip = IpAddress::new_v4([0; 4]); + let ptr = ip.as_ptr_mut().cast::(); + unsafe { + core::ptr::write(ptr, 192); + core::ptr::write(ptr.add(1), 168); + core::ptr::write(ptr.add(2), 42); + core::ptr::write(ptr.add(3), 73); + } + unsafe { assert_eq!(ip.v4.octets(), [192, 168, 42, 73]) } } - /// Test conversion from `core::net::IpAddr` to `IpvAddress`. - /// - /// Note that conversion in the other direction is not possible. + /// Test conversion from [`IpAddr`] to [`IpAddress`]. #[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); + // Reference: std types + let core_ipv4_v4 = Ipv4Addr::from(TEST_IPV4); + let core_ipv4 = IpAddr::from(core_ipv4_v4); + let core_ipv6_v6 = Ipv6Addr::from(TEST_IPV6); + let core_ipv6 = IpAddr::from(core_ipv6_v6); + + // Test From [u8; N] constructors + assert_eq!(IpAddress::from(TEST_IPV4).octets()[0..4], TEST_IPV4); + assert_eq!(IpAddress::from(TEST_IPV6).octets(), TEST_IPV6); + { + let bytes: [u8; 16] = IpAddress::from(TEST_IPV6).into(); + assert_eq!(bytes, TEST_IPV6); + } - 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); + // Test From::from std type constructors + let efi_ipv4 = IpAddress::from(core_ipv4); + assert_eq!(efi_ipv4.octets()[0..4], TEST_IPV4); + assert_eq!(unsafe { efi_ipv4.as_ipv4().unwrap() }, core_ipv4); + + let efi_ipv6 = IpAddress::from(core_ipv6); + assert_eq!(efi_ipv6.octets(), TEST_IPV6); + assert_eq!(unsafe { efi_ipv6.as_ipv4().unwrap_err() }, core_ipv6); + assert_eq!(unsafe { efi_ipv6.as_ipv6() }, core_ipv6); + + // Test From::from std type constructors + let efi_ipv4 = IpAddress::from(core_ipv4_v4); + assert_eq!(efi_ipv4.octets()[0..4], TEST_IPV4); + assert_eq!(unsafe { efi_ipv4.as_ipv4().unwrap() }, core_ipv4); + + let efi_ipv6 = IpAddress::from(core_ipv6_v6); + assert_eq!(efi_ipv6.octets(), TEST_IPV6); + assert_eq!(unsafe { efi_ipv6.as_ipv4().unwrap_err() }, core_ipv6); + assert_eq!(unsafe { efi_ipv6.as_ipv6() }, core_ipv6); } } diff --git a/uefi-raw/src/protocol/network/dhcp4.rs b/uefi-raw/src/protocol/network/dhcp4.rs index 9f26dc0ef..95de9a200 100644 --- a/uefi-raw/src/protocol/network/dhcp4.rs +++ b/uefi-raw/src/protocol/network/dhcp4.rs @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::{guid, Boolean, Char8, Event, Guid, Ipv4Address, MacAddress, Status}; +use crate::{guid, Boolean, Char8, Event, Guid, MacAddress, Status}; use core::ffi::c_void; +use core::net::Ipv4Addr; newtype_enum! { pub enum Dhcp4Event: i32 => { @@ -58,10 +59,10 @@ pub struct Dhcp4Header { pub xid: u32, pub seconds: u16, pub reserved: u16, - pub client_addr: Ipv4Address, - pub your_addr: Ipv4Address, - pub server_addr: Ipv4Address, - pub gateway_addr: Ipv4Address, + pub client_addr: Ipv4Addr, + pub your_addr: Ipv4Addr, + pub server_addr: Ipv4Addr, + pub gateway_addr: Ipv4Addr, pub client_hw_addr: [u8; 16], pub server_name: [Char8; 64], pub boot_file_name: [Char8; 128], @@ -86,7 +87,7 @@ pub struct Dhcp4ConfigData { pub discover_timeout: *mut u32, pub request_try_count: u32, pub request_timeout: *mut u32, - pub client_address: Ipv4Address, + pub client_address: Ipv4Addr, pub callback: Option< unsafe extern "efiapi" fn( this: *mut Dhcp4Protocol, @@ -107,11 +108,11 @@ pub struct Dhcp4ConfigData { pub struct Dhcp4ModeData { pub state: Dhcp4State, pub config_data: Dhcp4ConfigData, - pub client_address: Ipv4Address, + pub client_address: Ipv4Addr, pub client_mac_address: MacAddress, - pub server_address: Ipv4Address, - pub router_address: Ipv4Address, - pub subnet_mask: Ipv4Address, + pub server_address: Ipv4Addr, + pub router_address: Ipv4Addr, + pub subnet_mask: Ipv4Addr, pub lease_time: u32, pub reply_packet: *const Dhcp4Packet, } @@ -119,8 +120,8 @@ pub struct Dhcp4ModeData { #[derive(Debug)] #[repr(C)] pub struct Dhcp4ListenPoint { - pub listen_address: Ipv4Address, - pub subnet_mask: Ipv4Address, + pub listen_address: Ipv4Addr, + pub subnet_mask: Ipv4Addr, pub listen_port: u16, } @@ -129,9 +130,9 @@ pub struct Dhcp4ListenPoint { pub struct Dhcp4TransmitReceiveToken { pub status: Status, pub completion_event: Event, - pub remote_address: Ipv4Address, + pub remote_address: Ipv4Addr, pub remote_port: u16, - pub gateway_address: Ipv4Address, + pub gateway_address: Ipv4Addr, pub listen_point_count: u32, pub listen_points: *mut Dhcp4ListenPoint, pub timeout_value: u32, diff --git a/uefi-raw/src/protocol/network/http.rs b/uefi-raw/src/protocol/network/http.rs index 99ff1220b..62687e3b2 100644 --- a/uefi-raw/src/protocol/network/http.rs +++ b/uefi-raw/src/protocol/network/http.rs @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::{guid, Boolean, Char16, Char8, Event, Guid, Ipv4Address, Ipv6Address, Status}; +use crate::{guid, Boolean, Char16, Char8, Event, Guid, Status}; use core::ffi::c_void; use core::fmt::{self, Debug, Formatter}; +use core::net::{Ipv4Addr, Ipv6Addr}; use core::ptr; #[derive(Debug, Default)] @@ -23,19 +24,30 @@ newtype_enum! { } } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(C)] pub struct HttpV4AccessPoint { pub use_default_addr: Boolean, - pub local_address: Ipv4Address, - pub local_subnet: Ipv4Address, + pub local_address: Ipv4Addr, + pub local_subnet: Ipv4Addr, pub local_port: u16, } -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +impl Default for HttpV4AccessPoint { + fn default() -> Self { + Self { + use_default_addr: Default::default(), + local_address: Ipv4Addr::from([0; 4]), + local_subnet: Ipv4Addr::from([0; 4]), + local_port: 0, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(C)] pub struct HttpV6AccessPoint { - pub local_address: Ipv6Address, + pub local_address: Ipv6Addr, pub local_port: u16, } diff --git a/uefi-raw/src/protocol/network/ip4.rs b/uefi-raw/src/protocol/network/ip4.rs index 88fb04d65..bb16ec13a 100644 --- a/uefi-raw/src/protocol/network/ip4.rs +++ b/uefi-raw/src/protocol/network/ip4.rs @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::Ipv4Address; +use core::net::Ipv4Addr; #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(C)] pub struct Ip4RouteTable { - pub subnet_addr: Ipv4Address, - pub subnet_mask: Ipv4Address, - pub gateway_addr: Ipv4Address, + pub subnet_addr: Ipv4Addr, + pub subnet_mask: Ipv4Addr, + pub gateway_addr: Ipv4Addr, } diff --git a/uefi-raw/src/protocol/network/ip4_config2.rs b/uefi-raw/src/protocol/network/ip4_config2.rs index 41f334b05..f79937aec 100644 --- a/uefi-raw/src/protocol/network/ip4_config2.rs +++ b/uefi-raw/src/protocol/network/ip4_config2.rs @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::protocol::network::ip4::Ip4RouteTable; -use crate::{guid, Char16, Event, Guid, Ipv4Address, MacAddress, Status}; +use crate::{guid, Char16, Event, Guid, MacAddress, Status}; use core::ffi::c_void; +use core::net::Ipv4Addr; newtype_enum! { pub enum Ip4Config2DataType: i32 => { @@ -22,8 +23,8 @@ pub struct Ip4Config2InterfaceInfo { pub if_type: u8, pub hw_addr_size: u32, pub hw_addr: MacAddress, - pub station_addr: Ipv4Address, - pub subnet_mask: Ipv4Address, + pub station_addr: Ipv4Addr, + pub subnet_mask: Ipv4Addr, pub route_table_size: u32, pub route_table: *mut Ip4RouteTable, } @@ -39,8 +40,8 @@ newtype_enum! { #[derive(Debug)] #[repr(C)] pub struct Ip4Config2ManualAddress { - pub address: Ipv4Address, - pub subnet_mask: Ipv4Address, + pub address: Ipv4Addr, + pub subnet_mask: Ipv4Addr, } #[derive(Debug)] diff --git a/uefi-test-runner/src/proto/network/pxe.rs b/uefi-test-runner/src/proto/network/pxe.rs index 9f29733f7..f7a3cb751 100644 --- a/uefi-test-runner/src/proto/network/pxe.rs +++ b/uefi-test-runner/src/proto/network/pxe.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use uefi::proto::network::pxe::{BaseCode, DhcpV4Packet, IpFilter, IpFilters, UdpOpFlags}; -use uefi::proto::network::IpAddress; +use uefi::proto::network::EfiIpAddr; use uefi::{boot, CStr8}; pub fn test() { @@ -27,7 +27,7 @@ pub fn test() { assert!(base_code.mode().dhcp_ack_received()); let dhcp_ack: &DhcpV4Packet = base_code.mode().dhcp_ack().as_ref(); let server_ip = dhcp_ack.bootp_si_addr; - let server_ip = IpAddress::new_v4(server_ip); + let server_ip = EfiIpAddr::new_v4(server_ip); const EXAMPLE_FILE_NAME: &[u8] = b"example-file.txt\0"; const EXAMPLE_FILE_CONTENT: &[u8] = b"Hello world!"; diff --git a/uefi-test-runner/src/proto/network/snp.rs b/uefi-test-runner/src/proto/network/snp.rs index a0c2ccba4..83989636c 100644 --- a/uefi-test-runner/src/proto/network/snp.rs +++ b/uefi-test-runner/src/proto/network/snp.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use uefi::proto::network::snp::{InterruptStatus, ReceiveFlags, SimpleNetwork}; -use uefi::proto::network::MacAddress; +use uefi::proto::network::EfiMacAddr; use uefi::{boot, Status}; pub fn test() { @@ -75,7 +75,7 @@ pub fn test() { \xa9\xe4\ \x04\x01\x02\x03\x04"; - let dest_addr = MacAddress([0xffu8; 32]); + let dest_addr = EfiMacAddr([0xffu8; 32]); assert!(!simple_network .get_interrupt_status() .unwrap() diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index fa9cb6218..958db7356 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -29,6 +29,11 @@ defaults to the recommended value of `MemoryType::LOADER_DATA`. - **Breaking:** Removed duplication in `DevicePathHeader`. Instead of public fields, there is now a public constructor combined with public getters. +- **Breaking:** Removed type `IpAddress`. Instead, a new alias `EfiIpAddr` is + exported which forwards to the new `IpAddress` type in `uefi-raw`. That type + is tightly integrated with `core::net::{IpAddr, Ipv4Addr, Ipv6Addr}`. + This simplifies working with IP addresses significantly. +- **Breaking:** For consistency, `MacAddress` was renamed to `EfiMacAddr`. - `boot::memory_map()` will never return `Status::BUFFER_TOO_SMALL` from now on, as this is considered a hard internal error where users can't do anything about it anyway. It will panic instead. @@ -41,7 +46,7 @@ - The `Display` impl for `CStr8` now excludes the trailing null character. - `VariableKeys` initializes with a larger name buffer to work around firmware bugs on some devices. -- The UEFI `allocator::Allocator` has been optimized for page-aligned +- The UEFI `allocator::Allocator` has been optimized for page-aligned allocations. diff --git a/uefi/src/proto/device_path/device_path_gen.rs b/uefi/src/proto/device_path/device_path_gen.rs index d30b93ee8..0d0764496 100644 --- a/uefi/src/proto/device_path/device_path_gen.rs +++ b/uefi/src/proto/device_path/device_path_gen.rs @@ -14,13 +14,13 @@ use crate::polyfill::maybe_uninit_slice_as_mut_ptr; use crate::proto::device_path::{ self, DevicePathHeader, DevicePathNode, DeviceSubType, DeviceType, NodeConversionError, }; -use crate::proto::network::IpAddress; use crate::{guid, Guid}; use bitflags::bitflags; use core::mem::{size_of, size_of_val}; use core::ptr::addr_of; use core::{fmt, slice}; use ptr_meta::Pointee; +use uefi_raw::IpAddress; /// Device path nodes for [`DeviceType::END`]. pub mod end { use super::*; diff --git a/uefi/src/proto/network/ip4config2.rs b/uefi/src/proto/network/ip4config2.rs index 013c659d4..1e642219f 100644 --- a/uefi/src/proto/network/ip4config2.rs +++ b/uefi/src/proto/network/ip4config2.rs @@ -7,7 +7,7 @@ use alloc::vec; use alloc::vec::Vec; use core::ffi::c_void; - +use core::net::Ipv4Addr; use uefi::boot::ScopedProtocol; use uefi::prelude::*; use uefi::proto::unsafe_protocol; @@ -15,7 +15,6 @@ use uefi::{print, println}; use uefi_raw::protocol::network::ip4_config2::{ Ip4Config2DataType, Ip4Config2InterfaceInfo, Ip4Config2Policy, Ip4Config2Protocol, }; -use uefi_raw::Ipv4Address; /// IP4 Config2 [`Protocol`]. Configure IPv4 networking. /// @@ -101,29 +100,19 @@ impl Ip4Config2 { }) } - fn print_info(info: &Ip4Config2InterfaceInfo) { - println!( - "addr v4: {}.{}.{}.{}", - info.station_addr.0[0], - info.station_addr.0[1], - info.station_addr.0[2], - info.station_addr.0[3], - ); - } - /// Bring up network interface. Does nothing in case the network /// is already set up. Otherwise turns on DHCP and waits until an /// IPv4 address has been assigned. Reports progress on the /// console if verbose is set to true. Returns TIMEOUT error in /// case DHCP configuration does not finish within 30 seconds. pub fn ifup(&mut self, verbose: bool) -> uefi::Result<()> { - let no_address = Ipv4Address::default(); + let no_address = Ipv4Addr::from_bits(0); let info = self.get_interface_info()?; if info.station_addr != no_address { if verbose { print!("Network is already up: "); - Self::print_info(&info); + println!("addr v4: {}", info.station_addr); } return Ok(()); } @@ -142,7 +131,7 @@ impl Ip4Config2 { if info.station_addr != no_address { if verbose { print!(" OK: "); - Self::print_info(&info); + println!("addr v4: {}", info.station_addr); } return Ok(()); } diff --git a/uefi/src/proto/network/mod.rs b/uefi/src/proto/network/mod.rs index b3eb665b6..2e874212a 100644 --- a/uefi/src/proto/network/mod.rs +++ b/uefi/src/proto/network/mod.rs @@ -3,101 +3,15 @@ //! Network access protocols. //! //! These protocols can be used to interact with network resources. +//! +//! To work with Mac and IP addresses, `uefi` uses with the types: +//! - [`EfiIpAddr`] that is tightly integrated with the [`core::net::IpAddr`] +//! type, +//! - [`EfiMacAddr`] pub mod http; pub mod ip4config2; pub mod pxe; pub mod snp; -pub use uefi_raw::MacAddress; - -/// Represents an IPv4/v6 address. -/// -/// Corresponds to the `EFI_IP_ADDRESS` type in the C API. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[repr(C, align(4))] -pub struct IpAddress(pub [u8; 16]); - -impl IpAddress { - /// Construct a new IPv4 address. - #[must_use] - pub const fn new_v4(ip_addr: [u8; 4]) -> Self { - let mut buffer = [0; 16]; - buffer[0] = ip_addr[0]; - buffer[1] = ip_addr[1]; - buffer[2] = ip_addr[2]; - buffer[3] = ip_addr[3]; - Self(buffer) - } - - /// Construct a new IPv6 address. - #[must_use] - pub const fn new_v6(ip_addr: [u8; 16]) -> Self { - Self(ip_addr) - } - - /// Construct from a `uefi_raw::IpAddress` union. - /// - /// # Safety - /// - /// `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 { - if is_ipv6 { - Self::new_v6(unsafe { ip_addr.v6.0 }) - } else { - Self::new_v4(unsafe { ip_addr.v4.0 }) - } - } - - #[must_use] - const fn as_raw_ptr(&self) -> *const uefi_raw::IpAddress { - // The uefi-raw type is defined differently, but the layout is - // compatible. - self.0.as_ptr().cast() - } - - #[must_use] - fn as_raw_ptr_mut(&mut self) -> *mut uefi_raw::IpAddress { - // The uefi-raw type is defined differently, but the layout is - // compatible. - self.0.as_mut_ptr().cast() - } -} - -impl From for IpAddress { - fn from(t: core::net::Ipv4Addr) -> Self { - Self::new_v4(t.octets()) - } -} - -impl From for core::net::Ipv4Addr { - fn from(IpAddress(o): IpAddress) -> Self { - Self::from([o[0], o[1], o[2], o[3]]) - } -} - -impl From for IpAddress { - fn from(t: core::net::Ipv6Addr) -> Self { - Self::new_v6(t.octets()) - } -} - -impl From for core::net::Ipv6Addr { - fn from(value: IpAddress) -> Self { - Self::from(value.0) - } -} - -impl From for IpAddress { - fn from(t: core::net::IpAddr) -> Self { - match t { - core::net::IpAddr::V4(a) => a.into(), - core::net::IpAddr::V6(a) => a.into(), - } - } -} - -// NOTE: We cannot impl From for core::net::IpAddr -// because IpAddress is a raw union, with nothing indicating -// whether it should be considered v4 or v6. +pub use uefi_raw::{IpAddress as EfiIpAddr, MacAddress as EfiMacAddr}; diff --git a/uefi/src/proto/network/pxe.rs b/uefi/src/proto/network/pxe.rs index a46162151..0cad16bab 100644 --- a/uefi/src/proto/network/pxe.rs +++ b/uefi/src/proto/network/pxe.rs @@ -2,7 +2,7 @@ //! PXE Base Code protocol. -use super::{IpAddress, MacAddress}; +use super::{EfiIpAddr, EfiMacAddr}; use crate::polyfill::maybe_uninit_slice_as_mut_ptr; use crate::proto::unsafe_protocol; use crate::util::{ptr_write_unaligned_and_add, usize_from_u32}; @@ -65,7 +65,7 @@ impl BaseCode { } /// Returns the size of a file located on a TFTP server. - pub fn tftp_get_file_size(&mut self, server_ip: &IpAddress, filename: &CStr8) -> Result { + pub fn tftp_get_file_size(&mut self, server_ip: &EfiIpAddr, filename: &CStr8) -> Result { let mut buffer_size = 0; let status = unsafe { @@ -76,7 +76,7 @@ impl BaseCode { Boolean::FALSE, &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), cstr8_to_ptr(filename), null(), Boolean::FALSE, @@ -88,7 +88,7 @@ impl BaseCode { /// Reads a file located on a TFTP server. pub fn tftp_read_file( &mut self, - server_ip: &IpAddress, + server_ip: &EfiIpAddr, filename: &CStr8, buffer: Option<&mut [u8]>, ) -> Result { @@ -107,7 +107,7 @@ impl BaseCode { Boolean::FALSE, &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), cstr8_to_ptr(filename), null(), dont_use_buffer, @@ -119,7 +119,7 @@ impl BaseCode { /// Writes to a file located on a TFTP server. pub fn tftp_write_file( &mut self, - server_ip: &IpAddress, + server_ip: &EfiIpAddr, filename: &CStr8, overwrite: bool, buffer: &[u8], @@ -135,7 +135,7 @@ impl BaseCode { overwrite.into(), &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), cstr8_to_ptr(filename), null(), Boolean::FALSE, @@ -147,7 +147,7 @@ impl BaseCode { /// Reads a directory listing of a directory on a TFTP server. pub fn tftp_read_dir<'a>( &mut self, - server_ip: &IpAddress, + server_ip: &EfiIpAddr, directory_name: &CStr8, buffer: &'a mut [u8], ) -> Result, ReadDirParseError>> + 'a> @@ -163,7 +163,7 @@ impl BaseCode { Boolean::FALSE, &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), cstr8_to_ptr(directory_name), null(), Boolean::FALSE, @@ -222,7 +222,7 @@ impl BaseCode { /// Returns the size of a file located on a MTFTP server. pub fn mtftp_get_file_size( &mut self, - server_ip: &IpAddress, + server_ip: &EfiIpAddr, filename: &CStr8, info: &MtftpInfo, ) -> Result { @@ -236,9 +236,9 @@ impl BaseCode { Boolean::FALSE, &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), cstr8_to_ptr(filename), - info.as_raw_ptr(), + info.as_ptr(), Boolean::FALSE, ) }; @@ -248,7 +248,7 @@ impl BaseCode { /// Reads a file located on a MTFTP server. pub fn mtftp_read_file( &mut self, - server_ip: &IpAddress, + server_ip: &EfiIpAddr, filename: &CStr8, buffer: Option<&mut [u8]>, info: &MtftpInfo, @@ -268,9 +268,9 @@ impl BaseCode { Boolean::FALSE, &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), cstr8_to_ptr(filename), - info.as_raw_ptr(), + info.as_ptr(), dont_use_buffer, ) }; @@ -280,7 +280,7 @@ impl BaseCode { /// Reads a directory listing of a directory on a MTFTP server. pub fn mtftp_read_dir<'a>( &mut self, - server_ip: &IpAddress, + server_ip: &EfiIpAddr, buffer: &'a mut [u8], info: &MtftpInfo, ) -> Result, ReadDirParseError>> + 'a> @@ -296,9 +296,9 @@ impl BaseCode { Boolean::FALSE, &mut buffer_size, null(), - server_ip.as_raw_ptr(), + server_ip.as_ptr(), null_mut(), - info.as_raw_ptr(), + info.as_ptr(), Boolean::FALSE, ) }; @@ -330,7 +330,7 @@ impl BaseCode { // The IP should have exact 4 octets, not more. return Err(ReadDirParseError); } - let ip_address = IpAddress::new_v4(buffer); + let ip_address = EfiIpAddr::new_v4(buffer); let information_string = iterator.next().ok_or(ReadDirParseError)?; let (_null_terminator, information_string) = information_string.split_last().unwrap(); @@ -374,10 +374,10 @@ impl BaseCode { pub fn udp_write( &mut self, op_flags: UdpOpFlags, - dest_ip: &IpAddress, + dest_ip: &EfiIpAddr, dest_port: u16, - gateway_ip: Option<&IpAddress>, - src_ip: Option<&IpAddress>, + gateway_ip: Option<&EfiIpAddr>, + src_ip: Option<&EfiIpAddr>, src_port: Option<&mut u16>, header: Option<&[u8]>, buffer: &[u8], @@ -394,7 +394,7 @@ impl BaseCode { (self.0.udp_write)( &mut self.0, op_flags, - dest_ip.as_raw_ptr(), + dest_ip.as_ptr(), &dest_port, opt_ip_addr_to_ptr(gateway_ip), opt_ip_addr_to_ptr(src_ip), @@ -413,9 +413,9 @@ impl BaseCode { pub fn udp_read( &mut self, op_flags: UdpOpFlags, - dest_ip: Option<&mut IpAddress>, + dest_ip: Option<&mut EfiIpAddr>, dest_port: Option<&mut u16>, - src_ip: Option<&mut IpAddress>, + src_ip: Option<&mut EfiIpAddr>, src_port: Option<&mut u16>, header: Option<&mut [u8]>, buffer: &mut [u8], @@ -455,9 +455,8 @@ impl BaseCode { } /// Uses the ARP protocol to resolve a MAC address. - pub fn arp(&mut self, ip_addr: &IpAddress, mac_addr: Option<&mut MacAddress>) -> Result { - unsafe { (self.0.arp)(&mut self.0, ip_addr.as_raw_ptr(), opt_mut_to_ptr(mac_addr)) } - .to_result() + pub fn arp(&mut self, ip_addr: &EfiIpAddr, mac_addr: Option<&mut EfiMacAddr>) -> Result { + unsafe { (self.0.arp)(&mut self.0, ip_addr.as_ptr(), opt_mut_to_ptr(mac_addr)) }.to_result() } /// Updates the parameters that affect the operation of the PXE Base Code @@ -487,8 +486,8 @@ impl BaseCode { /// device. pub fn set_station_ip( &mut self, - new_station_ip: Option<&IpAddress>, - new_subnet_mask: Option<&IpAddress>, + new_station_ip: Option<&EfiIpAddr>, + new_subnet_mask: Option<&EfiIpAddr>, ) -> Result { unsafe { (self.0.set_station_ip)( @@ -558,14 +557,14 @@ fn opt_bool_to_ptr(arg: &Option) -> *const Boolean { .unwrap_or_else(null) } -/// Convert an `Option<&IpAddress>` to a `*const uefi_raw::IpAddress`. -fn opt_ip_addr_to_ptr(arg: Option<&IpAddress>) -> *const uefi_raw::IpAddress { - arg.map(|arg| arg.as_raw_ptr()).unwrap_or_else(null) +/// Convert an `Option<&EfiIpAddr>` to a `*const uefi_raw::EfiIpAddr`. +fn opt_ip_addr_to_ptr(arg: Option<&EfiIpAddr>) -> *const EfiIpAddr { + arg.map(|arg| arg.as_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 { - arg.map(|arg| arg.as_raw_ptr_mut()).unwrap_or_else(null_mut) +/// Convert an `Option<&mut EfiIpAddr>` to a `*mut uefi_raw::EfiIpAddr`. +fn opt_ip_addr_to_ptr_mut(arg: Option<&mut EfiIpAddr>) -> *mut EfiIpAddr { + arg.map(|arg| arg.as_ptr_mut()).unwrap_or_else(null_mut) } /// Convert an `Option<&Packet>` to a `*const PxeBaseCodePacket`. @@ -600,7 +599,7 @@ pub struct DiscoverInfo { use_b_cast: bool, use_u_cast: bool, must_use_list: bool, - server_m_cast_ip: IpAddress, + server_m_cast_ip: EfiIpAddr, ip_cnt: u16, srv_list: [Server], } @@ -613,14 +612,14 @@ impl DiscoverInfo { use_b_cast: bool, use_u_cast: bool, must_use_list: bool, - server_m_cast_ip: IpAddress, + server_m_cast_ip: EfiIpAddr, srv_list: &[Server], ) -> Result<&'buf mut Self> { let server_count = srv_list.len(); assert!(server_count <= u16::MAX as usize, "too many servers"); let required_size = size_of::() * 4 - + size_of::() + + size_of::() + size_of::() + size_of_val(srv_list); @@ -675,7 +674,7 @@ impl DiscoverInfo { /// Returns the address used in multicast discovery. #[must_use] - pub const fn server_m_cast_ip(&self) -> &IpAddress { + pub const fn server_m_cast_ip(&self) -> &EfiIpAddr { &self.server_m_cast_ip } @@ -704,7 +703,7 @@ pub struct Server { accept_any_response: bool, _reserved: u8, /// The IP address of the server - ip_addr: IpAddress, + ip_addr: EfiIpAddr, } impl Server { @@ -712,19 +711,19 @@ impl Server { /// `None` only Boot Server replies with matching the IP address will be /// accepted. #[must_use] - pub fn new(ty: u16, ip_addr: Option) -> Self { + pub fn new(ty: u16, ip_addr: Option) -> Self { Self { ty, accept_any_response: ip_addr.is_none(), _reserved: 0, - ip_addr: ip_addr.unwrap_or(IpAddress([0; 16])), + ip_addr: ip_addr.unwrap_or_default(), } } - /// Returns a `None` if the any response should be accepted or the IP + /// Returns `None` if any response should be accepted, or otherwise the IP /// address of a Boot Server whose responses should be accepted. #[must_use] - pub const fn ip_addr(&self) -> Option<&IpAddress> { + pub const fn ip_addr(&self) -> Option<&EfiIpAddr> { if self.accept_any_response { None } else { @@ -741,7 +740,7 @@ impl Server { pub struct MtftpInfo { /// File multicast IP address. This is the IP address to which the server /// will send the requested file. - pub m_cast_ip: IpAddress, + pub m_cast_ip: EfiIpAddr, /// Client multicast listening port. This is the UDP port to which the /// server will send the requested file. pub c_port: u16, @@ -757,7 +756,7 @@ pub struct MtftpInfo { } impl MtftpInfo { - const fn as_raw_ptr(&self) -> *const PxeBaseCodeMtftpInfo { + const fn as_ptr(&self) -> *const PxeBaseCodeMtftpInfo { ptr::from_ref(self).cast() } } @@ -772,7 +771,7 @@ pub struct IpFilter { pub filters: IpFilters, ip_cnt: u8, _reserved: u16, - ip_list: [IpAddress; 8], + ip_list: [EfiIpAddr; 8], } impl IpFilter { @@ -782,11 +781,11 @@ impl IpFilter { /// /// Panics if `ip_list` contains more than 8 entries. #[must_use] - pub fn new(filters: IpFilters, ip_list: &[IpAddress]) -> Self { + pub fn new(filters: IpFilters, ip_list: &[EfiIpAddr]) -> Self { assert!(ip_list.len() <= 8); let ip_cnt = ip_list.len() as u8; - let mut buffer = [IpAddress([0; 16]); 8]; + let mut buffer = [EfiIpAddr::from([0; 16]); 8]; buffer[..ip_list.len()].copy_from_slice(ip_list); Self { @@ -800,7 +799,7 @@ impl IpFilter { /// A list of IP addresses other than the Station Ip that should be /// enabled. Maybe be multicast or unicast. #[must_use] - pub fn ip_list(&self) -> &[IpAddress] { + pub fn ip_list(&self) -> &[EfiIpAddr] { &self.ip_list[..usize::from(self.ip_cnt)] } } @@ -1122,8 +1121,8 @@ impl Mode { /// [`BaseCode::udp_write`], [`BaseCode::arp`] and any of the TFTP/MTFTP /// operations are called. #[must_use] - pub fn station_ip(&self) -> IpAddress { - unsafe { IpAddress::from_raw(self.0.station_ip, self.using_ipv6()) } + pub const fn station_ip(&self) -> EfiIpAddr { + self.0.station_ip } /// The device's current subnet mask. This field is initialized to a zero @@ -1135,8 +1134,8 @@ impl Mode { /// [`BaseCode::udp_read`], [`BaseCode::udp_write`], /// [`BaseCode::arp`] or any of the TFTP/MTFTP operations are called. #[must_use] - pub fn subnet_mask(&self) -> IpAddress { - unsafe { IpAddress::from_raw(self.0.subnet_mask, self.using_ipv6()) } + pub const fn subnet_mask(&self) -> EfiIpAddr { + self.0.subnet_mask } /// Cached DHCP Discover packet. This field is zero-filled by the @@ -1253,9 +1252,9 @@ impl Mode { #[derive(Debug)] pub struct ArpEntry { /// The IP address. - pub ip_addr: IpAddress, + pub ip_addr: EfiIpAddr, /// The mac address of the device that is addressed by [`Self::ip_addr`]. - pub mac_addr: MacAddress, + pub mac_addr: EfiMacAddr, } /// An entry for the route table found in [`Mode::route_table`] @@ -1265,9 +1264,9 @@ pub struct ArpEntry { #[allow(missing_docs)] #[derive(Debug)] pub struct RouteEntry { - pub ip_addr: IpAddress, - pub subnet_mask: IpAddress, - pub gw_addr: IpAddress, + pub ip_addr: EfiIpAddr, + pub subnet_mask: EfiIpAddr, + pub gw_addr: EfiIpAddr, } /// An ICMP error packet. @@ -1357,7 +1356,7 @@ pub struct TftpFileInfo<'a> { #[derive(Debug)] pub struct MtftpFileInfo<'a> { pub filename: &'a CStr8, - pub ip_address: IpAddress, + pub ip_address: EfiIpAddr, pub size: u64, pub year: u16, pub month: u8, diff --git a/uefi/src/proto/network/snp.rs b/uefi/src/proto/network/snp.rs index 208477d59..50d3c7304 100644 --- a/uefi/src/proto/network/snp.rs +++ b/uefi/src/proto/network/snp.rs @@ -9,11 +9,12 @@ //! No interface function must be called until `SimpleNetwork.start` is successfully //! called first. -use super::{IpAddress, MacAddress}; +use super::{EfiIpAddr, EfiMacAddr}; use crate::data_types::Event; use crate::proto::unsafe_protocol; use crate::{Result, StatusExt}; use core::ffi::c_void; +use core::net::IpAddr; use core::ptr; use core::ptr::NonNull; use uefi_raw::protocol::network::snp::SimpleNetworkProtocol; @@ -66,7 +67,7 @@ impl SimpleNetwork { enable: ReceiveFlags, disable: ReceiveFlags, reset_mcast_filter: bool, - mcast_filter: Option<&[MacAddress]>, + mcast_filter: Option<&[EfiMacAddr]>, ) -> Result { let filter_count = mcast_filter.map(|filters| filters.len()).unwrap_or(0); let filters = mcast_filter @@ -87,7 +88,7 @@ impl SimpleNetwork { } /// Modify or reset the current station address, if supported. - pub fn station_address(&self, reset: bool, new: Option<&MacAddress>) -> Result { + pub fn station_address(&self, reset: bool, new: Option<&EfiMacAddr>) -> Result { unsafe { (self.0.station_address)( &self.0, @@ -127,13 +128,13 @@ impl SimpleNetwork { } /// Convert a multicast IP address to a multicast HW MAC Address. - pub fn mcast_ip_to_mac(&self, ipv6: bool, ip: IpAddress) -> Result { - let mut mac_address = MacAddress([0; 32]); + pub fn mcast_ip_to_mac(&self, ipv6: bool, ip: IpAddr) -> Result { + let mut mac_address = EfiMacAddr([0; 32]); let status = unsafe { (self.0.multicast_ip_to_mac)( &self.0, Boolean::from(ipv6), - ip.as_raw_ptr(), + EfiIpAddr::from(ip).as_ptr(), &mut mac_address, ) }; @@ -191,8 +192,8 @@ impl SimpleNetwork { &self, header_size: usize, buffer: &[u8], - src_addr: Option, - dest_addr: Option, + src_addr: Option, + dest_addr: Option, protocol: Option, ) -> Result { unsafe { @@ -216,8 +217,8 @@ impl SimpleNetwork { &self, buffer: &mut [u8], header_size: Option<&mut usize>, - src_addr: Option<&mut MacAddress>, - dest_addr: Option<&mut MacAddress>, + src_addr: Option<&mut EfiMacAddr>, + dest_addr: Option<&mut EfiMacAddr>, protocol: Option<&mut u16>, ) -> Result { let mut buffer_size = buffer.len(); diff --git a/xtask/src/device_path/mod.rs b/xtask/src/device_path/mod.rs index b03fa5e03..55b2c83aa 100644 --- a/xtask/src/device_path/mod.rs +++ b/xtask/src/device_path/mod.rs @@ -79,12 +79,12 @@ fn gen_uefi_code_as_string(groups: &[NodeGroup]) -> Result { self, DevicePathHeader, DevicePathNode, DeviceSubType, DeviceType, NodeConversionError, }; - use crate::proto::network::IpAddress; use crate::mem::memory_map::MemoryType; use core::mem::{size_of, size_of_val}; use core::ptr::addr_of; use core::{fmt, slice}; use ptr_meta::Pointee; + use uefi_raw::IpAddress; #(#packed_modules)*