Skip to content

Commit 19bdcee

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

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

uefi/src/proto/network/ip4config2.rs

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

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)