diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 4c480daf..4481c400 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -39,6 +39,10 @@ use crate::{ brk::sys_brk, mmap::{sys_mmap, sys_mprotect, sys_munmap}, }, + net::syscalls::{ + recv::sys_recvfrom, send::sys_sendto, sys_accept, sys_bind, sys_connect, sys_listen, + sys_shutdown, sys_socket, + }, process::{ clone::sys_clone, creds::{ @@ -348,7 +352,34 @@ pub async fn handle_syscall() { 0xb1 => sys_getegid().map_err(|e| match e {}), 0xb2 => sys_gettid().map_err(|e| match e {}), 0xb3 => sys_sysinfo(TUA::from_value(arg1 as _)).await, - 0xc6 => Err(KernelError::NotSupported), + 0xc6 => sys_socket(arg1 as _, arg2 as _, arg3 as _).await, + 0xc8 => sys_bind(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, + 0xc9 => sys_listen(arg1.into(), arg2 as _).await, + 0xca => sys_accept(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, + 0xcb => sys_connect(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, + 0xce => { + sys_sendto( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + TUA::from_value(arg5 as _), + arg6 as _, + ) + .await + } + 0xcf => { + sys_recvfrom( + arg1.into(), + TUA::from_value(arg2 as _), + arg3 as _, + arg4 as _, + TUA::from_value(arg5 as _), + arg6 as _, + ) + .await + } + 0xd2 => sys_shutdown(arg1.into(), arg2 as _).await, 0xd6 => sys_brk(VA::from_value(arg1 as _)) .await .map_err(|e| match e {}), diff --git a/src/console/chardev.rs b/src/console/chardev.rs index 871b0a04..f05168f6 100644 --- a/src/console/chardev.rs +++ b/src/console/chardev.rs @@ -28,7 +28,7 @@ impl OpenableDevice for TtyDev { Ok(task .fd_table .lock_save_irq() - .get(Fd(0)) + .get_file(Fd(0)) .ok_or(FsError::NoDevice)?) } } diff --git a/src/fs/dir.rs b/src/fs/dir.rs index 4713dd36..a85f7bc2 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -136,7 +136,7 @@ pub async fn sys_getdents64(fd: Fd, mut ubuf: UA, size: u32) -> Result { let file = task .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let (ops, ctx) = &mut *file.lock().await; diff --git a/src/fs/syscalls/at/mod.rs b/src/fs/syscalls/at/mod.rs index 0cbf48cd..6cefed92 100644 --- a/src/fs/syscalls/at/mod.rs +++ b/src/fs/syscalls/at/mod.rs @@ -50,7 +50,7 @@ async fn resolve_at_start_node(dirfd: Fd, path: &Path) -> Result> let file = task .fd_table .lock_save_irq() - .get(dirfd) + .get_file(dirfd) .ok_or(KernelError::BadFd)?; let inode = file.inode().ok_or(KernelError::NotSupported)?; diff --git a/src/fs/syscalls/chdir.rs b/src/fs/syscalls/chdir.rs index 755fb189..8e42b0ee 100644 --- a/src/fs/syscalls/chdir.rs +++ b/src/fs/syscalls/chdir.rs @@ -62,7 +62,7 @@ pub async fn sys_fchdir(fd: Fd) -> Result { let file = task .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; *task.cwd.lock_save_irq() = ( diff --git a/src/fs/syscalls/close.rs b/src/fs/syscalls/close.rs index b9617f38..6950b4a2 100644 --- a/src/fs/syscalls/close.rs +++ b/src/fs/syscalls/close.rs @@ -1,20 +1,29 @@ +use crate::process::fd_table::FileDescriptorEntryItem; use crate::{process::fd_table::Fd, sched::current_task}; use alloc::sync::Arc; use libkernel::error::{KernelError, Result}; pub async fn sys_close(fd: Fd) -> Result { - let file = current_task() + let fd_item = current_task() .fd_table .lock_save_irq() .remove(fd) .ok_or(KernelError::BadFd)?; - if let Some(file) = Arc::into_inner(file) { - let (ops, ctx) = &mut *file.lock().await; - ops.release(ctx).await?; + match fd_item { + FileDescriptorEntryItem::File(file) => { + if let Some(file) = Arc::into_inner(file) { + let (ops, ctx) = &mut *file.lock().await; + ops.release(ctx).await?; - Ok(0) - } else { - Ok(0) + Ok(0) + } else { + Ok(0) + } + } + FileDescriptorEntryItem::Socket(socket) => { + todo!(); + Ok(0) + } } } diff --git a/src/fs/syscalls/ioctl.rs b/src/fs/syscalls/ioctl.rs index 8d91ac4f..f3b18012 100644 --- a/src/fs/syscalls/ioctl.rs +++ b/src/fs/syscalls/ioctl.rs @@ -5,7 +5,7 @@ pub async fn sys_ioctl(fd: Fd, request: usize, arg: usize) -> Result { let fd = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let (ops, ctx) = &mut *fd.lock().await; diff --git a/src/fs/syscalls/iov.rs b/src/fs/syscalls/iov.rs index 0a334c30..2dd8b959 100644 --- a/src/fs/syscalls/iov.rs +++ b/src/fs/syscalls/iov.rs @@ -22,7 +22,7 @@ pub async fn sys_writev(fd: Fd, iov_ptr: TUA, no_iov: usize) -> Result, no_iov: usize) -> Result Result { let file = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let (ops, ctx) = &mut *file.lock().await; @@ -20,7 +20,7 @@ pub async fn sys_read(fd: Fd, user_buf: UA, count: usize) -> Result { let file = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let (ops, ctx) = &mut *file.lock().await; diff --git a/src/fs/syscalls/seek.rs b/src/fs/syscalls/seek.rs index ef8fd4a7..6a72bc3a 100644 --- a/src/fs/syscalls/seek.rs +++ b/src/fs/syscalls/seek.rs @@ -19,7 +19,7 @@ pub async fn sys_lseek(fd: Fd, offset: isize, whence: i32) -> Result { let fd = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let (ops, ctx) = &mut *fd.lock().await; diff --git a/src/fs/syscalls/splice.rs b/src/fs/syscalls/splice.rs index 1e232658..90cf13c4 100644 --- a/src/fs/syscalls/splice.rs +++ b/src/fs/syscalls/splice.rs @@ -15,8 +15,8 @@ pub async fn sys_sendfile( let task = current_task(); let fds = task.fd_table.lock_save_irq(); - let reader = fds.get(in_fd).ok_or(KernelError::BadFd)?; - let writer = fds.get(out_fd).ok_or(KernelError::BadFd)?; + let reader = fds.get_file(in_fd).ok_or(KernelError::BadFd)?; + let writer = fds.get_file(out_fd).ok_or(KernelError::BadFd)?; (reader, writer) }; diff --git a/src/fs/syscalls/stat.rs b/src/fs/syscalls/stat.rs index 595ac47b..3708e11b 100644 --- a/src/fs/syscalls/stat.rs +++ b/src/fs/syscalls/stat.rs @@ -8,7 +8,7 @@ pub async fn sys_fstat(fd: Fd, statbuf: TUA) -> Result { let fd = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let inode = fd.inode().ok_or(KernelError::BadFd)?; diff --git a/src/fs/syscalls/trunc.rs b/src/fs/syscalls/trunc.rs index 3bc97556..2bd458b1 100644 --- a/src/fs/syscalls/trunc.rs +++ b/src/fs/syscalls/trunc.rs @@ -33,7 +33,7 @@ pub async fn sys_ftruncate(fd: Fd, new_size: usize) -> Result { let fd = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let (ops, ctx) = &mut *fd.lock().await; diff --git a/src/main.rs b/src/main.rs index 940cdf1f..60e6f17b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,7 @@ mod fs; mod interrupts; mod kernel; mod memory; +mod net; mod process; mod sched; mod sync; diff --git a/src/memory/mmap.rs b/src/memory/mmap.rs index 7ad313e2..f876f5f5 100644 --- a/src/memory/mmap.rs +++ b/src/memory/mmap.rs @@ -92,7 +92,7 @@ pub async fn sys_mmap( let fd = current_task() .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; let inode = fd.inode().ok_or(KernelError::BadFd)?; diff --git a/src/net/mod.rs b/src/net/mod.rs new file mode 100644 index 00000000..afed693c --- /dev/null +++ b/src/net/mod.rs @@ -0,0 +1,3 @@ +pub mod open_socket; +mod sops; +pub mod syscalls; diff --git a/src/net/open_socket.rs b/src/net/open_socket.rs new file mode 100644 index 00000000..28fec004 --- /dev/null +++ b/src/net/open_socket.rs @@ -0,0 +1,27 @@ +use crate::net::sops::SocketOps; +use crate::sync::{AsyncMutexGuard, Mutex}; +use alloc::boxed::Box; + +pub struct SocketCtx {} + +impl SocketCtx { + pub fn new() -> Self { + Self {} + } +} + +pub struct OpenSocket { + state: Mutex<(Box, SocketCtx)>, +} + +impl OpenSocket { + pub fn new(ops: Box) -> Self { + Self { + state: Mutex::new((ops, SocketCtx::new())), + } + } + + pub async fn lock(&self) -> AsyncMutexGuard<'_, (Box, SocketCtx)> { + self.state.lock().await + } +} diff --git a/src/net/sops.rs b/src/net/sops.rs new file mode 100644 index 00000000..41a8f370 --- /dev/null +++ b/src/net/sops.rs @@ -0,0 +1,33 @@ +use crate::net::open_socket::SocketCtx; +use alloc::boxed::Box; +use alloc::vec::Vec; +use async_trait::async_trait; +use libkernel::error::{KernelError, Result}; + +#[async_trait] +pub trait SocketOps: Send + Sync { + async fn bind(&self, _ctx: &mut SocketCtx, _addr: &[u8]) -> Result<()> { + Err(KernelError::NotSupported) + } + async fn connect(&self, _ctx: &mut SocketCtx, _addr: &[u8]) -> Result<()> { + Err(KernelError::NotSupported) + } + async fn listen(&self, _ctx: &mut SocketCtx, _backlog: i32) -> Result<()> { + Err(KernelError::NotSupported) + } + async fn accept(&self, _ctx: &mut SocketCtx) -> Result> { + Err(KernelError::NotSupported) + } + async fn sendmsg(&self, _ctx: &mut SocketCtx, _msg: &[u8]) -> Result { + Err(KernelError::NotSupported) + } + async fn recvmsg(&self, _ctx: &mut SocketCtx, _buf: &mut [u8]) -> Result { + Err(KernelError::NotSupported) + } + fn getsockopt(&self, _ctx: &mut SocketCtx, _level: i32, _opt: i32) -> Result> { + Err(KernelError::NotSupported) + } + fn setsockopt(&self, _ctx: &mut SocketCtx, _level: i32, _opt: i32, _val: &[u8]) -> Result<()> { + Err(KernelError::NotSupported) + } +} diff --git a/src/net/syscalls/mod.rs b/src/net/syscalls/mod.rs new file mode 100644 index 00000000..39803e7f --- /dev/null +++ b/src/net/syscalls/mod.rs @@ -0,0 +1,113 @@ +use crate::process::fd_table::Fd; +use crate::sched::current_task; +use libkernel::error::KernelError; +use libkernel::memory::address::UA; + +pub mod recv; +pub mod send; + +pub enum AddressFamily { + Unix = 1, + Inet = 2, + Inet6 = 10, +} + +impl TryFrom for AddressFamily { + type Error = KernelError; + + fn try_from(value: i32) -> libkernel::error::Result { + match value { + 1 => Ok(AddressFamily::Unix), + 2 => Ok(AddressFamily::Inet), + 10 => Ok(AddressFamily::Inet6), + _ => Err(KernelError::InvalidValue), + } + } +} + +pub enum SocketType { + Datagram = 1, + Stream = 2, + Raw = 3, + RDM = 4, + SeqPacket = 5, + DCCP = 6, + Packet = 10, +} + +impl TryFrom for SocketType { + type Error = KernelError; + + fn try_from(value: i32) -> libkernel::error::Result { + match value { + 1 => Ok(SocketType::Datagram), + 2 => Ok(SocketType::Stream), + 3 => Ok(SocketType::Raw), + 4 => Ok(SocketType::RDM), + 5 => Ok(SocketType::SeqPacket), + 6 => Ok(SocketType::DCCP), + 10 => Ok(SocketType::Packet), + _ => Err(KernelError::InvalidValue), + } + } +} + +pub async fn sys_socket( + domain: i32, + type_: i32, + _protocol: i32, +) -> libkernel::error::Result { + let _family = AddressFamily::try_from(domain)?; + // TODO: mask out flags from type_ + let _socket_type = SocketType::try_from(type_)?; + Err(KernelError::NotSupported) +} + +pub async fn sys_bind(fd: Fd, addr: UA, addr_len: u32) -> libkernel::error::Result { + Err(KernelError::NotSupported) +} + +pub async fn sys_listen(fd: Fd, backlog: i32) -> libkernel::error::Result { + let task = current_task(); + let socket = task + .fd_table + .lock_save_irq() + .get_socket(fd) + .ok_or(KernelError::BadFd)?; + let (ops, state) = &mut *socket.lock().await; + ops.listen(state, backlog).await?; + Ok(0) +} + +pub async fn sys_accept(fd: Fd, addr: UA, addr_len: u32) -> libkernel::error::Result { + let _ = (addr, addr_len); + Err(KernelError::NotSupported) +} + +pub async fn sys_connect(fd: Fd, addr: UA, addr_len: u32) -> libkernel::error::Result { + Err(KernelError::NotSupported) +} + +pub enum ShutdownHow { + Read = 0, + Write = 1, + Both = 2, +} + +impl TryFrom for ShutdownHow { + type Error = KernelError; + + fn try_from(value: i32) -> libkernel::error::Result { + match value { + 0 => Ok(ShutdownHow::Read), + 1 => Ok(ShutdownHow::Write), + 2 => Ok(ShutdownHow::Both), + _ => Err(KernelError::InvalidValue), + } + } +} + +pub async fn sys_shutdown(fd: Fd, how: i32) -> libkernel::error::Result { + let _how = ShutdownHow::try_from(how)?; + Err(KernelError::NotSupported) +} diff --git a/src/net/syscalls/recv.rs b/src/net/syscalls/recv.rs new file mode 100644 index 00000000..e7fd8c6e --- /dev/null +++ b/src/net/syscalls/recv.rs @@ -0,0 +1,30 @@ +use crate::process::fd_table::Fd; +use libkernel::error::{KernelError, Result}; +use libkernel::memory::address::UA; + +async fn recv( + _fd: Fd, + _buf: UA, + _size: usize, + _flags: i32, + _src_addr: Option, + _addrlen: Option, +) -> Result { + Err(KernelError::NotSupported) +} + +#[allow(dead_code)] +pub async fn sys_recv(fd: Fd, buf: UA, size: usize, flags: i32) -> Result { + recv(fd, buf, size, flags, None, None).await +} + +pub async fn sys_recvfrom( + fd: Fd, + buf: UA, + size: usize, + flags: i32, + src_addr: UA, + addrlen: u32, +) -> Result { + recv(fd, buf, size, flags, Some(src_addr), Some(addrlen)).await +} diff --git a/src/net/syscalls/send.rs b/src/net/syscalls/send.rs new file mode 100644 index 00000000..96373b5d --- /dev/null +++ b/src/net/syscalls/send.rs @@ -0,0 +1,30 @@ +use crate::process::fd_table::Fd; +use libkernel::error::{KernelError, Result}; +use libkernel::memory::address::UA; + +async fn send( + _fd: Fd, + _buf: UA, + _size: usize, + _flags: i32, + _dest_addr: Option, + _addrlen: Option, +) -> Result { + Err(KernelError::NotSupported) +} + +#[allow(dead_code)] +pub async fn sys_send(fd: Fd, buf: UA, size: usize, flags: i32) -> Result { + send(fd, buf, size, flags, None, None).await +} + +pub async fn sys_sendto( + fd: Fd, + buf: UA, + size: usize, + flags: i32, + dest_addr: UA, + addrlen: u32, +) -> Result { + send(fd, buf, size, flags, Some(dest_addr), Some(addrlen)).await +} diff --git a/src/process/fd_table.rs b/src/process/fd_table.rs index 2f111722..cb1178fe 100644 --- a/src/process/fd_table.rs +++ b/src/process/fd_table.rs @@ -1,3 +1,5 @@ +use crate::net::open_socket::OpenSocket; +use crate::process::fd_table::select::PollFlags; use crate::{fs::open_file::OpenFile, memory::uaccess::UserCopyable}; use alloc::{sync::Arc, vec::Vec}; use libkernel::error::{FsError, Result}; @@ -39,9 +41,41 @@ bitflags::bitflags! { } } +#[derive(Clone)] +pub enum FileDescriptorEntryItem { + File(Arc), + Socket(Arc), +} + +impl FileDescriptorEntryItem { + pub async fn poll( + &self, + flags: PollFlags, + ) -> impl Future> + Send + use<> { + match self { + FileDescriptorEntryItem::File(file) => file.poll(flags).await, + FileDescriptorEntryItem::Socket(socket) => { + todo!(); + } + } + } +} + +impl From> for FileDescriptorEntryItem { + fn from(file: Arc) -> Self { + FileDescriptorEntryItem::File(file) + } +} + +impl From> for FileDescriptorEntryItem { + fn from(socket: Arc) -> Self { + FileDescriptorEntryItem::Socket(socket) + } +} + #[derive(Clone)] pub struct FileDescriptorEntry { - file: Arc, + item: FileDescriptorEntryItem, flags: FdFlags, } @@ -67,19 +101,43 @@ impl FileDescriptorTable { } /// Gets the file object associated with a given file descriptor. - pub fn get(&self, fd: Fd) -> Option> { + pub fn get(&self, fd: Fd) -> Option { self.entries .get(fd.0 as usize) .and_then(|entry| entry.as_ref()) - .map(|entry| entry.file.clone()) + .map(|entry| entry.item.clone()) + } + + pub fn get_file(&self, fd: Fd) -> Option> { + match self + .entries + .get(fd.0 as usize) + .and_then(|entry| entry.as_ref()) + .map(|entry| entry.item.clone())? + { + FileDescriptorEntryItem::File(file) => Some(file), + _ => None, + } + } + + pub fn get_socket(&self, fd: Fd) -> Option> { + match self + .entries + .get(fd.0 as usize) + .and_then(|entry| entry.as_ref()) + .map(|entry| entry.item.clone())? + { + FileDescriptorEntryItem::Socket(socket) => Some(socket), + _ => None, + } } /// Inserts a new file into the table, returning the new file descriptor. - pub fn insert(&mut self, file: Arc) -> Result { + pub fn insert(&mut self, item: impl Into) -> Result { let fd = self.find_free_fd()?; let entry = FileDescriptorEntry { - file, + item: item.into(), flags: FdFlags::default(), }; @@ -103,7 +161,7 @@ impl FileDescriptorTable { /// Removes a file descriptor from the table, returning the file if it /// existed. - pub fn remove(&mut self, fd: Fd) -> Option> { + pub fn remove(&mut self, fd: Fd) -> Option { let fd_idx = fd.0 as usize; if let Some(entry) = self.entries.get_mut(fd_idx) @@ -111,7 +169,7 @@ impl FileDescriptorTable { { // Update the hint to speed up the next search. self.next_fd_hint = self.next_fd_hint.min(fd_idx); - return Some(old_entry.file); + return Some(old_entry.item); } None diff --git a/src/process/fd_table/dup.rs b/src/process/fd_table/dup.rs index 5f6ed78a..7c959deb 100644 --- a/src/process/fd_table/dup.rs +++ b/src/process/fd_table/dup.rs @@ -37,7 +37,7 @@ pub fn sys_dup3(oldfd: Fd, newfd: Fd, flags: u32) -> Result { files.insert_at( newfd, FileDescriptorEntry { - file: old_file.clone(), + item: old_file.clone(), flags: if flags.contains(OpenFlags::O_CLOEXEC) { FdFlags::CLOEXEC } else { diff --git a/src/process/fd_table/fcntl.rs b/src/process/fd_table/fcntl.rs index d67765e8..7c8140ee 100644 --- a/src/process/fd_table/fcntl.rs +++ b/src/process/fd_table/fcntl.rs @@ -3,7 +3,7 @@ use libkernel::error::{KernelError, Result}; use crate::{process::fd_table::FdFlags, sched::current_task}; -use super::Fd; +use super::{Fd, FileDescriptorEntryItem}; const F_DUPFD: u32 = 0; // Duplicate file descriptor. const F_GETFD: u32 = 1; // Get file descriptor flags. @@ -48,8 +48,12 @@ pub async fn sys_fcntl(fd: Fd, op: u32, arg: usize) -> Result { .get_mut(fd.as_raw() as usize) .and_then(|entry| entry.as_mut()) .ok_or(KernelError::BadFd)?; - - fd.file.clone() + match fd.item.clone() { + FileDescriptorEntryItem::File(file) => file, + FileDescriptorEntryItem::Socket(_) => { + return Err(KernelError::InvalidValue); + } + } }; Ok(open_fd.flags().await.bits() as _) diff --git a/src/process/fd_table/select.rs b/src/process/fd_table/select.rs index 997293b5..d342e08c 100644 --- a/src/process/fd_table/select.rs +++ b/src/process/fd_table/select.rs @@ -84,7 +84,7 @@ pub async fn sys_pselect6( let file = task .fd_table .lock_save_irq() - .get(fd) + .get_file(fd) .ok_or(KernelError::BadFd)?; read_fds.push((