Auto merge of #150644 - matthiaskrgr:rollup-ey900sr, r=matthiaskrgr
Rollup of 2 pull requests Successful merges: - rust-lang/rust#145339 (std: sys: net: uefi: tcp: Initial TcpListener support) - rust-lang/rust#150641 (std: remove manual bindings on NetBSD) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1d22b964df
5 changed files with 132 additions and 69 deletions
|
|
@ -16,26 +16,26 @@ pub struct TcpStream {
|
|||
}
|
||||
|
||||
impl TcpStream {
|
||||
fn new(inner: tcp::Tcp) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
read_timeout: Arc::new(Mutex::new(None)),
|
||||
write_timeout: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
|
||||
return each_addr(addr, inner);
|
||||
|
||||
fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
|
||||
let inner = tcp::Tcp::connect(addr, None)?;
|
||||
Ok(TcpStream {
|
||||
inner,
|
||||
read_timeout: Arc::new(Mutex::new(None)),
|
||||
write_timeout: Arc::new(Mutex::new(None)),
|
||||
})
|
||||
Ok(TcpStream::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
|
||||
let inner = tcp::Tcp::connect(addr, Some(timeout))?;
|
||||
Ok(Self {
|
||||
inner,
|
||||
read_timeout: Arc::new(Mutex::new(None)),
|
||||
write_timeout: Arc::new(Mutex::new(None)),
|
||||
})
|
||||
Ok(Self::new(inner))
|
||||
}
|
||||
|
||||
pub fn set_read_timeout(&self, t: Option<Duration>) -> io::Result<()> {
|
||||
|
|
@ -148,16 +148,23 @@ pub struct TcpListener {
|
|||
}
|
||||
|
||||
impl TcpListener {
|
||||
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
|
||||
unsupported()
|
||||
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
|
||||
return each_addr(addr, inner);
|
||||
|
||||
fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
|
||||
let inner = tcp::Tcp::bind(addr)?;
|
||||
Ok(TcpListener { inner })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
|
||||
unsupported()
|
||||
self.inner.socket_addr()
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
|
||||
unsupported()
|
||||
let tcp = self.inner.accept()?;
|
||||
let addr = tcp.peer_addr()?;
|
||||
Ok((TcpStream::new(tcp), addr))
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<TcpListener> {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,24 @@ impl Tcp {
|
|||
temp.connect(timeout)?;
|
||||
Ok(Tcp::V4(temp))
|
||||
}
|
||||
SocketAddr::V6(_) => todo!(),
|
||||
SocketAddr::V6(_) => unsupported(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bind(addr: &SocketAddr) -> io::Result<Self> {
|
||||
match addr {
|
||||
SocketAddr::V4(x) => {
|
||||
let temp = tcp4::Tcp4::new()?;
|
||||
temp.configure(false, None, Some(x))?;
|
||||
Ok(Tcp::V4(temp))
|
||||
}
|
||||
SocketAddr::V6(_) => unsupported(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn accept(&self) -> io::Result<Self> {
|
||||
match self {
|
||||
Self::V4(client) => client.accept().map(Tcp::V4),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use r_efi::protocols::tcp4;
|
|||
|
||||
use crate::io::{self, IoSlice, IoSliceMut};
|
||||
use crate::net::SocketAddrV4;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::ptr::{self, NonNull};
|
||||
use crate::sync::atomic::{AtomicBool, Ordering};
|
||||
use crate::sys::pal::helpers;
|
||||
use crate::time::{Duration, Instant};
|
||||
|
|
@ -12,9 +12,9 @@ const TYPE_OF_SERVICE: u8 = 8;
|
|||
const TIME_TO_LIVE: u8 = 255;
|
||||
|
||||
pub(crate) struct Tcp4 {
|
||||
handle: NonNull<crate::ffi::c_void>,
|
||||
protocol: NonNull<tcp4::Protocol>,
|
||||
flag: AtomicBool,
|
||||
#[expect(dead_code)]
|
||||
service_binding: helpers::ServiceProtocol,
|
||||
}
|
||||
|
||||
|
|
@ -22,10 +22,11 @@ const DEFAULT_ADDR: efi::Ipv4Address = efi::Ipv4Address { addr: [0u8; 4] };
|
|||
|
||||
impl Tcp4 {
|
||||
pub(crate) fn new() -> io::Result<Self> {
|
||||
let service_binding = helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?;
|
||||
let protocol = helpers::open_protocol(service_binding.child_handle(), tcp4::PROTOCOL_GUID)?;
|
||||
let (service_binding, handle) =
|
||||
helpers::ServiceProtocol::open(tcp4::SERVICE_BINDING_PROTOCOL_GUID)?;
|
||||
let protocol = helpers::open_protocol(handle, tcp4::PROTOCOL_GUID)?;
|
||||
|
||||
Ok(Self { service_binding, protocol, flag: AtomicBool::new(false) })
|
||||
Ok(Self { service_binding, handle, protocol, flag: AtomicBool::new(false) })
|
||||
}
|
||||
|
||||
pub(crate) fn configure(
|
||||
|
|
@ -42,11 +43,14 @@ impl Tcp4 {
|
|||
(DEFAULT_ADDR, 0)
|
||||
};
|
||||
|
||||
// FIXME: Remove when passive connections with proper subnet handling are added
|
||||
assert!(station_address.is_none());
|
||||
let use_default_address = efi::Boolean::TRUE;
|
||||
let (station_address, station_port) = (DEFAULT_ADDR, 0);
|
||||
let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(0, 0, 0, 0));
|
||||
let use_default_address: r_efi::efi::Boolean =
|
||||
station_address.is_none_or(|addr| addr.ip().is_unspecified()).into();
|
||||
let (station_address, station_port) = if let Some(x) = station_address {
|
||||
(helpers::ipv4_to_r_efi(*x.ip()), x.port())
|
||||
} else {
|
||||
(DEFAULT_ADDR, 0)
|
||||
};
|
||||
let subnet_mask = helpers::ipv4_to_r_efi(crate::net::Ipv4Addr::new(255, 255, 255, 0));
|
||||
|
||||
let mut config_data = tcp4::ConfigData {
|
||||
type_of_service: TYPE_OF_SERVICE,
|
||||
|
|
@ -60,7 +64,7 @@ impl Tcp4 {
|
|||
station_port,
|
||||
subnet_mask,
|
||||
},
|
||||
control_option: crate::ptr::null_mut(),
|
||||
control_option: ptr::null_mut(),
|
||||
};
|
||||
|
||||
let r = unsafe { ((*protocol).configure)(protocol, &mut config_data) };
|
||||
|
|
@ -74,17 +78,55 @@ impl Tcp4 {
|
|||
let r = unsafe {
|
||||
((*protocol).get_mode_data)(
|
||||
protocol,
|
||||
crate::ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
&mut config_data,
|
||||
crate::ptr::null_mut(),
|
||||
crate::ptr::null_mut(),
|
||||
crate::ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(config_data) }
|
||||
}
|
||||
|
||||
pub(crate) fn accept(&self) -> io::Result<Self> {
|
||||
let evt = unsafe { self.create_evt() }?;
|
||||
let completion_token =
|
||||
tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS };
|
||||
let mut listen_token =
|
||||
tcp4::ListenToken { completion_token, new_child_handle: ptr::null_mut() };
|
||||
|
||||
let protocol = self.protocol.as_ptr();
|
||||
let r = unsafe { ((*protocol).accept)(protocol, &mut listen_token) };
|
||||
if r.is_error() {
|
||||
return Err(io::Error::from_raw_os_error(r.as_usize()));
|
||||
}
|
||||
|
||||
unsafe { self.wait_or_cancel(None, &mut listen_token.completion_token) }?;
|
||||
|
||||
if completion_token.status.is_error() {
|
||||
Err(io::Error::from_raw_os_error(completion_token.status.as_usize()))
|
||||
} else {
|
||||
// EDK2 internals seem to assume a single ServiceBinding Protocol for TCP4 and TCP6, and
|
||||
// thus does not use any service binding protocol data in destroying child sockets. It
|
||||
// does seem to suggest that we need to cleanup even the protocols created by accept. To
|
||||
// be on the safe side with other implementations, we will be using the same service
|
||||
// binding protocol as the parent TCP4 handle.
|
||||
//
|
||||
// https://github.com/tianocore/edk2/blob/f80580f56b267c96f16f985dbf707b2f96947da4/NetworkPkg/TcpDxe/TcpDriver.c#L938
|
||||
|
||||
let handle = NonNull::new(listen_token.new_child_handle).unwrap();
|
||||
let protocol = helpers::open_protocol(handle, tcp4::PROTOCOL_GUID)?;
|
||||
|
||||
Ok(Self {
|
||||
handle,
|
||||
service_binding: self.service_binding,
|
||||
protocol,
|
||||
flag: AtomicBool::new(false),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn connect(&self, timeout: Option<Duration>) -> io::Result<()> {
|
||||
let evt = unsafe { self.create_evt() }?;
|
||||
let completion_token =
|
||||
|
|
@ -352,6 +394,12 @@ impl Tcp4 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for Tcp4 {
|
||||
fn drop(&mut self) {
|
||||
let _ = unsafe { self.service_binding.destroy_child(self.handle) };
|
||||
}
|
||||
}
|
||||
|
||||
extern "efiapi" fn toggle_atomic_flag(_: r_efi::efi::Event, ctx: *mut crate::ffi::c_void) {
|
||||
let flag = unsafe { AtomicBool::from_ptr(ctx.cast()) };
|
||||
flag.store(true, Ordering::Relaxed);
|
||||
|
|
|
|||
|
|
@ -651,34 +651,38 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result<BorrowedDeviceP
|
|||
|
||||
/// Helper for UEFI Protocols which are created and destroyed using
|
||||
/// [EFI_SERVICE_BINDING_PROTOCOL](https://uefi.org/specs/UEFI/2.11/11_Protocols_UEFI_Driver_Model.html#efi-service-binding-protocol)
|
||||
///
|
||||
/// # Invariant
|
||||
/// - `handle` must always be a valid UEFI handle corresponding to the `service_guid`.
|
||||
/// - Copying `ServiceProtocol` is sound as long as `handle` remains valid.
|
||||
/// - For most service binding protocols (in edk2 implementations), such handles remain valid
|
||||
/// for the lifetime of the UEFI environment — effectively `'static`.
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct ServiceProtocol {
|
||||
service_guid: r_efi::efi::Guid,
|
||||
handle: NonNull<crate::ffi::c_void>,
|
||||
child_handle: NonNull<crate::ffi::c_void>,
|
||||
}
|
||||
|
||||
impl ServiceProtocol {
|
||||
pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result<Self> {
|
||||
/// Open a child handle on a service_binding protocol.
|
||||
pub(crate) fn open(
|
||||
service_guid: r_efi::efi::Guid,
|
||||
) -> io::Result<(Self, NonNull<crate::ffi::c_void>)> {
|
||||
let handles = locate_handles(service_guid)?;
|
||||
|
||||
for handle in handles {
|
||||
if let Ok(protocol) = open_protocol::<service_binding::Protocol>(handle, service_guid) {
|
||||
let Ok(child_handle) = Self::create_child(protocol) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
return Ok(Self { service_guid, handle, child_handle });
|
||||
if let Ok(child_handle) = unsafe { Self::create_child(protocol) } {
|
||||
return Ok((Self { service_guid, handle }, child_handle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found"))
|
||||
}
|
||||
|
||||
pub(crate) fn child_handle(&self) -> NonNull<crate::ffi::c_void> {
|
||||
self.child_handle
|
||||
}
|
||||
|
||||
fn create_child(
|
||||
// SAFETY: sbp must be a valid service binding protocol pointer
|
||||
unsafe fn create_child(
|
||||
sbp: NonNull<service_binding::Protocol>,
|
||||
) -> io::Result<NonNull<crate::ffi::c_void>> {
|
||||
let mut child_handle: r_efi::efi::Handle = crate::ptr::null_mut();
|
||||
|
|
@ -692,17 +696,17 @@ impl ServiceProtocol {
|
|||
.ok_or(const_error!(io::ErrorKind::Other, "null child handle"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ServiceProtocol {
|
||||
fn drop(&mut self) {
|
||||
if let Ok(sbp) = open_protocol::<service_binding::Protocol>(self.handle, self.service_guid)
|
||||
{
|
||||
// SAFETY: Child handle must be allocated by the current service binding protocol.
|
||||
let _ = unsafe {
|
||||
((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), self.child_handle.as_ptr())
|
||||
};
|
||||
}
|
||||
// SAFETY: Child handle must be allocated by the current service binding protocol and must be
|
||||
// valid.
|
||||
pub(crate) unsafe fn destroy_child(
|
||||
&self,
|
||||
handle: NonNull<crate::ffi::c_void>,
|
||||
) -> io::Result<()> {
|
||||
let sbp = open_protocol::<service_binding::Protocol>(self.handle, self.service_guid)?;
|
||||
|
||||
let r = unsafe { ((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), handle.as_ptr()) };
|
||||
if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,24 +2,11 @@
|
|||
// separate modules for each platform.
|
||||
#![cfg(target_os = "netbsd")]
|
||||
|
||||
use libc::{_lwp_self, CLOCK_MONOTONIC, c_long, clockid_t, lwpid_t, time_t, timespec};
|
||||
use libc::{_lwp_park, _lwp_self, _lwp_unpark, CLOCK_MONOTONIC, c_long, lwpid_t, time_t, timespec};
|
||||
|
||||
use crate::ffi::{c_int, c_void};
|
||||
use crate::ptr;
|
||||
use crate::time::Duration;
|
||||
|
||||
unsafe extern "C" {
|
||||
fn ___lwp_park60(
|
||||
clock_id: clockid_t,
|
||||
flags: c_int,
|
||||
ts: *mut timespec,
|
||||
unpark: lwpid_t,
|
||||
hint: *const c_void,
|
||||
unparkhint: *const c_void,
|
||||
) -> c_int;
|
||||
fn _lwp_unpark(lwp: lwpid_t, hint: *const c_void) -> c_int;
|
||||
}
|
||||
|
||||
pub type ThreadId = lwpid_t;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -30,7 +17,7 @@ pub fn current() -> ThreadId {
|
|||
#[inline]
|
||||
pub fn park(hint: usize) {
|
||||
unsafe {
|
||||
___lwp_park60(0, 0, ptr::null_mut(), 0, ptr::without_provenance(hint), ptr::null());
|
||||
_lwp_park(0, 0, ptr::null_mut(), 0, ptr::without_provenance(hint), ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,13 +32,13 @@ pub fn park_timeout(dur: Duration, hint: usize) {
|
|||
// Timeout needs to be mutable since it is modified on NetBSD 9.0 and
|
||||
// above.
|
||||
unsafe {
|
||||
___lwp_park60(
|
||||
_lwp_park(
|
||||
CLOCK_MONOTONIC,
|
||||
0,
|
||||
&mut timeout,
|
||||
0,
|
||||
ptr::without_provenance(hint),
|
||||
ptr::null(),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue