@@ -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,76 @@ 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
+ #[ 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
+ }
147
212
}
148
213
149
214
impl Debug for IpAddress {
150
215
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 ( )
155
217
}
156
218
}
157
219
158
220
impl Default for IpAddress {
159
221
fn default ( ) -> Self {
160
222
Self {
223
+ // Initialize all fields to zero
161
224
_align_helper : [ 0u32 ; 4 ] ,
162
225
}
163
226
}
@@ -166,16 +229,51 @@ impl Default for IpAddress {
166
229
impl From < IpAddr > for IpAddress {
167
230
fn from ( t : IpAddr ) -> Self {
168
231
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 ( ) ) ,
175
234
}
176
235
}
177
236
}
178
237
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
+
179
277
/// UEFI Media Access Control (MAC) address.
180
278
///
181
279
/// UEFI supports multiple network protocols and hardware types, not just
@@ -240,17 +338,55 @@ mod tests {
240
338
assert_eq ! ( size_of:: <Ipv6Addr >( ) , 16 ) ;
241
339
assert_eq ! ( align_of:: <Ipv6Addr >( ) , 1 ) ;
242
340
}
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`].
246
356
#[ test]
247
357
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
+ }
251
371
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) ;
255
391
}
256
392
}
0 commit comments