netstack: Add shutdown syscall

This commit is contained in:
Akshit Gaur
2026-01-19 17:07:08 +05:30
parent 41659cce0f
commit 557491b5e3
5 changed files with 159 additions and 13 deletions
+24 -1
View File
@@ -171,7 +171,9 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> SyscallResult<usize> {
if self.can_send() {
if !file.write_enabled {
return Err(SyscallError::new(syscall::EPIPE));
} else if self.can_send() {
match file.data.socket_type {
IcmpSocketType::Echo => {
if buf.len() < mem::size_of::<u16>() {
@@ -207,6 +209,9 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> SyscallResult<usize> {
if !file.read_enabled {
return Ok(0);
}
while self.can_recv() {
let (payload, _) = self.recv().expect("Can't recv icmp packet");
let icmp_packet = Icmpv4Packet::new_unchecked(&payload);
@@ -283,4 +288,22 @@ impl<'a> SchemeSocket for IcmpSocket<'a> {
) -> SyscallResult<usize> {
self.fpath(file, buf)
}
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
let socket_file = match file {
SchemeFile::Socket(ref mut file) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match how {
0 => socket_file.read_enabled = false, // SHUT_RD
1 => socket_file.write_enabled = false, // SHUT_WR
2 => {
socket_file.read_enabled = false;
socket_file.write_enabled = false;
} // SHUT_RDWR
_ => return Err(SyscallError::new(syscall::EINVAL)),
}
Ok(0)
}
}
+24 -2
View File
@@ -98,7 +98,9 @@ impl<'a> SchemeSocket for RawSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> SyscallResult<usize> {
if self.can_send() {
if !file.write_enabled {
return Err(SyscallError::new(syscall::EPIPE));
} else if self.can_send() {
self.send_slice(buf).expect("Can't send slice");
Ok(buf.len())
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
@@ -113,7 +115,9 @@ impl<'a> SchemeSocket for RawSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> SyscallResult<usize> {
if self.can_recv() {
if !file.read_enabled {
Ok(0)
} else if self.can_recv() {
let length = self.recv_slice(buf).expect("Can't receive slice");
Ok(length)
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
@@ -152,4 +156,22 @@ impl<'a> SchemeSocket for RawSocket<'a> {
) -> SyscallResult<usize> {
self.fpath(file, buf)
}
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
let socket_file = match file {
SchemeFile::Socket(ref mut file) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match how {
0 => socket_file.read_enabled = false, // SHUT_RD
1 => socket_file.write_enabled = false, // SHUT_WR
2 => {
socket_file.read_enabled = false;
socket_file.write_enabled = false;
} // SHUT_RDWR
_ => return Err(SyscallError::new(syscall::EINVAL)),
}
Ok(0)
}
}
+59 -7
View File
@@ -39,6 +39,8 @@ pub struct NullFile {
pub flags: usize,
pub uid: u32,
pub gid: u32,
pub read_enabled: bool,
pub write_enabled: bool,
}
pub struct SocketFile<DataT> {
@@ -51,6 +53,8 @@ pub struct SocketFile<DataT> {
write_notified: bool,
read_timeout: Option<TimeSpec>,
write_timeout: Option<TimeSpec>,
pub read_enabled: bool,
pub write_enabled: bool,
}
impl<DataT> SocketFile<DataT> {
@@ -63,6 +67,8 @@ impl<DataT> SocketFile<DataT> {
read_timeout: self.read_timeout,
write_timeout: self.write_timeout,
socket_handle: self.socket_handle,
read_enabled: self.read_enabled,
write_enabled: self.write_enabled,
data,
}
}
@@ -75,6 +81,8 @@ impl<DataT> SocketFile<DataT> {
write_notified: false,
read_timeout: None,
write_timeout: None,
read_enabled: true,
write_enabled: true,
socket_handle,
data,
}
@@ -226,6 +234,8 @@ where
file: &SchemeFile<Self>,
payload: &mut [u8],
) -> SyscallResult<usize>;
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
}
pub struct SocketScheme<SocketT>
@@ -442,6 +452,32 @@ where
SocketT::handle_get_peer_name(socket, file, payload)
}
SocketCall::Shutdown => {
let how = metadata[1] as usize;
if let Some(null_file) = self.nulls.get_mut(&fd) {
match how {
0 => null_file.read_enabled = false,
1 => null_file.write_enabled = false,
2 => {
null_file.read_enabled = false;
null_file.write_enabled = false;
}
_ => return Err(SyscallError::new(EINVAL)),
}
return Ok(0);
}
let file = self
.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
let mut socket_set = self.socket_set.borrow_mut();
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
SocketT::handle_shutdown(socket, file, how)
}
_ => Err(SyscallError::new(EOPNOTSUPP)),
}
}
@@ -452,9 +488,17 @@ where
flags: usize,
uid: u32,
gid: u32,
read_enabled: bool,
write_enabled: bool,
) -> SyscallResult<OpenResult> {
if path.is_empty() {
let null = NullFile { flags, uid, gid };
let null = NullFile {
flags,
uid,
gid,
read_enabled,
write_enabled,
};
let id = self.next_fd;
self.next_fd += 1;
@@ -482,6 +526,8 @@ where
write_notified: false,
write_timeout: None,
read_timeout: None,
read_enabled: read_enabled,
write_enabled: write_enabled,
data,
});
@@ -504,7 +550,7 @@ where
SocketT: SchemeSocket + AnySocket<'static>,
{
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
self.open_inner(path, flags, ctx.uid, ctx.gid)
self.open_inner(path, flags, ctx.uid, ctx.gid, true, true)
}
fn call(
@@ -642,13 +688,19 @@ where
fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult<OpenResult> {
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
if let Some((flags, uid, gid)) = self
.nulls
.get(&fd)
.map(|null| (null.flags, null.uid, null.gid))
if let Some((flags, uid, gid, read_enabled, write_enabled)) =
self.nulls.get(&fd).map(|null| {
(
null.flags,
null.uid,
null.gid,
null.read_enabled,
null.write_enabled,
)
})
{
// dup from empty path to a new path
return self.open_inner(path, flags, uid, gid);
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
}
let new_file = {
+28 -2
View File
@@ -153,7 +153,9 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &[u8],
) -> SyscallResult<usize> {
if !self.is_active() {
if !file.write_enabled {
return Err(SyscallError::new(syscall::EPIPE));
} else if !self.is_active() {
Err(SyscallError::new(syscall::ENOTCONN))
} else if self.can_send() {
self.send_slice(buf).expect("Can't send slice");
@@ -170,7 +172,9 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> SyscallResult<usize> {
if !self.is_active() {
if !file.read_enabled {
Ok(0)
} else if !self.is_active() {
Err(SyscallError::new(syscall::ENOTCONN))
} else if self.can_recv() {
let length = self.recv_slice(buf).expect("Can't receive slice");
@@ -308,4 +312,26 @@ impl<'a> SchemeSocket for TcpSocket<'a> {
) -> SyscallResult<usize> {
self.fpath(file, buf)
}
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
let socket_file = match file {
SchemeFile::Socket(ref mut file) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match how {
0 => socket_file.read_enabled = false, // SHUT_RD
1 => {
socket_file.write_enabled = false;
self.close();
} // SHUT_WR
2 => {
socket_file.read_enabled = false;
socket_file.write_enabled = false;
self.close();
} // SHUT_RDWR
_ => return Err(SyscallError::new(syscall::EINVAL)),
}
Ok(0)
}
}
+24 -1
View File
@@ -144,6 +144,9 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
if !file.data.is_specified() {
return Err(SyscallError::new(syscall::EADDRNOTAVAIL));
}
if !file.write_enabled {
return Err(SyscallError::new(syscall::EPIPE));
}
if self.can_send() {
let endpoint = file.data;
let endpoint = IpEndpoint::new(
@@ -166,7 +169,9 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
file: &mut SocketFile<Self::DataT>,
buf: &mut [u8],
) -> SyscallResult<usize> {
if self.can_recv() {
if !file.read_enabled {
Ok(0)
} else if self.can_recv() {
let (length, _) = self.recv_slice(buf).expect("Can't receive slice");
Ok(length)
} else if file.flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK {
@@ -257,4 +262,22 @@ impl<'a> SchemeSocket for UdpSocket<'a> {
) -> SyscallResult<usize> {
self.fpath(file, buf)
}
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize> {
let socket_file = match file {
SchemeFile::Socket(ref mut file) => file,
_ => return Err(SyscallError::new(syscall::EBADF)),
};
match how {
0 => socket_file.read_enabled = false, // SHUT_RD
1 => socket_file.write_enabled = false, // SHUT_WR
2 => {
socket_file.read_enabled = false;
socket_file.write_enabled = false;
} // SHUT_RDWR
_ => return Err(SyscallError::new(syscall::EINVAL)),
}
Ok(0)
}
}