Skip to content

Commit c00e658

Browse files
committed
std: sys: net: uefi: Implement TCP4 connect
- Implement TCP4 connect using EFI_TCP4_PROTOCOL. - Tested on QEMU setup with connecting to TCP server on host. Signed-off-by: Ayush Singh <[email protected]>
1 parent 79de6c0 commit c00e658

File tree

4 files changed

+178
-30
lines changed

4 files changed

+178
-30
lines changed

library/std/src/sys/net/connection/uefi/mod.rs

+31-28
Original file line numberDiff line numberDiff line change
@@ -4,117 +4,120 @@ use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
44
use crate::sys::unsupported;
55
use crate::time::Duration;
66

7-
pub struct TcpStream(!);
7+
mod tcp;
8+
pub(crate) mod tcp4;
9+
10+
pub struct TcpStream(#[expect(dead_code)] tcp::Tcp);
811

912
impl TcpStream {
10-
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
11-
unsupported()
13+
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
14+
tcp::Tcp::connect(addr?).map(Self)
1215
}
1316

1417
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
1518
unsupported()
1619
}
1720

1821
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
19-
self.0
22+
unsupported()
2023
}
2124

2225
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
23-
self.0
26+
unsupported()
2427
}
2528

2629
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
27-
self.0
30+
unsupported()
2831
}
2932

3033
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
31-
self.0
34+
unsupported()
3235
}
3336

3437
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
35-
self.0
38+
unsupported()
3639
}
3740

3841
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
39-
self.0
42+
unsupported()
4043
}
4144

4245
pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
43-
self.0
46+
unsupported()
4447
}
4548

4649
pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
47-
self.0
50+
unsupported()
4851
}
4952

5053
pub fn is_read_vectored(&self) -> bool {
51-
self.0
54+
false
5255
}
5356

5457
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
55-
self.0
58+
unsupported()
5659
}
5760

5861
pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
59-
self.0
62+
unsupported()
6063
}
6164

6265
pub fn is_write_vectored(&self) -> bool {
63-
self.0
66+
false
6467
}
6568

6669
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
67-
self.0
70+
unsupported()
6871
}
6972

7073
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
71-
self.0
74+
unsupported()
7275
}
7376

7477
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
75-
self.0
78+
unsupported()
7679
}
7780

7881
pub fn duplicate(&self) -> io::Result<TcpStream> {
79-
self.0
82+
unsupported()
8083
}
8184

8285
pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
83-
self.0
86+
unsupported()
8487
}
8588

8689
pub fn linger(&self) -> io::Result<Option<Duration>> {
87-
self.0
90+
unsupported()
8891
}
8992

9093
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
91-
self.0
94+
unsupported()
9295
}
9396

9497
pub fn nodelay(&self) -> io::Result<bool> {
95-
self.0
98+
unsupported()
9699
}
97100

98101
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
99-
self.0
102+
unsupported()
100103
}
101104

102105
pub fn ttl(&self) -> io::Result<u32> {
103-
self.0
106+
unsupported()
104107
}
105108

106109
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
107-
self.0
110+
unsupported()
108111
}
109112

110113
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
111-
self.0
114+
unsupported()
112115
}
113116
}
114117

