diff --git a/src/backend/libc/net/netdevice.rs b/src/backend/libc/net/netdevice.rs index 887f768db..afdbb67fb 100644 --- a/src/backend/libc/net/netdevice.rs +++ b/src/backend/libc/net/netdevice.rs @@ -2,15 +2,11 @@ #![allow(unsafe_code)] -#[cfg(feature = "alloc")] -use crate::alloc::string::String; use crate::backend::c; use crate::backend::io::syscalls::ioctl; use crate::fd::BorrowedFd; use crate::io; -#[cfg(feature = "alloc")] -use c::SIOCGIFNAME; -use c::{__c_anonymous_ifr_ifru, c_char, ifreq, IFNAMSIZ, SIOCGIFINDEX}; +use c::{__c_anonymous_ifr_ifru, c_char, ifreq, IFNAMSIZ, SIOCGIFINDEX, SIOCGIFNAME}; pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result { let if_name_bytes = if_name.as_bytes(); @@ -31,8 +27,7 @@ pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result, index: u32) -> io::Result { +pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<(usize, [u8; 16])> { let mut ifreq = ifreq { ifr_name: [0; 16], ifr_ifru: __c_anonymous_ifr_ifru { @@ -43,12 +38,12 @@ pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result, if_name: &str) -> io::Result { let if_name_bytes = if_name.as_bytes(); @@ -40,8 +36,7 @@ pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result, index: u32) -> io::Result { +pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<(usize, [u8; 16])> { let mut ifreq = ifreq { ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] }, ifr_ifru: ifreq__bindgen_ty_2 { @@ -61,9 +56,10 @@ pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result(), ifrn_name.len()) }; - str::from_utf8(ifrn_name) - .map_err(|_| io::Errno::ILSEQ) - .map(ToOwned::to_owned) + let mut name_buf = [0; 16]; + name_buf[..ifrn_name.len()].copy_from_slice(ifrn_name); + + Ok((nul_byte, name_buf)) } else { Err(io::Errno::INVAL) } diff --git a/src/net/netdevice.rs b/src/net/netdevice.rs index 1ddd918ef..54872f52a 100644 --- a/src/net/netdevice.rs +++ b/src/net/netdevice.rs @@ -19,7 +19,7 @@ use crate::fd::AsFd; use crate::io; #[cfg(feature = "alloc")] -use alloc::string::String; +use alloc::{borrow::ToOwned, string::String}; /// `ioctl(fd, SIOCGIFINDEX, ifreq)`—Returns the interface index for a given /// name. @@ -42,6 +42,8 @@ pub fn name_to_index(fd: Fd, if_name: &str) -> io::Result { /// /// See the [module-level documentation] for information about `fd` usage. /// +/// See also [`index_to_name_inlined`] which does not require `alloc` feature. +/// /// # References /// - [Linux] /// @@ -52,12 +54,84 @@ pub fn name_to_index(fd: Fd, if_name: &str) -> io::Result { #[cfg(feature = "alloc")] #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub fn index_to_name(fd: Fd, index: u32) -> io::Result { - crate::backend::net::netdevice::index_to_name(fd.as_fd(), index) + let (len, ifrn_name) = crate::backend::net::netdevice::index_to_name(fd.as_fd(), index)?; + + core::str::from_utf8(&ifrn_name[..len]) + .map_err(|_| io::Errno::ILSEQ) + .map(ToOwned::to_owned) +} + +/// `ioctl(fd, SIOCGIFNAME, ifreq)`—Returns the interface name for a given +/// index. +/// +/// See the [module-level documentation] for information about `fd` usage. +/// +/// # References +/// - [Linux] +/// +/// [module-level documentation]: self +/// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html +#[inline] +#[doc(alias = "SIOCGIFNAME")] +pub fn index_to_name_inlined(fd: Fd, index: u32) -> io::Result { + let (len, ifrn_name) = crate::backend::net::netdevice::index_to_name(fd.as_fd(), index)?; + + // Check if the name is valid UTF-8. + core::str::from_utf8(&ifrn_name[..len]) + .map_err(|_| io::Errno::ILSEQ) + .map(|_| InlinedName { + len, + name: ifrn_name, + }) +} + +/// The inlined interface name. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct InlinedName { + len: usize, + name: [u8; 16], +} + +impl InlinedName { + /// Returns the str representation of the inlined name. + pub fn as_str(&self) -> &str { + self.as_ref() + } + + /// Returns the bytes representation of the inlined name. + pub fn as_bytes(&self) -> &[u8] { + self.as_ref() + } +} + +impl AsRef<[u8]> for InlinedName { + fn as_ref(&self) -> &[u8] { + &self.name[..self.len] + } +} + +impl AsRef for InlinedName { + fn as_ref(&self) -> &str { + // SAFETY: `InlinedName` is constructed with valid UTF-8. + core::str::from_utf8(&self.name[..self.len]).unwrap() + } +} + +impl core::borrow::Borrow for InlinedName { + fn borrow(&self) -> &str { + self.as_ref() + } +} + +impl core::fmt::Display for InlinedName { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.as_str().fmt(f) + } } #[cfg(test)] mod tests { - use crate::backend::net::netdevice::{index_to_name, name_to_index}; + use super::{index_to_name, index_to_name_inlined, name_to_index}; use crate::fd::AsFd; use crate::net::{AddressFamily, SocketFlags, SocketType}; @@ -81,6 +155,31 @@ mod tests { assert_eq!(Ok(loopback_index), name_to_index(fd.as_fd(), "lo")); } + #[test] + fn test_index_to_name_inlined() { + let fd = crate::net::socket_with( + AddressFamily::INET, + SocketType::DGRAM, + SocketFlags::CLOEXEC, + None, + ) + .unwrap(); + + let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex") + .unwrap() + .as_str() + .split_at(1) + .0 + .parse::() + .unwrap(); + assert_eq!( + "lo", + index_to_name_inlined(fd.as_fd(), loopback_index) + .unwrap() + .as_str(), + ); + } + #[test] #[cfg(feature = "alloc")] fn test_index_to_name() {