Skip to content

Commit 8b0b482

Browse files
committed
add ip4 config2 protocol
Signed-off-by: Gerd Hoffmann <[email protected]>
1 parent 6ab3d14 commit 8b0b482

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

uefi/src/proto/network/ip4config2.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
#![cfg(feature = "alloc")]
4+
5+
//! IP4 Config2 Protocol.
6+
7+
use alloc::vec;
8+
use alloc::vec::Vec;
9+
use core::ffi::c_void;
10+
11+
use uefi::boot::ScopedProtocol;
12+
use uefi::prelude::*;
13+
use uefi::proto::unsafe_protocol;
14+
use uefi::{print, println};
15+
use uefi_raw::protocol::network::ip4_config2::{
16+
Ip4Config2DataType, Ip4Config2InterfaceInfo, Ip4Config2Policy, Ip4Config2Protocol,
17+
};
18+
use uefi_raw::Ipv4Address;
19+
20+
/// IP4 Config2 [`Protocol`]. Configure IPv4 networking.
21+
///
22+
/// [`Protocol`]: uefi::proto::Protocol
23+
#[derive(Debug)]
24+
#[unsafe_protocol(Ip4Config2Protocol::GUID)]
25+
pub struct Ip4Config2(pub Ip4Config2Protocol);
26+
27+
impl Ip4Config2 {
28+
/// Open IP4 Config2 protocol for the given NIC handle.
29+
pub fn new(nic_handle: Handle) -> uefi::Result<ScopedProtocol<Self>> {
30+
let protocol;
31+
unsafe {
32+
protocol = boot::open_protocol::<Self>(
33+
boot::OpenProtocolParams {
34+
handle: nic_handle,
35+
agent: boot::image_handle(),
36+
controller: None,
37+
},
38+
boot::OpenProtocolAttributes::GetProtocol,
39+
)?;
40+
}
41+
Ok(protocol)
42+
}
43+
44+
/// Set configuration data. It is recommended to type-specific set_* helpers instead of calling this directly.
45+
pub fn set_data(&mut self, data_type: Ip4Config2DataType, data: &mut [u8]) -> uefi::Result<()> {
46+
let status = unsafe {
47+
let data_ptr = data.as_mut_ptr().cast::<c_void>();
48+
(self.0.set_data)(&mut self.0, data_type, data.len(), data_ptr)
49+
};
50+
match status {
51+
Status::SUCCESS => Ok(()),
52+
_ => Err(status.into()),
53+
}
54+
}
55+
56+
/// Get configuration data. It is recommended to type-specific get_* helpers instead of calling this directly.
57+
pub fn get_data(&mut self, data_type: Ip4Config2DataType) -> uefi::Result<Vec<u8>> {
58+
let mut data_size = 0;
59+
60+
// call #1: figure return buffer size
61+
let status = unsafe {
62+
let null = core::ptr::null_mut();
63+
(self.0.get_data)(&mut self.0, data_type, &mut data_size, null)
64+
};
65+
if status != Status::BUFFER_TOO_SMALL {
66+
return Err(status.into());
67+
}
68+
69+
// call #2: get data
70+
let mut data = vec![0; data_size];
71+
let status = unsafe {
72+
let data_ptr = data.as_mut_ptr().cast::<c_void>();
73+
(self.0.get_data)(&mut self.0, data_type, &mut data_size, data_ptr)
74+
};
75+
match status {
76+
Status::SUCCESS => Ok(data),
77+
_ => Err(status.into()),
78+
}
79+
}
80+
81+
/// Set config policy (static vs. dhcp).
82+
pub fn set_policy(&mut self, policy: Ip4Config2Policy) -> uefi::Result<()> {
83+
let mut data: [u8; 4] = policy.0.to_ne_bytes();
84+
self.set_data(Ip4Config2DataType::POLICY, &mut data)
85+
}
86+
87+
/// Get current interface configuration.
88+
pub fn get_interface_info(&mut self) -> uefi::Result<Ip4Config2InterfaceInfo> {
89+
let data = self.get_data(Ip4Config2DataType::INTERFACE_INFO)?;
90+
let info: &Ip4Config2InterfaceInfo =
91+
unsafe { &*(data.as_ptr().cast::<Ip4Config2InterfaceInfo>()) };
92+
Ok(Ip4Config2InterfaceInfo {
93+
name: info.name,
94+
if_type: info.if_type,
95+
hw_addr_size: info.hw_addr_size,
96+
hw_addr: info.hw_addr,
97+
station_addr: info.station_addr,
98+
subnet_mask: info.subnet_mask,
99+
route_table_size: 0,
100+
route_table: core::ptr::null_mut(),
101+
})
102+
}
103+
104+
fn print_info(info: &Ip4Config2InterfaceInfo) {
105+
println!(
106+
"addr v4: {}.{}.{}.{}",
107+
info.station_addr.0[0],
108+
info.station_addr.0[1],
109+
info.station_addr.0[2],
110+
info.station_addr.0[3],
111+
);
112+
}
113+
114+
/// Bring up network interface. Does nothing in case the network
115+
/// is already set up. Otherwise turns on DHCP and waits until an
116+
/// IPv4 address has been assigned. Reports progress on the
117+
/// console if verbose is set to true. Returns TIMEOUT error in
118+
/// case DHCP configuration does not finish within 30 seconds.
119+
pub fn ifup(&mut self, verbose: bool) -> uefi::Result<()> {
120+
let no_address = Ipv4Address::default();
121+
122+
let info = self.get_interface_info()?;
123+
if info.station_addr != no_address {
124+
if verbose {
125+
print!("Network is already up: ");
126+
Self::print_info(&info);
127+
}
128+
return Ok(());
129+
}
130+
131+
if verbose {
132+
print!("DHCP ");
133+
}
134+
self.set_policy(Ip4Config2Policy::DHCP)?;
135+
136+
for _ in 0..30 {
137+
if verbose {
138+
print!(".");
139+
}
140+
boot::stall(1_000_000);
141+
let info = self.get_interface_info()?;
142+
if info.station_addr != no_address {
143+
if verbose {
144+
print!(" OK: ");
145+
Self::print_info(&info);
146+
}
147+
return Ok(());
148+
}
149+
}
150+
151+
Err(Status::TIMEOUT.into())
152+
}
153+
}

uefi/src/proto/network/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//!
55
//! These protocols can be used to interact with network resources.
66
7+
pub mod ip4config2;
78
pub mod pxe;
89
pub mod snp;
910

0 commit comments

Comments
 (0)