115118
impl fmt::Debug for TcpStream {
116119
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
117-
self.0
120+
todo!()
118121
}
119122
}
120123

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use super::tcp4;
2+
use crate::io;
3+
use crate::net::SocketAddr;
4+
5+
pub(crate) enum Tcp {
6+
V4(#[expect(dead_code)] tcp4::Tcp4),
7+
}
8+
9+
impl Tcp {
10+
pub(crate) fn connect(addr: &SocketAddr) -> io::Result<Self> {
11+
match addr {
12+
SocketAddr::V4(x) => {
13+
let temp = tcp4::Tcp4::new()?;
14+
temp.configure(true, Some(x), None)?;
15+
temp.connect()?;
16+
Ok(Tcp::V4(temp))
17+
}
18+
SocketAddr::V6(_) => todo!(),
19+
}
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use r_efi::efi::{self, Status};
2+
use r_efi::protocols::tcp4;
3+
4+
use crate::io;
5+
use crate::net::SocketAddrV4;
6+
use crate::ptr::NonNull;
7+
use crate::sync::atomic::{AtomicBool, Ordering};
8+
use crate::sys::pal::helpers;
9+
10+
const TYPE_OF_SERVICE: u8 = 8;
11+
const TIME_TO_LIVE: u8 = 255;
12+
13+
pub(crate) struct Tcp4 {
14+
protocol: NonNull<tcp4::Protocol>,
15+
flag: AtomicBool,
16+
#[expect(dead_code)]
17+
service_binding: helpers::ServiceProtocol,
18+
}
19+
20+
const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] };
21+
22+
impl Tcp4 {
23+
pub(crate) fn new() -> io::Result<Self> {
24+
let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?;
25+
let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?;
26+
27+
Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) })
28+
}
29+
30+
pub(crate) fn configure(
31+
&self,
32+
active: bool,
33+
remote_address: Option<&SocketAddrV4>,
34+
station_address: Option<&SocketAddrV4>,
35+
) -> io::Result<()> {
36+
let protocol = self.protocol.as_ptr();
37+
38+
let (remote_address, remote_port) = if let Some(x) = remote_address {
39+
(helpers::ipv4_to_r_efi(*x.ip()), x.port())
40+
} else {
41+
(DEFAULT_ADDR, 0)
42+
};
43+
44+
// FIXME: Remove when passive connections with proper subnet handling are added
45+
assert!(station_address.is_none());
46+
let use_default_address = efi::Boolean::TRUE;
47+
let (station_address, station_port) = (DEFAULT_ADDR, 0);
48+
let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0));
49+
50+
let mut config_data = tcp4::ConfigData {
51+
type_of_service: TYPE_OF_SERVICE,
52+
time_to_live: TIME_TO_LIVE,
53+
access_point: tcp4::AccessPoint {
54+
use_default_address,
55+
remote_address,
56+
remote_port,
57+
active_flag: active.into(),
58+
station_address,
59+
station_port,
60+
subnet_mask,
61+
},
62+
control_option: crate::ptr::null_mut(),
63+
};
64+
65+
let r = unsafe { ((*protocol).configure)(protocol, &mut config_data) };
66+
if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
67+
}
68+
69+
pub(crate) fn connect(&self) -> io::Result<()> {
70+
let evt = self.create_evt()?;
71+
let completion_token =
72+
tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
73+
74+
let protocol = self.protocol.as_ptr();
75+
let mut conn_token = tcp4::ConnectionToken { completion_token };
76+
77+
let r = unsafe { ((*protocol).connect)(protocol, &mut conn_token) };
78+
if r.is_error() {
79+
return Err(io::Error::from_raw_os_error(r.as_usize()));
80+
}
81+
82+
self.wait_for_flag().unwrap();
83+
84+
if completion_token.status.is_error() {
85+
Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
86+
} else {
87+
Ok(())
88+
}
89+
}
90+
91+
fn create_evt(&self) -> io::Result<helpers::OwnedEvent> {
92+
self.flag.store(false, Ordering::Relaxed);
93+
helpers::OwnedEvent::new(
94+
efi::EVT_NOTIFY_SIGNAL,
95+
efi::TPL_CALLBACK,
96+
Some(toggle_atomic_flag),
97+
Some(unsafe { NonNull::new_unchecked(self.flag.as_ptr().cast()) }),
98+
)
99+
}
100+
101+
fn wait_for_flag(&self) -> io::Result<()> {
102+
while !self.flag.load(Ordering::Relaxed) {
103+
let protocol = self.protocol.as_ptr();
104+
let r = unsafe { ((*protocol).poll)(protocol) };
105+
106+
if r.is_error() {
107+
return Err(io::Error::from_raw_os_error(r.as_usize()));
108+
}
109+
}
110+
111+
Ok(())
112+
}
113+
}
114+
115+
extern "efiapi" fn toggle_atomic_flag(_: r_efi::efi::Event, ctx: *mut crate::ffi::c_void) {
116+
let flag = unsafe { AtomicBool::from_ptr(ctx.cast()) };
117+
flag.store(true, Ordering::Relaxed);
118+
}

library/std/src/sys/pal/uefi/helpers.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,6 @@ pub(crate) struct ServiceProtocol {
653653
}
654654

655655
impl ServiceProtocol {
656-
#[expect(dead_code)]
657656
pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result<Self> {
658657
let handles = locate_handles(service_guid)?;
659658

@@ -670,7 +669,6 @@ impl ServiceProtocol {
670669
Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found"))
671670
}
672671

673-
#[expect(dead_code)]
674672
pub(crate) fn child_handle(&self) -> NonNull<crate::ffi::c_void> {
675673
self.child_handle
676674
}
@@ -732,6 +730,10 @@ impl OwnedEvent {
732730
}
733731
}
734732

733+
pub(crate) fn as_ptr(&self) -> efi::Event {
734+
self.0.as_ptr()
735+
}
736+
735737
pub(crate) fn into_raw(self) -> *mut crate::ffi::c_void {
736738
let r = self.0.as_ptr();
737739
crate::mem::forget(self);
@@ -755,3 +757,7 @@ impl Drop for OwnedEvent {
755757
}
756758
}
757759
}
760+
761+
pub(crate) const fn ipv4_to_r_efi(addr: crate::net::Ipv4Addr) -> efi::Ipv4Address {
762+
efi::Ipv4Address { addr: addr.octets() }
763+
}

0 commit comments

Comments
 (0)