@@ -113,6 +113,9 @@ impl From<Boolean> for bool {
113
113
/// type is defined in the same way as edk2 for compatibility with C code. Note
114
114
/// that this is an **untagged union**, so there's no way to tell which type of
115
115
/// 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`].
116
119
#[ derive( Clone , Copy ) ]
117
120
#[ repr( C ) ]
118
121
pub union IpAddress {
@@ -144,14 +147,66 @@ impl IpAddress {
144
147
v6 : Ipv6Addr :: from ( ip_addr) ,
145
148
}
146
149
}
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
+ }
147
205
}
148
206
149
207
impl Debug for IpAddress {
150
208
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 ( )
155
210
}
156
211
}
157
212
@@ -176,6 +231,41 @@ impl From<IpAddr> for IpAddress {
176
231
}
177
232
}
178
233
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
+
179
269
/// UEFI Media Access Control (MAC) address.
180
270
///
181
271
/// UEFI supports multiple network protocols and hardware types, not just
@@ -240,17 +330,43 @@ mod tests {
240
330
assert_eq ! ( size_of:: <Ipv6Addr >( ) , 16 ) ;
241
331
assert_eq ! ( align_of:: <Ipv6Addr >( ) , 1 ) ;
242
332
}
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`].
246
348
#[ test]
247
349
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) ;
251
366
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) ;
255
371
}
256
372
}
0 commit comments