Skip to content

Commit 5459fc4

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 <[email protected]>
1 parent d9dba3a commit 5459fc4

File tree

3 files changed

+70
-21
lines changed

3 files changed

+70
-21
lines changed

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,22 @@ pub struct TcpStream {
1515
}
1616

1717
impl TcpStream {
18-
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
19-
let inner = tcp::Tcp::connect(addr?, None)?;
20-
Ok(Self {
18+
fn new(inner: tcp::Tcp) -> Self {
19+
Self {
2120
inner,
2221
read_timeout: Arc::new(Mutex::new(None)),
2322
write_timeout: Arc::new(Mutex::new(None)),
24-
})
23+
}
24+
}
25+
26+
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
27+
let inner = tcp::Tcp::connect(addr?, None)?;
28+
Ok(Self::new(inner))
2529
}
2630

2731
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
2832
let inner = tcp::Tcp::connect(addr, Some(timeout))?;
29-
Ok(Self {
30-
inner,
31-
read_timeout: Arc::new(Mutex::new(None)),
32-
write_timeout: Arc::new(Mutex::new(None)),
33-
})
33+
Ok(Self::new(inner))
3434
}
3535

3636
pub fn set_read_timeout(&self, t: Option<Duration>) -> io::Result<()> {
@@ -145,16 +145,19 @@ pub struct TcpListener {
145145
}
146146

147147
impl TcpListener {
148-
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
149-
unsupported()
148+
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
149+
let inner = tcp::Tcp::bind(addr?)?;
150+
Ok(Self { inner })
150151
}
151152

152153
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
153-
unsupported()
154+
self.inner.socket_addr()
154155
}
155156

156157
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
157-
unsupported()
158+
let tcp = self.inner.accept()?;
159+
let addr = tcp.peer_addr()?;
160+
Ok((TcpStream::new(tcp), addr))
158161
}
159162

160163
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: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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,13 @@ 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 = 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 = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(255, 255, 255, 0));
5052

5153
let mut config_data = tcp4::ConfigData {
5254
type_of_service: TYPE_OF_SERVICE,
@@ -85,6 +87,33 @@ impl Tcp4 {
8587
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(config_data) }
8688
}
8789

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

0 commit comments

Comments
 (0)