Skip to content

Commit a452682

Browse files
committed
std: sys: net: uefi: tcp: Initial TcpListener support
Add support for binding and accepting TCP4 connections. While testing, the following network options were used with QEMU + OVMF: -nic user,hostfwd=tcp::12345-:12345 The default localhost address on qemu seems to be 10.0.2.15. UEFI spec does not seem to state that the TCP Handle returned by the Accept method has a ServiceBinding Protocol. So have made the ServiceBinding Protocol optional. Signed-off-by: Ayush Singh <ayush@beagleboard.org>
1 parent ae12bc2 commit a452682

File tree

3 files changed

+82
-28
lines changed

3 files changed

+82
-28
lines changed

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

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,26 @@ pub struct TcpStream {
1616
}
1717

1818
impl TcpStream {
19+
fn new(inner: tcp::Tcp) -> Self {
20+
Self {
21+
inner,
22+
read_timeout: Arc::new(Mutex::new(None)),
23+
write_timeout: Arc::new(Mutex::new(None)),
24+
}
25+
}
26+
1927
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
2028
return each_addr(addr, inner);
2129

2230
fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
2331
let inner = tcp::Tcp::connect(addr, None)?;
24-
Ok(TcpStream {
25-
inner,
26-
read_timeout: Arc::new(Mutex::new(None)),
27-
write_timeout: Arc::new(Mutex::new(None)),
28-
})
32+
Ok(TcpStream::new(inner))
2933
}
3034
}
3135

3236
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
3337
let inner = tcp::Tcp::connect(addr, Some(timeout))?;
34-
Ok(Self {
35-
inner,
36-
read_timeout: Arc::new(Mutex::new(None)),
37-
write_timeout: Arc::new(Mutex::new(None)),
38-
})
38+
Ok(Self::new(inner))
3939
}
4040

4141
pub fn set_read_timeout(&self, t: Option<Duration>) -> io::Result<()> {
@@ -150,16 +150,23 @@ pub struct TcpListener {
150150
}
151151

152152
impl TcpListener {
153-
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
154-
unsupported()
153+
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
154+
return each_addr(addr, inner);
155+
156+
fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
157+
let inner = tcp::Tcp::bind(addr)?;
158+
Ok(TcpListener { inner })
159+
}
155160
}
156161

157162
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
158-
unsupported()
163+
self.inner.socket_addr()
159164
}
160165

161166
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
162-
unsupported()
167+
let tcp = self.inner.accept()?;
168+
let addr = tcp.peer_addr()?;
169+
Ok((TcpStream::new(tcp), addr))
163170
}
164171

165172
pub fn duplicate(&self) -> io::Result<TcpListener> {

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,24 @@ impl Tcp {
1818
temp.connect(timeout)?;
1919
Ok(Tcp::V4(temp))
2020
}
21-
SocketAddr::V6(_) => todo!(),
21+
SocketAddr::V6(_) => unsupported(),
22+
}
23+
}
24+
25+
pub(crate) fn bind(addr: &SocketAddr) -> io::Result<Self> {
26+
match addr {
27+
SocketAddr::V4(x) => {
28+
let temp = tcp4::Tcp4::new()?;
29+
temp.configure(false, None, Some(x))?;
30+
Ok(Tcp::V4(temp))
31+
}
32+
SocketAddr::V6(_) => unsupported(),
33+
}
34+
}
35+
36+
pub(crate) fn accept(&self) -> io::Result<Self> {
37+
match self {
38+
Self::V4(client) => client.accept().map(Tcp::V4),
2239
}
2340
}
2441

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

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use r_efi::protocols::tcp4;
33

44
use crate::io;
55
use crate::net::SocketAddrV4;
6-
use crate::ptr::NonNull;
6+
use crate::ptr::{self, NonNull};
77
use crate::sync::atomic::{AtomicBool, Ordering};
88
use crate::sys::pal::helpers;
99
use crate::time::{Duration, Instant};
@@ -15,7 +15,7 @@ pub(crate) struct Tcp4 {
1515
protocol: NonNull<tcp4::Protocol>,
1616
flag: AtomicBool,
1717
#[expect(dead_code)]
18-
service_binding: helpers::ServiceProtocol,
18+
service_binding: Option<helpers::ServiceProtocol>,
1919
}
2020

