1use core::fmt::{self, Debug, Display, Formatter};
12
13#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
22#[repr(transparent)]
23pub struct Ipv4Address(pub [u8; 4]);
24
25impl Ipv4Address {
26 #[must_use]
28 pub const fn octets(self) -> [u8; 4] {
29 self.0
30 }
31}
32
33impl From<core::net::Ipv4Addr> for Ipv4Address {
34 fn from(ip: core::net::Ipv4Addr) -> Self {
35 Self(ip.octets())
36 }
37}
38
39impl From<Ipv4Address> for core::net::Ipv4Addr {
40 fn from(ip: Ipv4Address) -> Self {
41 Self::from(ip.0)
42 }
43}
44
45impl From<[u8; 4]> for Ipv4Address {
46 fn from(octets: [u8; 4]) -> Self {
47 Self(octets)
48 }
49}
50
51impl Display for Ipv4Address {
52 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
53 let ip = core::net::Ipv4Addr::from(*self);
54 write!(f, "{}", ip)
55 }
56}
57
58#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
67#[repr(transparent)]
68pub struct Ipv6Address(pub [u8; 16]);
69
70impl Ipv6Address {
71 #[must_use]
73 pub const fn octets(self) -> [u8; 16] {
74 self.0
75 }
76}
77
78impl From<core::net::Ipv6Addr> for Ipv6Address {
79 fn from(ip: core::net::Ipv6Addr) -> Self {
80 Self(ip.octets())
81 }
82}
83
84impl From<Ipv6Address> for core::net::Ipv6Addr {
85 fn from(ip: Ipv6Address) -> Self {
86 Self::from(ip.0)
87 }
88}
89
90impl From<[u8; 16]> for Ipv6Address {
91 fn from(octets: [u8; 16]) -> Self {
92 Self(octets)
93 }
94}
95
96impl Display for Ipv6Address {
97 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
98 let ip = core::net::Ipv6Addr::from(*self);
99 write!(f, "{}", ip)
100 }
101}
102
103#[derive(Clone, Copy)]
119#[repr(C)]
120pub union IpAddress {
121 pub addr: [u32; 4],
125
126 pub v4: Ipv4Address,
128
129 pub v6: Ipv6Address,
131}
132
133impl IpAddress {
134 pub const ZERO: Self = Self { addr: [0; 4] };
136
137 #[must_use]
145 pub const fn new_v4(octets: [u8; 4]) -> Self {
146 Self {
147 v4: Ipv4Address(octets),
148 }
149 }
150
151 #[must_use]
156 pub const fn new_v6(octets: [u8; 16]) -> Self {
157 Self {
158 v6: Ipv6Address(octets),
159 }
160 }
161
162 #[must_use]
173 pub unsafe fn into_core_addr(self, is_ipv6: bool) -> core::net::IpAddr {
174 if is_ipv6 {
175 core::net::IpAddr::V6(core::net::Ipv6Addr::from(unsafe { self.v6.octets() }))
177 } else {
178 core::net::IpAddr::V4(core::net::Ipv4Addr::from(unsafe { self.v4.octets() }))
180 }
181 }
182}
183
184impl Debug for IpAddress {
185 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
186 f.debug_struct("IpAddress").finish()
190 }
191}
192
193impl Default for IpAddress {
194 fn default() -> Self {
195 Self::ZERO
196 }
197}
198
199impl From<core::net::IpAddr> for IpAddress {
200 fn from(t: core::net::IpAddr) -> Self {
201 match t {
202 core::net::IpAddr::V4(ip) => Self::new_v4(ip.octets()),
203 core::net::IpAddr::V6(ip) => Self::new_v6(ip.octets()),
204 }
205 }
206}
207
208impl From<core::net::Ipv4Addr> for IpAddress {
209 fn from(value: core::net::Ipv4Addr) -> Self {
210 Self::new_v4(value.octets())
211 }
212}
213
214impl From<core::net::Ipv6Addr> for IpAddress {
215 fn from(value: core::net::Ipv6Addr) -> Self {
216 Self::new_v6(value.octets())
217 }
218}
219
220impl From<[u8; 4]> for IpAddress {
221 fn from(octets: [u8; 4]) -> Self {
222 Self::new_v4(octets)
223 }
224}
225
226impl From<[u8; 16]> for IpAddress {
227 fn from(octets: [u8; 16]) -> Self {
228 Self::new_v6(octets)
229 }
230}
231
232#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
249#[repr(transparent)]
250pub struct MacAddress(pub [u8; 32]);
251
252impl MacAddress {
253 #[must_use]
255 pub const fn octets(self) -> [u8; 32] {
256 self.0
257 }
258
259 #[must_use]
262 pub fn into_ethernet_addr(self) -> [u8; 6] {
263 let mut buffer = [0; 6];
264 buffer.copy_from_slice(&self.octets()[6..]);
265 buffer
266 }
267}
268
269impl From<[u8; 6]> for MacAddress {
271 fn from(octets: [u8; 6]) -> Self {
272 let mut buffer = [0; 32];
273 buffer[..6].copy_from_slice(&octets);
274 Self(buffer)
275 }
276}
277
278impl From<MacAddress> for [u8; 6] {
280 fn from(MacAddress(o): MacAddress) -> Self {
281 [o[0], o[1], o[2], o[3], o[4], o[5]]
282 }
283}
284
285impl From<[u8; 32]> for MacAddress {
287 fn from(octets: [u8; 32]) -> Self {
288 Self(octets)
289 }
290}
291
292#[cfg(test)]
293mod tests {
294 use super::*;
295
296 const TEST_IPV4: [u8; 4] = [91, 92, 93, 94];
297 const TEST_IPV6: [u8; 16] = [
298 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
299 ];
300
301 #[test]
303 fn test_ip_addr4_conversion() {
304 let uefi_addr = Ipv4Address(TEST_IPV4);
305 let core_addr = core::net::Ipv4Addr::from(uefi_addr);
306 assert_eq!(uefi_addr, Ipv4Address::from(core_addr));
307 }
308
309 #[test]
311 fn test_ip_addr6_conversion() {
312 let uefi_addr = Ipv6Address(TEST_IPV6);
313 let core_addr = core::net::Ipv6Addr::from(uefi_addr);
314 assert_eq!(uefi_addr, Ipv6Address::from(core_addr));
315 }
316
317 #[test]
321 fn test_ip_addr_conversion() {
322 let core_addr = core::net::IpAddr::V4(core::net::Ipv4Addr::from(TEST_IPV4));
323 let uefi_addr = IpAddress::from(core_addr);
324 assert_eq!(unsafe { uefi_addr.v4.0 }, TEST_IPV4);
325
326 let core_addr = core::net::IpAddr::V6(core::net::Ipv6Addr::from(TEST_IPV6));
327 let uefi_addr = IpAddress::from(core_addr);
328 assert_eq!(unsafe { uefi_addr.v6.0 }, TEST_IPV6);
329 }
330
331 #[test]
334 fn test_efi_ip_address_abi() {
335 #[repr(C, packed)]
336 struct PackedHelper<T>(T);
337
338 assert_eq!(align_of::<IpAddress>(), 4);
339 assert_eq!(size_of::<IpAddress>(), 16);
340
341 assert_eq!(align_of::<PackedHelper<IpAddress>>(), 1);
342 assert_eq!(size_of::<PackedHelper<IpAddress>>(), 16);
343 }
344
345 #[test]
347 fn test_promised_from_impls() {
348 {
350 let octets = [0_u8, 1, 2, 3];
351 assert_eq!(Ipv4Address::from(octets), Ipv4Address(octets));
352 let uefi_addr = IpAddress::from(octets);
353 assert_eq!(&octets, &unsafe { uefi_addr.v4.octets() });
354 }
355 {
357 let octets = [0_u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
358 assert_eq!(Ipv6Address::from(octets), Ipv6Address(octets));
359 let uefi_addr = IpAddress::from(octets);
360 assert_eq!(&octets, &unsafe { uefi_addr.v6.octets() });
361 }
362 {
364 let octets = [7, 5, 3, 1];
365 let core_ipv4_addr = core::net::Ipv4Addr::from(octets);
366 assert_eq!(Ipv4Address::from(core_ipv4_addr).octets(), octets);
367 assert_eq!(
368 unsafe { IpAddress::from(core_ipv4_addr).v4.octets() },
369 octets
370 );
371 }
372 {
374 let octets = [7, 5, 3, 1, 6, 3, 8, 5, 2, 5, 2, 7, 3, 5, 2, 6];
375 let core_ipv6_addr = core::net::Ipv6Addr::from(octets);
376 assert_eq!(Ipv6Address::from(core_ipv6_addr).octets(), octets);
377 assert_eq!(
378 unsafe { IpAddress::from(core_ipv6_addr).v6.octets() },
379 octets
380 );
381 }
382 {
384 let octets = [8, 8, 2, 6];
385 let core_ip_addr = core::net::IpAddr::from(octets);
386 assert_eq!(unsafe { IpAddress::from(core_ip_addr).v4.octets() }, octets);
387 }
388 {
390 let octets = [8, 8, 2, 6, 6, 7];
391 let uefi_mac_addr = MacAddress::from(octets);
392 assert_eq!(uefi_mac_addr.octets()[0..6], octets);
393 let octets2: [u8; 6] = uefi_mac_addr.into();
394 assert_eq!(octets2, octets)
395 }
396 {
398 let octets = [
399 8_u8, 8, 2, 6, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 7, 0, 0, 0,
400 0, 0, 0, 0, 42,
401 ];
402 let uefi_mac_addr = MacAddress::from(octets);
403 assert_eq!(uefi_mac_addr.octets(), octets);
404 }
405 }
406
407 #[test]
413 fn test_uefi_flow() {
414 fn efi_retrieve_efi_ip_addr(addr: *mut IpAddress, is_ipv6: bool) {
415 let addr = unsafe { addr.as_mut().unwrap() };
416 unsafe {
418 addr.v4.0[0] = 42;
419 addr.v4.0[1] = 42;
420 addr.v4.0[2] = 42;
421 addr.v4.0[3] = 42;
422 }
423 if is_ipv6 {
424 unsafe {
425 addr.v6.0[14] = 42;
426 addr.v6.0[15] = 42;
427 }
428 }
429 }
430
431 fn high_level_retrieve_ip(is_ipv6: bool) -> core::net::IpAddr {
432 let mut efi_ip_addr = IpAddress::ZERO;
433 efi_retrieve_efi_ip_addr(&mut efi_ip_addr, is_ipv6);
434 unsafe { efi_ip_addr.into_core_addr(is_ipv6) }
435 }
436
437 let ipv4_addr = high_level_retrieve_ip(false);
438 let ipv4_addr: core::net::Ipv4Addr = match ipv4_addr {
439 core::net::IpAddr::V4(ipv4_addr) => ipv4_addr,
440 core::net::IpAddr::V6(_) => panic!("should not happen"),
441 };
442 assert_eq!(ipv4_addr.octets(), [42, 42, 42, 42]);
443
444 let ipv6_addr = high_level_retrieve_ip(true);
445 let ipv6_addr: core::net::Ipv6Addr = match ipv6_addr {
446 core::net::IpAddr::V6(ipv6_addr) => ipv6_addr,
447 core::net::IpAddr::V4(_) => panic!("should not happen"),
448 };
449 let expected = [42, 42, 42, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 42];
450 assert_eq!(ipv6_addr.octets(), expected);
451 }
452}