@@ -113,6 +113,12 @@ 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`].
119
+ ///
120
+ /// The constructors ensure that all unused bytes of these type are always
121
+ /// initialized to zero.
116
122
#[ derive( Clone , Copy ) ]
117
123
#[ repr( C ) ]
118
124
pub union IpAddress {
@@ -132,9 +138,10 @@ impl IpAddress {
132
138
/// Construct a new IPv4 address.
133
139
#[ must_use]
134
140
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
138
145
}
139
146
140
147
/// Construct a new IPv6 address.
@@ -144,20 +151,73 @@ impl IpAddress {
144
151
v6 : Ipv6Addr :: from ( ip_addr) ,
145
152
}
146
153
}
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
+ }
147
209
}
148
210
149
211
impl Debug for IpAddress {
150
212
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 ( )
155
214
}
156
215
}
157
216
158
217
impl Default for IpAddress {
159
218
fn default ( ) -> Self {
160
219
Self {
220
+ // Initialize all fields to zero
161
221
_align_helper : [ 0u32 ; 4 ] ,
162
222
}
163
223
}
@@ -166,16 +226,51 @@ impl Default for IpAddress {
166
226
impl From < IpAddr > for IpAddress {
167
227
fn from ( t : IpAddr ) -> Self {
168
228
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 ( ) ) ,
175
240
}
176
241
}
177
242
}
178
243
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
+
179
274
/// UEFI Media Access Control (MAC) address.
180
275
///
181
276
/// UEFI supports multiple network protocols and hardware types, not just
@@ -240,17 +335,55 @@ mod tests {
240
335
assert_eq ! ( size_of:: <Ipv6Addr >( ) , 16 ) ;
241
336
assert_eq ! ( align_of:: <Ipv6Addr >( ) , 1 ) ;
242
337
}
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`].
246
353
#[ test]
247
354
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
+ }
251
368
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) ;
255
388
}
256
389
}
0 commit comments