@@ -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,73 @@ 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+ pub const fn octets ( & self ) -> [ u8 ; 16 ] {
158+ unsafe { self . v6 . octets ( ) }
159+ }
160+
161+ /// Returns a raw pointer to the IP address.
162+ #[ must_use]
163+ pub const fn as_ptr ( & self ) -> * const Self {
164+ core:: ptr:: addr_of!( * self )
165+ }
166+
167+ /// Returns a raw mutable pointer to the IP address.
168+ #[ must_use]
169+ pub fn as_ptr_mut ( & mut self ) -> * mut Self {
170+ core:: ptr:: addr_of_mut!( * self )
171+ }
172+
173+ /// Transforms this EFI type to the Rust standard libraries type.
174+ ///
175+ /// # Arguments
176+ /// - `is_ipv6`: Whether the internal data should be interpreted as IPv6 or
177+ /// IPv4 address.
178+ pub fn to_ip_addr ( self , is_ipv6 : bool ) -> IpAddr {
179+ if is_ipv6 {
180+ IpAddr :: V6 ( Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } ) )
181+ } else {
182+ IpAddr :: V4 ( Ipv4Addr :: from ( unsafe { self . v4 . octets ( ) } ) )
183+ }
184+ }
185+
186+ /// Returns the underlying data as [`Ipv4Addr`], if only the first four
187+ /// octets are used.
188+ ///
189+ /// # Safety
190+ /// This function is not unsafe memory-wise but callers need to ensure with
191+ /// additional context that the IP is indeed an IPv4 address.
192+ pub unsafe fn as_ipv4 ( & self ) -> Result < Ipv4Addr , Ipv6Addr > {
193+ let extra = self . octets ( ) [ 4 ..] . iter ( ) . any ( |& x| x != 0 ) ;
194+ if !extra {
195+ Ok ( Ipv4Addr :: from ( unsafe { self . v4 . octets ( ) } ) )
196+ } else {
197+ Err ( Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } ) )
198+ }
199+ }
200+
201+ /// Returns the underlying data as [`Ipv6Addr`].
202+ ///
203+ /// # Safety
204+ /// This function is not unsafe memory-wise but callers need to ensure with
205+ /// additional context that the IP is indeed an IPv6 address.
206+ pub unsafe fn as_ipv6 ( & self ) -> Ipv6Addr {
207+ Ipv6Addr :: from ( unsafe { self . v6 . octets ( ) } )
208+ }
147209}
148210
149211impl Debug for IpAddress {
150212 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 ( )
213+ f. debug_tuple ( "IpAddress" ) . field ( & self . octets ( ) ) . finish ( )
155214 }
156215}
157216
158217impl Default for IpAddress {
159218 fn default ( ) -> Self {
160219 Self {
220+ // Initialize all fields to zero
161221 _align_helper : [ 0u32 ; 4 ] ,
162222 }
163223 }
@@ -166,16 +226,51 @@ impl Default for IpAddress {
166226impl From < IpAddr > for IpAddress {
167227 fn from ( t : IpAddr ) -> Self {
168228 match t {
169- IpAddr :: V4 ( ip) => Self {
170- v4 : Ipv4Addr :: from ( ip) ,
171- } ,
172- IpAddr :: V6 ( ip) => Self {
173- v6 : Ipv6Addr :: from ( ip) ,
174- } ,
229+ IpAddr :: V4 ( ip) => Self :: new_v4 ( ip. octets ( ) ) ,
230+ IpAddr :: V6 ( ip) => Self :: new_v6 ( ip. octets ( ) ) ,
231+ }
232+ }
233+ }
234+
235+ impl From < & IpAddr > for IpAddress {
236+ fn from ( t : & IpAddr ) -> Self {
237+ match t {
238+ IpAddr :: V4 ( ip) => Self :: new_v4 ( ip. octets ( ) ) ,
239+ IpAddr :: V6 ( ip) => Self :: new_v6 ( ip. octets ( ) ) ,
175240 }
176241 }
177242}
178243
244+ impl From < [ u8 ; 4 ] > for IpAddress {
245+ fn from ( octets : [ u8 ; 4 ] ) -> Self {
246+ Self :: new_v4 ( octets)
247+ }
248+ }
249+
250+ impl From < [ u8 ; 16 ] > for IpAddress {
251+ fn from ( octets : [ u8 ; 16 ] ) -> Self {
252+ Self :: new_v6 ( octets)
253+ }
254+ }
255+
256+ impl From < IpAddress > for [ u8 ; 16 ] {
257+ fn from ( value : IpAddress ) -> Self {
258+ value. octets ( )
259+ }
260+ }
261+
262+ impl From < Ipv4Addr > for IpAddress {
263+ fn from ( value : Ipv4Addr ) -> Self {
264+ Self :: new_v4 ( value. octets ( ) )
265+ }
266+ }
267+
268+ impl From < Ipv6Addr > for IpAddress {
269+ fn from ( value : Ipv6Addr ) -> Self {
270+ Self :: new_v6 ( value. octets ( ) )
271+ }
272+ }
273+
179274/// UEFI Media Access Control (MAC) address.
180275///
181276/// UEFI supports multiple network protocols and hardware types, not just
@@ -240,17 +335,55 @@ mod tests {
240335 assert_eq ! ( size_of:: <Ipv6Addr >( ) , 16 ) ;
241336 assert_eq ! ( align_of:: <Ipv6Addr >( ) , 1 ) ;
242337 }
243- /// Test conversion from `core::net::IpAddr` to `IpvAddress`.
244- ///
245- /// Note that conversion in the other direction is not possible.
338+
339+ #[ test]
340+ fn ip_ptr ( ) {
341+ let mut ip = IpAddress :: new_v4 ( [ 0 ; 4 ] ) ;
342+ let ptr = ip. as_ptr_mut ( ) . cast :: < u8 > ( ) ;
343+ unsafe {
344+ core:: ptr:: write ( ptr, 192 ) ;
345+ core:: ptr:: write ( ptr. add ( 1 ) , 168 ) ;
346+ core:: ptr:: write ( ptr. add ( 2 ) , 42 ) ;
347+ core:: ptr:: write ( ptr. add ( 3 ) , 73 ) ;
348+ }
349+ unsafe { assert_eq ! ( ip. v4. octets( ) , [ 192 , 168 , 42 , 73 ] ) }
350+ }
351+
352+ /// Test conversion from [`IpAddr`] to [`IpAddress`].
246353 #[ test]
247354 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 ) ;
355+ // Reference: std types
356+ let core_ipv4_v4 = Ipv4Addr :: from ( TEST_IPV4 ) ;
357+ let core_ipv4 = IpAddr :: from ( core_ipv4_v4) ;
358+ let core_ipv6_v6 = Ipv6Addr :: from ( TEST_IPV6 ) ;
359+ let core_ipv6 = IpAddr :: from ( core_ipv6_v6) ;
360+
361+ // Test From [u8; N] constructors
362+ assert_eq ! ( IpAddress :: from( TEST_IPV4 ) . octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
363+ assert_eq ! ( IpAddress :: from( TEST_IPV6 ) . octets( ) , TEST_IPV6 ) ;
364+ {
365+ let bytes: [ u8 ; 16 ] = IpAddress :: from ( TEST_IPV6 ) . into ( ) ;
366+ assert_eq ! ( bytes, TEST_IPV6 ) ;
367+ }
251368
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 ) ;
369+ // Test From::from std type constructors
370+ let efi_ipv4 = IpAddress :: from ( core_ipv4) ;
371+ assert_eq ! ( efi_ipv4. octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
372+ assert_eq ! ( unsafe { efi_ipv4. as_ipv4( ) . unwrap( ) } , core_ipv4) ;
373+
374+ let efi_ipv6 = IpAddress :: from ( core_ipv6) ;
375+ assert_eq ! ( efi_ipv6. octets( ) , TEST_IPV6 ) ;
376+ assert_eq ! ( unsafe { efi_ipv6. as_ipv4( ) . unwrap_err( ) } , core_ipv6) ;
377+ assert_eq ! ( unsafe { efi_ipv6. as_ipv6( ) } , core_ipv6) ;
378+
379+ // Test From::from std type constructors
380+ let efi_ipv4 = IpAddress :: from ( core_ipv4_v4) ;
381+ assert_eq ! ( efi_ipv4. octets( ) [ 0 ..4 ] , TEST_IPV4 ) ;
382+ assert_eq ! ( unsafe { efi_ipv4. as_ipv4( ) . unwrap( ) } , core_ipv4) ;
383+
384+ let efi_ipv6 = IpAddress :: from ( core_ipv6_v6) ;
385+ assert_eq ! ( efi_ipv6. octets( ) , TEST_IPV6 ) ;
386+ assert_eq ! ( unsafe { efi_ipv6. as_ipv4( ) . unwrap_err( ) } , core_ipv6) ;
387+ assert_eq ! ( unsafe { efi_ipv6. as_ipv6( ) } , core_ipv6) ;
255388 }
256389}
0 commit comments