Skip to content

Commit b562456

Browse files
uefi: Make pxe::Mode an opaque struct
Methods are now provided to access mode data instead of direct field access. In a later PR, this will help with switching the public API to use `core::net::IpAddr`.
1 parent 322fa3e commit b562456

File tree

4 files changed

+176
-45
lines changed

4 files changed

+176
-45
lines changed

uefi-test-runner/src/proto/network/pxe.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub fn test() {
2424
.dhcp(false)
2525
.expect("failed to complete a dhcpv4 handshake");
2626

27-
assert!(base_code.mode().dhcp_ack_received);
28-
let dhcp_ack: &DhcpV4Packet = base_code.mode().dhcp_ack.as_ref();
27+
assert!(base_code.mode().dhcp_ack_received());
28+
let dhcp_ack: &DhcpV4Packet = base_code.mode().dhcp_ack().as_ref();
2929
let server_ip = dhcp_ack.bootp_si_addr;
3030
let server_ip = IpAddress::new_v4(server_ip);
3131

@@ -75,7 +75,7 @@ pub fn test() {
7575

7676
let mut src_ip = server_ip;
7777
let mut src_port = EXAMPLE_SERVICE_PORT;
78-
let mut dest_ip = base_code.mode().station_ip;
78+
let mut dest_ip = base_code.mode().station_ip();
7979
let mut dest_port = write_src_port;
8080
let mut header = [0; 1];
8181
let mut received = [0; 4];

uefi/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
- **Breaking:** The `pxe::BaseCode::tftp_read_dir` and
1313
`pxe::BaseCode::mtftp_read_dir` methods now take `&mut self` instead of
1414
`&self`.
15+
- **Breaking:** The `pxe::Mode` struct is now opaque. Use method calls to access
16+
mode data instead of direct field access.
1517
- `boot::memory_map()` will never return `Status::BUFFER_TOO_SMALL` from now on,
1618
as this is considered a hard internal error where users can't do anything
1719
about it anyway. It will panic instead.

uefi/src/proto/network/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ impl IpAddress {
3434
Self(ip_addr)
3535
}
3636

37+
/// Construct from a `uefi_raw::IpAddress` union.
38+
///
39+
/// # Safety
40+
///
41+
/// `is_ipv6` must accurately reflect how the union was initialized.
42+
#[must_use]
43+
unsafe fn from_raw(ip_addr: uefi_raw::IpAddress, is_ipv6: bool) -> Self {
44+
if is_ipv6 {
45+
Self::new_v6(unsafe { ip_addr.v6.0 })
46+
} else {
47+
Self::new_v4(unsafe { ip_addr.v4.0 })
48+
}
49+
}
50+
3751
#[must_use]
3852
const fn as_raw_ptr(&self) -> *const uefi_raw::IpAddress {
3953
// The uefi-raw type is defined differently, but the layout is

uefi/src/proto/network/pxe.rs

+157-42
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
use super::{IpAddress, MacAddress};
66
use crate::polyfill::maybe_uninit_slice_as_mut_ptr;
77
use crate::proto::unsafe_protocol;
8-
use crate::util::ptr_write_unaligned_and_add;
8+
use crate::util::{ptr_write_unaligned_and_add, usize_from_u32};
99
use crate::{CStr8, Result, Status, StatusExt};
1010
use bitflags::bitflags;
1111
use core::fmt::{self, Debug, Display, Formatter};
1212
use core::iter::from_fn;
1313
use core::mem::MaybeUninit;
1414
use core::ptr::{self, null, null_mut};
15+
use core::slice;
1516
use ptr_meta::Pointee;
1617
use uefi_raw::protocol::network::pxe::{
17-
PxeBaseCodeDiscoverInfo, PxeBaseCodeIpFilter, PxeBaseCodeMtftpInfo, PxeBaseCodePacket,
18-
PxeBaseCodeProtocol, PxeBaseCodeTftpOpcode,
18+
PxeBaseCodeDiscoverInfo, PxeBaseCodeIpFilter, PxeBaseCodeMode, PxeBaseCodeMtftpInfo,
19+
PxeBaseCodePacket, PxeBaseCodeProtocol, PxeBaseCodeTftpOpcode,
1920
};
2021
use uefi_raw::{Boolean, Char8};
2122

@@ -814,6 +815,13 @@ pub union Packet {
814815
dhcpv6: DhcpV6Packet,
815816
}
816817

818+
impl Packet {
819+
fn from_raw(packet: &PxeBaseCodePacket) -> &Self {
820+
// Safety: `Packet` has the same layout as `PxeBaseCodePacket`.
821+
unsafe { &*ptr::from_ref(packet).cast() }
822+
}
823+
}
824+
817825
impl Debug for Packet {
818826
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
819827
write!(f, "<binary data>")
@@ -942,91 +950,150 @@ impl DhcpV6Packet {
942950
/// [`BaseCode`].
943951
///
944952
/// Corresponds to the `EFI_PXE_BASE_CODE_MODE` type in the C API.
945-
#[repr(C)]
953+
#[repr(transparent)]
946954
#[derive(Debug)]
947-
pub struct Mode {
955+
pub struct Mode(PxeBaseCodeMode);
956+
957+
impl Mode {
948958
/// `true` if this device has been started by calling [`BaseCode::start`].
949959
/// This field is set to `true` by [`BaseCode::start`] and to `false` by
950960
/// the [`BaseCode::stop`] function.
951-
pub started: bool,
961+
pub fn started(&self) -> bool {
962+
self.0.started.into()
963+
}
964+
952965
/// `true` if the UNDI protocol supports IPv6
953-
pub ipv6_available: bool,
966+
pub fn ipv6_available(&self) -> bool {
967+
self.0.ipv6_available.into()
968+
}
969+
954970
/// `true` if this PXE Base Code Protocol implementation supports IPv6.
955-
pub ipv6_supported: bool,
971+
pub fn ipv6_supported(&self) -> bool {
972+
self.0.ipv6_supported.into()
973+
}
974+
956975
/// `true` if this device is currently using IPv6. This field is set by
957976
/// [`BaseCode::start`].
958-
pub using_ipv6: bool,
977+
pub fn using_ipv6(&self) -> bool {
978+
self.0.using_ipv6.into()
979+
}
980+
959981
/// `true` if this PXE Base Code implementation supports Boot Integrity
960982
/// Services (BIS). This field is set by [`BaseCode::start`].
961-
pub bis_supported: bool,
983+
pub fn bis_supported(&self) -> bool {
984+
self.0.bis_supported.into()
985+
}
986+
962987
/// `true` if this device and the platform support Boot Integrity Services
963988
/// (BIS). This field is set by [`BaseCode::start`].
964-
pub bis_detected: bool,
989+
pub fn bis_detected(&self) -> bool {
990+
self.0.bis_detected.into()
991+
}
992+
965993
/// `true` for automatic ARP packet generation, `false` otherwise. This
966994
/// field is initialized to `true` by [`BaseCode::start`] and can be
967995
/// modified with [`BaseCode::set_parameters`].
968-
pub auto_arp: bool,
996+
pub fn auto_arp(&self) -> bool {
997+
self.0.auto_arp.into()
998+
}
999+
9691000
/// This field is used to change the Client Hardware Address (chaddr) field
9701001
/// in the DHCP and Discovery packets. Set to `true` to send the SystemGuid
9711002
/// (if one is available). Set to `false` to send the client NIC MAC
9721003
/// address. This field is initialized to `false` by [`BaseCode::start`]
9731004
/// and can be modified with [`BaseCode::set_parameters`].
974-
pub send_guid: bool,
1005+
pub fn send_guid(&self) -> bool {
1006+
self.0.send_guid.into()
1007+
}
1008+
9751009
/// This field is initialized to `false` by [`BaseCode::start`] and set to
9761010
/// `true` when [`BaseCode::dhcp`] completes successfully. When `true`,
9771011
/// [`Self::dhcp_discover`] is valid. This field can also be changed by
9781012
/// [`BaseCode::set_packets`].
979-
pub dhcp_discover_valid: bool,
1013+
pub fn dhcp_discover_valid(&self) -> bool {
1014+
self.0.dhcp_discover_valid.into()
1015+
}
1016+
9801017
/// This field is initialized to `false` by [`BaseCode::start`] and set to
9811018
/// `true` when [`BaseCode::dhcp`] completes successfully. When `true`,
9821019
/// [`Self::dhcp_ack`] is valid. This field can also be changed by
9831020
/// [`BaseCode::set_packets`].
984-
pub dhcp_ack_received: bool,
1021+
pub fn dhcp_ack_received(&self) -> bool {
1022+
self.0.dhcp_ack_received.into()
1023+
}
1024+
9851025
/// This field is initialized to `false` by [`BaseCode::start`] and set to
9861026
/// `true` when [`BaseCode::dhcp`] completes successfully and a proxy DHCP
9871027
/// offer packet was received. When `true`, [`Self::proxy_offer`] is valid.
9881028
/// This field can also be changed by [`BaseCode::set_packets`].
989-
pub proxy_offer_received: bool,
1029+
pub fn proxy_offer_received(&self) -> bool {
1030+
self.0.proxy_offer_received.into()
1031+
}
1032+
9901033
/// When `true`, [`Self::pxe_discover`] is valid. This field is set to
9911034
/// `false` by [`BaseCode::start`] and [`BaseCode::dhcp`], and can be set
9921035
/// to `true` or `false` by [`BaseCode::discover`] and
9931036
/// [`BaseCode::set_packets`].
994-
pub pxe_discover_valid: bool,
1037+
pub fn pxe_discover_valid(&self) -> bool {
1038+
self.0.pxe_discover_valid.into()
1039+
}
1040+
9951041
/// When `true`, [`Self::pxe_reply`] is valid. This field is set to `false`
9961042
/// by [`BaseCode::start`] and [`BaseCode::dhcp`], and can be set to `true`
9971043
/// or `false` by [`BaseCode::discover`] and [`BaseCode::set_packets`].
998-
pub pxe_reply_received: bool,
1044+
pub fn pxe_reply_received(&self) -> bool {
1045+
self.0.pxe_reply_received.into()
1046+
}
1047+
9991048
/// When `true`, [`Self::pxe_bis_reply`] is valid. This field is set to
10001049
/// `false` by [`BaseCode::start`] and [`BaseCode::dhcp`], and can be set
10011050
/// to `true` or `false` by the [`BaseCode::discover`] and
10021051
/// [`BaseCode::set_packets`].
1003-
pub pxe_bis_reply_received: bool,
1052+
pub fn pxe_bis_reply_received(&self) -> bool {
1053+
self.0.pxe_bis_reply_received.into()
1054+
}
1055+
10041056
/// Indicates whether [`Self::icmp_error`] has been updated. This field is
10051057
/// reset to `false` by [`BaseCode::start`], [`BaseCode::dhcp`],
10061058
/// [`BaseCode::discover`],[`BaseCode::udp_read`], [`BaseCode::udp_write`],
10071059
/// [`BaseCode::arp`] and any of the TFTP/MTFTP operations. If an ICMP
10081060
/// error is received, this field will be set to `true` after
10091061
/// [`Self::icmp_error`] is updated.
1010-
pub icmp_error_received: bool,
1062+
pub fn icmp_error_received(&self) -> bool {
1063+
self.0.icmp_error_received.into()
1064+
}
1065+
10111066
/// Indicates whether [`Self::tftp_error`] has been updated. This field is
10121067
/// reset to `false` by [`BaseCode::start`] and any of the TFTP/MTFTP
10131068
/// operations. If a TFTP error is received, this field will be set to
10141069
/// `true` after [`Self::tftp_error`] is updated.
1015-
pub tftp_error_received: bool,
1070+
pub fn tftp_error_received(&self) -> bool {
1071+
self.0.tftp_error_received.into()
1072+
}
1073+
10161074
/// When `false`, callbacks will not be made. When `true`, make callbacks
10171075
/// to the PXE Base Code Callback Protocol. This field is reset to `false`
10181076
/// by [`BaseCode::start`] if the PXE Base Code Callback Protocol is not
10191077
/// available. It is reset to `true` by [`BaseCode::start`] if the PXE Base
10201078
/// Code Callback Protocol is available.
1021-
pub make_callbacks: bool,
1079+
pub fn make_callbacks(&self) -> bool {
1080+
self.0.make_callbacks.into()
1081+
}
1082+
10221083
/// The "time to live" field of the IP header. This field is initialized to
10231084
/// `16` by [`BaseCode::start`] and can be modified by
10241085
/// [`BaseCode::set_parameters`].
1025-
pub ttl: u8,
1086+
pub fn ttl(&self) -> u8 {
1087+
self.0.ttl
1088+
}
1089+
10261090
/// The type of service field of the IP header. This field is initialized
10271091
/// to `0` by [`BaseCode::start`], and can be modified with
10281092
/// [`BaseCode::set_parameters`].
1029-
pub tos: u8,
1093+
pub fn tos(&self) -> u8 {
1094+
self.0.tos
1095+
}
1096+
10301097
/// The device’s current IP address. This field is initialized to a zero
10311098
/// address by Start(). This field is set when [`BaseCode::dhcp`] completes
10321099
/// successfully. This field can also be set by
@@ -1035,7 +1102,10 @@ pub struct Mode {
10351102
/// before [`BaseCode::discover`], [`BaseCode::udp_read`],
10361103
/// [`BaseCode::udp_write`], [`BaseCode::arp`] and any of the TFTP/MTFTP
10371104
/// operations are called.
1038-
pub station_ip: IpAddress,
1105+
pub fn station_ip(&self) -> IpAddress {
1106+
unsafe { IpAddress::from_raw(self.0.station_ip, self.using_ipv6()) }
1107+
}
1108+
10391109
/// The device's current subnet mask. This field is initialized to a zero
10401110
/// address by [`BaseCode::start`]. This field is set when
10411111
/// [`BaseCode::dhcp`] completes successfully. This field can also be set
@@ -1044,58 +1114,103 @@ pub struct Mode {
10441114
/// [`BaseCode::set_station_ip`] before [`BaseCode::discover`],
10451115
/// [`BaseCode::udp_read`], [`BaseCode::udp_write`],
10461116
/// [`BaseCode::arp`] or any of the TFTP/MTFTP operations are called.
1047-
pub subnet_mask: IpAddress,
1117+
pub fn subnet_mask(&self) -> IpAddress {
1118+
unsafe { IpAddress::from_raw(self.0.subnet_mask, self.using_ipv6()) }
1119+
}
1120+
10481121
/// Cached DHCP Discover packet. This field is zero-filled by the
10491122
/// [`BaseCode::start`] function, and is set when [`BaseCode::dhcp`]
10501123
/// completes successfully. The contents of this field can replaced by
10511124
/// [`BaseCode::set_packets`].
1052-
pub dhcp_discover: Packet,
1125+
pub fn dhcp_discover(&self) -> &Packet {
1126+
Packet::from_raw(&self.0.dhcp_discover)
1127+
}
1128+
10531129
/// Cached DHCP Ack packet. This field is zero-filled by
10541130
/// [`BaseCode::start`], and is set when [`BaseCode::dhcp`] completes
10551131
/// successfully. The contents of this field can be replaced by
10561132
/// [`BaseCode::set_packets`].
1057-
pub dhcp_ack: Packet,
1133+
pub fn dhcp_ack(&self) -> &Packet {
1134+
Packet::from_raw(&self.0.dhcp_ack)
1135+
}
1136+
10581137
/// Cached Proxy Offer packet. This field is zero-filled by
10591138
/// [`BaseCode::start`], and is set when [`BaseCode::dhcp`] completes
10601139
/// successfully. The contents of this field can be replaced by
10611140
/// [`BaseCode::set_packets`].
1062-
pub proxy_offer: Packet,
1141+
pub fn proxy_offer(&self) -> &Packet {
1142+
Packet::from_raw(&self.0.proxy_offer)
1143+
}
1144+
10631145
/// Cached PXE Discover packet. This field is zero-filled by
10641146
/// [`BaseCode::start`], and is set when [`BaseCode::discover`] completes
10651147
/// successfully. The contents of this field can be replaced by
10661148
/// [`BaseCode::set_packets`].
1067-
pub pxe_discover: Packet,
1149+
pub fn pxe_discover(&self) -> &Packet {
1150+
Packet::from_raw(&self.0.pxe_discover)
1151+
}
1152+
10681153
/// Cached PXE Reply packet. This field is zero-filled by
10691154
/// [`BaseCode::start`], and is set when [`BaseCode::discover`] completes
10701155
/// successfully. The contents of this field can be replaced by the
10711156
/// [`BaseCode::set_packets`] function.
1072-
pub pxe_reply: Packet,
1157+
pub fn pxe_reply(&self) -> &Packet {
1158+
Packet::from_raw(&self.0.pxe_reply)
1159+
}
1160+
10731161
/// Cached PXE BIS Reply packet. This field is zero-filled by
10741162
/// [`BaseCode::start`], and is set when [`BaseCode::discover`] completes
10751163
/// successfully. This field can be replaced by [`BaseCode::set_packets`].
1076-
pub pxe_bis_reply: Packet,
1164+
pub fn pxe_bis_reply(&self) -> &Packet {
1165+
Packet::from_raw(&self.0.pxe_bis_reply)
1166+
}
1167+
10771168
/// The current IP receive filter settings. The receive filter is disabled
10781169
/// and the number of IP receive filters is set to zero by
10791170
/// [`BaseCode::start`], and is set by [`BaseCode::set_ip_filter`].
1080-
pub ip_filter: IpFilter,
1081-
/// The number of valid entries in the ARP cache. This field is reset to
1082-
/// zero by [`BaseCode::start`].
1083-
pub arp_cache_entries: u32,
1084-
/// Array of cached ARP entries.
1085-
pub arp_cache: [ArpEntry; 8],
1171+
pub fn ip_filter(&self) -> &IpFilter {
1172+
// Safety: `IpFilter` has the same layout as `PxeBaseCodeIpFilter`.
1173+
unsafe { &*ptr::from_ref(&self.0.ip_filter).cast() }
1174+
}
1175+
1176+
/// Cached ARP entries.
1177+
pub fn arp_cache(&self) -> &[ArpEntry] {
1178+
let len = usize_from_u32(self.0.arp_cache_entries);
1179+
// Safety: `ArpEntry` has the same layout as `PxeBaseCodeArpEntry`.
1180+
unsafe { slice::from_raw_parts(ptr::from_ref(&self.0.arp_cache).cast::<ArpEntry>(), len) }
1181+
}
1182+
10861183
/// The number of valid entries in the current route table. This field is
10871184
/// reset to zero by [`BaseCode::start`].
1088-
pub route_table_entries: u32,
1185+
pub fn route_table_entries(&self) -> u32 {
1186+
self.0.route_table_entries
1187+
}
1188+
10891189
/// Array of route table entries.
1090-
pub route_table: [RouteEntry; 8],
1190+
pub fn route_table(&self) -> &[RouteEntry] {
1191+
let len = usize_from_u32(self.0.route_table_entries);
1192+
1193+
// Safety: `RouteEntry` has the same layout as `PxeBaseCodeRouteEntry`.
1194+
unsafe {
1195+
slice::from_raw_parts(ptr::from_ref(&self.0.route_table).cast::<RouteEntry>(), len)
1196+
}
1197+
}
1198+
10911199
/// ICMP error packet. This field is updated when an ICMP error is received
10921200
/// and is undefined until the first ICMP error is received. This field is
10931201
/// zero-filled by [`BaseCode::start`].
1094-
pub icmp_error: IcmpError,
1202+
pub fn icmp_error(&self) -> &IcmpError {
1203+
// Safety: `IcmpError` has the same layout as `PxeBaseCodeIcmpError`.
1204+
unsafe { &*ptr::from_ref(&self.0.icmp_error).cast() }
1205+
}
1206+
10951207
/// TFTP error packet. This field is updated when a TFTP error is received
10961208
/// and is undefined until the first TFTP error is received. This field is
10971209
/// zero-filled by the [`BaseCode::start`] function.
1098-
pub tftp_error: TftpError,
1210+
pub fn tftp_error(&self) -> &TftpError {
1211+
// Safety: `TftpError` has the same layout as `PxeBaseCodeTftpError`.
1212+
unsafe { &*ptr::from_ref(&self.0.tftp_error).cast() }
1213+
}
10991214
}
11001215

11011216
/// An entry for the ARP cache found in [`Mode::arp_cache`]

0 commit comments

Comments
 (0)