2121
const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] };
@@ -25,7 +25,7 @@ impl Tcp4 {
2525
let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?;
2626
let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?;
2727

28-
Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) })
28+
Ok(Self { service_binding: Some(service_binding), protocol, flag: AtomicBool::new(false) })
2929
}
3030

3131
pub(crate) fn configure(
@@ -42,11 +42,14 @@ impl Tcp4 {
4242
(DEFAULT_ADDR, 0)
4343
};
4444

45-
// FIXME: Remove when passive connections with proper subnet handling are added
46-
assert!(station_address.is_none());
47-
let use_default_address = efi::Boolean::TRUE;
48-
let (station_address, station_port) = (DEFAULT_ADDR, 0);
49-
let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0));
45+
let use_default_address: r_efi::efi::Boolean = station_address.is_none().into();
46+
let (station_address, station_port) = if let Some(x) = station_address {
47+
(helpers::ipv4_to_r_efi(*x.ip()), x.port())
48+
} else {
49+
(DEFAULT_ADDR, 0)
50+
};
51+
let subnet_mask = crate::net::Ipv4Addr::new(255, 255, 255, 0);
52+
let subnet_mask = helpers::ipv4_to_r_efi(subnet_mask);
5053

5154
let mut config_data = tcp4::ConfigData {
5255
type_of_service: TYPE_OF_SERVICE,
@@ -60,7 +63,7 @@ impl Tcp4 {
6063
station_port,
6164
subnet_mask,
6265
},
63-
control_option: crate::ptr::null_mut(),
66+
control_option: ptr::null_mut(),
6467
};
6568

6669
let r = unsafe { ((*protocol).configure)(protocol, &mut config_data) };
@@ -74,17 +77,44 @@ impl Tcp4 {
7477
let r = unsafe {
7578
((*protocol).get_mode_data)(
7679
protocol,
77-
crate::ptr::null_mut(),
80+
ptr::null_mut(),
7881
&mut config_data,
79-
crate::ptr::null_mut(),
80-
crate::ptr::null_mut(),
81-
crate::ptr::null_mut(),
82+
ptr::null_mut(),
83+
ptr::null_mut(),
84+
ptr::null_mut(),
8285
)
8386
};
8487

8588
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(config_data) }
8689
}
8790

91+
pub(crate) fn accept(&self) -> io::Result<Self> {
92+
let evt = unsafe { self.create_evt() }?;
93+
let completion_token =
94+
tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
95+
let mut listen_token =
96+
tcp4::ListenToken { completion_token, new_child_handle: ptr::null_mut() };
97+
98+
let protocol = self.protocol.as_ptr();
99+
let r = unsafe { ((*protocol).accept)(protocol, &mut listen_token) };
100+
if r.is_error() {
101+
return Err(io::Error::from_raw_os_error(r.as_usize()));
102+
}
103+
104+
unsafe { self.wait_or_cancel(None, &mut listen_token.completion_token) }?;
105+
106+
if completion_token.status.is_error() {
107+
Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
108+
} else {
109+
let handle = NonNull::new(listen_token.new_child_handle).unwrap();
110+
let protocol = helpers::open_protocol(handle, tcp4::PROTOCOL_GUID)?;
111+
112+
// The spec does not seem to state if we need to call ServiceBinding->DestroyChild for
113+
// this handle
114+
Ok(Self { service_binding: None, protocol, flag: AtomicBool::new(false) })
115+
}
116+
}
117+
88118
pub(crate) fn connect(&self, timeout: Option<Duration>) -> io::Result<()> {
89119
let evt = unsafe { self.create_evt() }?;
90120
let completion_token =

0 commit comments

Comments
 (0)