@@ -113,6 +113,9 @@ impl From<Boolean> for bool {
113113/// type is defined in the same way as edk2 for compatibility with C code. Note
114114/// that this is an **untagged union**, so there's no way to tell which type of
115115/// address an `IpAddress` value contains without additional context.
116+ ///
117+ /// For convenience, this type is tightly integrated with the Rust standard
118+ /// library types [`IpAddr`], [`Ipv4Addr`], and [`IpV6Addr`].
116119#[ derive( Clone , Copy ) ]
117120#[ repr( C ) ]
118121pub union IpAddress {
@@ -144,14 +147,66 @@ impl IpAddress {
144147 v6 : Ipv6Addr :: from ( ip_addr) ,
145148 }
146149 }
150+
151+ /// Returns the octets of the union. Without additional context, it is not
152+ /// clear whether the octets represent an IPv4 or IPv6 address.
153+ pub const fn octets ( & self ) -> [ u8 ; 16 ] {
154+ unsafe { self . v6 . octets ( ) }
155+ }
156+
157+ /// Returns a raw pointer to the IP address.
158+ #[ must_use]
159+ pub const fn as_ptr ( & self ) -> * const Self {
160+ core:: ptr:: addr_of!( * self )
161+ }
162+
163+ /// Returns a raw mutable pointer to the IP address.
164+ #[ must_use]
165+ pub fn as_ptr_mut ( & mut self ) -> * mut Self {
166+ core:: ptr:: addr_of_mut!( * self )
167+ }
168+
169+ /// Transforms this EFI type to the Rust standard libraries type.
170+ ///
171+ /// # Arguments
172+ /// - `is_ipv6`: Whether the internal data should be interpreted as IPv6 or
173+ /// IPv4 address.
174+ pub fn to_ip_addr ( self , is_ipv6 : bool ) -> IpAddr {
175+ if is_ipv6 {
176+ IpAddr :: V6 ( Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } ) )
177+ } else {
178+ IpAddr :: V4 ( Ipv4Addr :: from ( unsafe { self . v4 . octets ( ) } ) )
179+ }
180+ }
181+
182+ /// Returns the underlying data as [`Ipv4Addr`], if only the first four
183+ /// octets are used.
184+ ///
185+ /// # Safety
186+ /// This function is not unsafe memory-wise but callers need to ensure with
187+ /// additional context that the IP is indeed an IPv4 address.
188+ pub unsafe fn as_ipv4 ( & self ) -> Result < Ipv4Addr , Ipv6Addr > {
189+ let extra = self . octets ( ) [ 4 ..] . iter ( ) . any ( |& x| x != 0 ) ;
190+ if extra {
191+ Ok ( Ipv4Addr :: from ( unsafe { self . v4 . octets ( ) } ) )
192+ } else {
193+ Err ( Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } ) )
194+ }
195+ }
196+
197+ /// Returns the underlying data as [`Ipv6Addr`].
198+ ///
199+ /// # Safety
200+ /// This function is not unsafe memory-wise but callers need to ensure with
201+ /// additional context that the IP is indeed an IPv6 address.
202+ pub unsafe fn as_ipv6 ( & self ) -> Ipv6Addr {
203+ Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } )
204+ }
147205}
148206
149207impl Debug for IpAddress {
150208 fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
151- // The type is an untagged union, so we don't know whether it contains
152- // an IPv4 or IPv6 address. It's also not safe to just print the whole
153- // 16 bytes, since they might not all be initialized.
154- f. debug_struct ( "IpAddress" ) . finish ( )
209+ f. debug_tuple ( "IpAddress" ) . field ( & self . octets ( ) ) . finish ( )
155210 }
156211}
157212
@@ -176,6 +231,41 @@ impl From<IpAddr> for IpAddress {
176231 }
177232}
178233
234+ impl From < & IpAddr > for IpAddress {
235+ fn from ( t : & IpAddr ) -> Self {
236+ match t {
237+ IpAddr :: V4 ( ip) => Self {
238+ v4 : Ipv4Addr :: from ( * ip) ,
239+ } ,
240+ IpAddr :: V6 ( ip) => Self {
241+ v6 : Ipv6Addr :: from ( * ip) ,
242+ } ,
243+ }
244+ }
245+ }
246+
247+ impl From < [ u8 ; 4 ] > for IpAddress {
248+ fn from ( value : [ u8 ; 4 ] ) -> Self {
249+ Self {
250+ v4 : Ipv4Addr :: from ( value) ,
251+ }
252+ }
253+ }
254+
255+ impl From < [ u8 ; 16 ] > for IpAddress {
256+ fn from ( value : [ u8 ; 16 ] ) -> Self {
257+ Self {
258+ v6 : Ipv6Addr :: from ( value) ,
259+ }
260+ }
261+ }
262+
263+ impl From < IpAddress > for [ u8 ; 16 ] {
264+ fn from ( value : IpAddress ) -> Self {
265+ value. octets ( )
266+ }
267+ }
268+
179269/// UEFI Media Access Control (MAC) address.
180270///
181271/// UEFI supports multiple network protocols and hardware types, not just
@@ -240,17 +330,43 @@ mod tests {
240330 assert_eq ! ( size_of:: <Ipv6Addr >( ) , 16 ) ;
241331 assert_eq ! ( align_of:: <Ipv6Addr >( ) , 1 ) ;
242332 }
243- /// Test conversion from `core::net::IpAddr` to `IpvAddress`.
244- ///
245- /// Note that conversion in the other direction is not possible.
333+
334+ #[ test]
335+ fn ip_ptr ( ) {
336+ let mut ip = IpAddress :: new_v4 ( [ 0 ; 4 ] ) ;
337+ let ptr = ip. as_ptr_mut ( ) . cast :: < u8 > ( ) ;
338+ unsafe {
339+ core:: ptr:: write ( ptr, 192 ) ;
340+ core:: ptr:: write ( ptr. add ( 1 ) , 168 ) ;
341+ core:: ptr:: write ( ptr. add ( 2 ) , 42 ) ;
342+ core:: ptr:: write ( ptr. add ( 3 ) , 73 ) ;
343+ }
344+ unsafe { assert_eq ! ( ip. v4. octets( ) , [ 192 , 168 , 42 , 73 ] ) }
345+ }
346+
347+ /// Test conversion from [`IpAddr`] to [`IpAddress`].
246348 #[ test]
247349 fn test_ip_addr_conversion ( ) {
248- let core_addr = IpAddr :: V4 ( core:: net:: Ipv4Addr :: from ( TEST_IPV4 ) ) ;
249- let uefi_addr = IpAddress :: from ( core_addr) ;
250- assert_eq ! ( unsafe { uefi_addr. v4. octets( ) } , TEST_IPV4 ) ;
350+ // Reference: std types
351+ let core_ipv4 = IpAddr :: from ( TEST_IPV4 ) ;
352+ let core_ipv6 = IpAddr :: from ( TEST_IPV6 ) ;
353+
354+ // Test From [u8; N] constructors
355+ assert_eq ! ( IpAddress :: from( TEST_IPV4 ) . octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
356+ assert_eq ! ( IpAddress :: from( TEST_IPV6 ) . octets( ) , TEST_IPV6 ) ;
357+ {
358+ let bytes: [ u8 ; 16 ] = IpAddress :: from ( TEST_IPV6 ) . into ( ) ;
359+ assert_eq ! ( bytes, TEST_IPV6 ) ;
360+ }
361+
362+ // Test from std type constructors
363+ let efi_ipv4 = IpAddress :: from ( core_ipv4) ;
364+ assert_eq ! ( efi_ipv4. octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
365+ assert_eq ! ( unsafe { efi_ipv4. as_ipv4( ) . unwrap( ) } , core_ipv4) ;
251366
252- let core_addr = IpAddr :: V6 ( core:: net:: Ipv6Addr :: from ( TEST_IPV6 ) ) ;
253- let uefi_addr = IpAddress :: from ( core_addr) ;
254- assert_eq ! ( unsafe { uefi_addr. v6. octets( ) } , TEST_IPV6 ) ;
367+ let efi_ipv6 = IpAddress :: from ( core_ipv6) ;
368+ assert_eq ! ( efi_ipv6. octets( ) , TEST_IPV6 ) ;
369+ assert_eq ! ( unsafe { efi_ipv4. as_ipv4( ) . unwrap_err( ) } , core_ipv6) ;
370+ assert_eq ! ( unsafe { efi_ipv4. as_ipv6( ) } , core_ipv6) ;
255371 }
256372}
0 commit comments