@@ -113,6 +113,12 @@ 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`].
119+ ///
120+ /// The constructors ensure that all unused bytes of these type are always
121+ /// initialized to zero.
116122#[ derive( Clone , Copy ) ]
117123#[ repr( C ) ]
118124pub union IpAddress {
@@ -132,9 +138,10 @@ impl IpAddress {
132138 /// Construct a new IPv4 address.
133139 #[ must_use]
134140 pub fn new_v4 ( ip_addr : [ u8 ; 4 ] ) -> Self {
135- Self {
136- v4 : Ipv4Addr :: from ( ip_addr) ,
137- }
141+ // Initialize all bytes to zero first.
142+ let mut obj = Self :: default ( ) ;
143+ obj. v4 = Ipv4Addr :: from ( ip_addr) ;
144+ obj
138145 }
139146
140147 /// Construct a new IPv6 address.
@@ -144,20 +151,76 @@ impl IpAddress {
144151 v6 : Ipv6Addr :: from ( ip_addr) ,
145152 }
146153 }
154+
155+ /// Returns the octets of the union. Without additional context, it is not
156+ /// clear whether the octets represent an IPv4 or IPv6 address.
157+ #[ must_use]
158+ pub const fn octets ( & self ) -> [ u8 ; 16 ] {
159+ unsafe { self . v6 . octets ( ) }
160+ }
161+
162+ /// Returns a raw pointer to the IP address.
163+ #[ must_use]
164+ pub const fn as_ptr ( & self ) -> * const Self {
165+ core:: ptr:: addr_of!( * self )
166+ }
167+
168+ /// Returns a raw mutable pointer to the IP address.
169+ #[ must_use]
170+ pub fn as_ptr_mut ( & mut self ) -> * mut Self {
171+ core:: ptr:: addr_of_mut!( * self )
172+ }
173+
174+ /// Transforms this EFI type to the Rust standard libraries type.
175+ ///
176+ /// # Arguments
177+ /// - `is_ipv6`: Whether the internal data should be interpreted as IPv6 or
178+ /// IPv4 address.
179+ #[ must_use]
180+ pub fn to_ip_addr ( self , is_ipv6 : bool ) -> IpAddr {
181+ if is_ipv6 {
182+ IpAddr :: V6 ( Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } ) )
183+ } else {
184+ IpAddr :: V4 ( Ipv4Addr :: from ( unsafe { self . v4 . octets ( ) } ) )
185+ }
186+ }
187+
188+ /// Returns the underlying data as [`Ipv4Addr`], if only the first four
189+ /// octets are used.
190+ ///
191+ /// # Safety
192+ /// This function is not unsafe memory-wise but callers need to ensure with
193+ /// additional context that the IP is indeed an IPv4 address.
194+ pub unsafe fn as_ipv4 ( & self ) -> Result < Ipv4Addr , Ipv6Addr > {
195+ let extra = self . octets ( ) [ 4 ..] . iter ( ) . any ( |& x| x != 0 ) ;
196+ if !extra {
197+ Ok ( Ipv4Addr :: from ( unsafe { self . v4 . octets ( ) } ) )
198+ } else {
199+ Err ( Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } ) )
200+ }
201+ }
202+
203+ /// Returns the underlying data as [`Ipv6Addr`].
204+ ///
205+ /// # Safety
206+ /// This function is not unsafe memory-wise but callers need to ensure with
207+ /// additional context that the IP is indeed an IPv6 address.
208+ #[ must_use]
209+ pub unsafe fn as_ipv6 ( & self ) -> Ipv6Addr {
210+ Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } )
211+ }
147212}
148213
149214impl Debug for IpAddress {
150215 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 ( )
216+ f. debug_tuple ( "IpAddress" ) . field ( & self . octets ( ) ) . finish ( )
155217 }
156218}
157219
158220impl Default for IpAddress {
159221 fn default ( ) -> Self {
160222 Self {
223+ // Initialize all fields to zero
161224 _align_helper : [ 0u32 ; 4 ] ,
162225 }
163226 }
@@ -166,16 +229,51 @@ impl Default for IpAddress {
166229impl From < IpAddr > for IpAddress {
167230 fn from ( t : IpAddr ) -> Self {
168231 match t {
169- IpAddr :: V4 ( ip) => Self {
170- v4 : Ipv4Addr :: from ( ip) ,
171- } ,
172- IpAddr :: V6 ( ip) => Self {
173- v6 : Ipv6Addr :: from ( ip) ,
174- } ,
232+ IpAddr :: V4 ( ip) => Self :: new_v4 ( ip. octets ( ) ) ,
233+ IpAddr :: V6 ( ip) => Self :: new_v6 ( ip. octets ( ) ) ,
175234 }
176235 }
177236}
178237
238+ impl From < & IpAddr > for IpAddress {
239+ fn from ( t : & IpAddr ) -> Self {
240+ match t {
241+ IpAddr :: V4 ( ip) => Self :: new_v4 ( ip. octets ( ) ) ,
242+ IpAddr :: V6 ( ip) => Self :: new_v6 ( ip. octets ( ) ) ,
243+ }
244+ }
245+ }
246+
247+ impl From < [ u8 ; 4 ] > for IpAddress {
248+ fn from ( octets : [ u8 ; 4 ] ) -> Self {
249+ Self :: new_v4 ( octets)
250+ }
251+ }
252+
253+ impl From < [ u8 ; 16 ] > for IpAddress {
254+ fn from ( octets : [ u8 ; 16 ] ) -> Self {
255+ Self :: new_v6 ( octets)
256+ }
257+ }
258+
259+ impl From < IpAddress > for [ u8 ; 16 ] {
260+ fn from ( value : IpAddress ) -> Self {
261+ value. octets ( )
262+ }
263+ }
264+
265+ impl From < Ipv4Addr > for IpAddress {
266+ fn from ( value : Ipv4Addr ) -> Self {
267+ Self :: new_v4 ( value. octets ( ) )
268+ }
269+ }
270+
271+ impl From < Ipv6Addr > for IpAddress {
272+ fn from ( value : Ipv6Addr ) -> Self {
273+ Self :: new_v6 ( value. octets ( ) )
274+ }
275+ }
276+
179277/// UEFI Media Access Control (MAC) address.
180278///
181279/// UEFI supports multiple network protocols and hardware types, not just
@@ -240,17 +338,55 @@ mod tests {
240338 assert_eq ! ( size_of:: <Ipv6Addr >( ) , 16 ) ;
241339 assert_eq ! ( align_of:: <Ipv6Addr >( ) , 1 ) ;
242340 }
243- /// Test conversion from `core::net::IpAddr` to `IpvAddress`.
244- ///
245- /// Note that conversion in the other direction is not possible.
341+
342+ #[ test]
343+ fn ip_ptr ( ) {
344+ let mut ip = IpAddress :: new_v4 ( [ 0 ; 4 ] ) ;
345+ let ptr = ip. as_ptr_mut ( ) . cast :: < u8 > ( ) ;
346+ unsafe {
347+ core:: ptr:: write ( ptr, 192 ) ;
348+ core:: ptr:: write ( ptr. add ( 1 ) , 168 ) ;
349+ core:: ptr:: write ( ptr. add ( 2 ) , 42 ) ;
350+ core:: ptr:: write ( ptr. add ( 3 ) , 73 ) ;
351+ }
352+ unsafe { assert_eq ! ( ip. v4. octets( ) , [ 192 , 168 , 42 , 73 ] ) }
353+ }
354+
355+ /// Test conversion from [`IpAddr`] to [`IpAddress`].
246356 #[ test]
247357 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 ) ;
358+ // Reference: std types
359+ let core_ipv4_v4 = Ipv4Addr :: from ( TEST_IPV4 ) ;
360+ let core_ipv4 = IpAddr :: from ( core_ipv4_v4) ;
361+ let core_ipv6_v6 = Ipv6Addr :: from ( TEST_IPV6 ) ;
362+ let core_ipv6 = IpAddr :: from ( core_ipv6_v6) ;
363+
364+ // Test From [u8; N] constructors
365+ assert_eq ! ( IpAddress :: from( TEST_IPV4 ) . octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
366+ assert_eq ! ( IpAddress :: from( TEST_IPV6 ) . octets( ) , TEST_IPV6 ) ;
367+ {
368+ let bytes: [ u8 ; 16 ] = IpAddress :: from ( TEST_IPV6 ) . into ( ) ;
369+ assert_eq ! ( bytes, TEST_IPV6 ) ;
370+ }
251371
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 ) ;
372+ // Test From::from std type constructors
373+ let efi_ipv4 = IpAddress :: from ( core_ipv4) ;
374+ assert_eq ! ( efi_ipv4. octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
375+ assert_eq ! ( unsafe { efi_ipv4. as_ipv4( ) . unwrap( ) } , core_ipv4) ;
376+
377+ let efi_ipv6 = IpAddress :: from ( core_ipv6) ;
378+ assert_eq ! ( efi_ipv6. octets( ) , TEST_IPV6 ) ;
379+ assert_eq ! ( unsafe { efi_ipv6. as_ipv4( ) . unwrap_err( ) } , core_ipv6) ;
380+ assert_eq ! ( unsafe { efi_ipv6. as_ipv6( ) } , core_ipv6) ;
381+
382+ // Test From::from std type constructors
383+ let efi_ipv4 = IpAddress :: from ( core_ipv4_v4) ;
384+ assert_eq ! ( efi_ipv4. octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
385+ assert_eq ! ( unsafe { efi_ipv4. as_ipv4( ) . unwrap( ) } , core_ipv4) ;
386+
387+ let efi_ipv6 = IpAddress :: from ( core_ipv6_v6) ;
388+ assert_eq ! ( efi_ipv6. octets( ) , TEST_IPV6 ) ;
389+ assert_eq ! ( unsafe { efi_ipv6. as_ipv4( ) . unwrap_err( ) } , core_ipv6) ;
390+ assert_eq ! ( unsafe { efi_ipv6. as_ipv6( ) } , core_ipv6) ;
255391 }
256392}
0 commit comments