From 6767ac5c69975b437fa6eaa442e6c707d03c9162 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Sun, 15 Feb 2026 05:14:34 -0300 Subject: [PATCH] =?utf8?q?feat:=20sendmsg/recvmsg=20=E2=80=94=20advanced?= =?utf8?q?=20socket=20I/O=20with=20scatter-gather=20iovec=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- include/syscall.h | 3 ++ src/kernel/syscall.c | 79 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/include/syscall.h b/include/syscall.h index 14b9850..9f6aae0 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -143,6 +143,9 @@ enum { SYSCALL_INOTIFY_INIT = 115, SYSCALL_INOTIFY_ADD_WATCH = 116, SYSCALL_INOTIFY_RM_WATCH = 117, + + SYSCALL_SENDMSG = 118, + SYSCALL_RECVMSG = 119, }; #endif diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 64dbabf..0e03f02 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -4071,6 +4071,73 @@ static inline int sock_fd_get_sid(int fd) { return (int)f->node->inode; } +__attribute__((noinline)) +static int syscall_sendmsg_impl(int sockfd, void* user_msg, int flags) { + int sid = sock_fd_get_sid(sockfd); + if (sid < 0) return -EBADF; + + struct { void* name; uint32_t namelen; void* iov; uint32_t iovlen; + void* control; uint32_t controllen; int mflags; } kmsg; + if (copy_from_user(&kmsg, user_msg, sizeof(kmsg)) < 0) return -EFAULT; + + struct sockaddr_in dest; + int has_dest = 0; + if (kmsg.name && kmsg.namelen >= sizeof(dest)) { + if (copy_from_user(&dest, kmsg.name, sizeof(dest)) < 0) return -EFAULT; + has_dest = 1; + } + + int total = 0; + for (uint32_t i = 0; i < kmsg.iovlen && i < 16; i++) { + struct { void* base; uint32_t len; } kiov; + uint8_t* iov_arr = (uint8_t*)kmsg.iov; + if (copy_from_user(&kiov, &iov_arr[i * sizeof(kiov)], sizeof(kiov)) < 0) + return -EFAULT; + if (kiov.len == 0) continue; + if (!user_range_ok(kiov.base, kiov.len)) return -EFAULT; + int ret; + if (has_dest) + ret = ksocket_sendto(sid, kiov.base, kiov.len, flags, &dest); + else + ret = ksocket_send(sid, kiov.base, kiov.len, flags); + if (ret < 0) return (total > 0) ? total : ret; + total += ret; + } + return total; +} + +__attribute__((noinline)) +static int syscall_recvmsg_impl(int sockfd, void* user_msg, int flags) { + int sid = sock_fd_get_sid(sockfd); + if (sid < 0) return -EBADF; + + struct { void* name; uint32_t namelen; void* iov; uint32_t iovlen; + void* control; uint32_t controllen; int mflags; } kmsg; + if (copy_from_user(&kmsg, user_msg, sizeof(kmsg)) < 0) return -EFAULT; + + int total = 0; + struct sockaddr_in src; + memset(&src, 0, sizeof(src)); + + for (uint32_t i = 0; i < kmsg.iovlen && i < 16; i++) { + struct { void* base; uint32_t len; } kiov; + uint8_t* iov_arr = (uint8_t*)kmsg.iov; + if (copy_from_user(&kiov, &iov_arr[i * sizeof(kiov)], sizeof(kiov)) < 0) + return -EFAULT; + if (kiov.len == 0) continue; + if (!user_range_ok(kiov.base, kiov.len)) return -EFAULT; + int ret = ksocket_recvfrom(sid, kiov.base, kiov.len, flags, &src); + if (ret < 0) return (total > 0) ? total : ret; + total += ret; + if ((uint32_t)ret < kiov.len) break; + } + + if (kmsg.name && kmsg.namelen >= sizeof(src)) + (void)copy_to_user(kmsg.name, &src, sizeof(src)); + + return total; +} + /* Separate function to keep socket locals off syscall_handler's stack frame */ __attribute__((noinline)) static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) { @@ -4202,6 +4269,18 @@ static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) return; } + if (syscall_no == SYSCALL_SENDMSG) { + sc_ret(regs) = (uint32_t)syscall_sendmsg_impl( + (int)sc_arg0(regs), (void*)sc_arg1(regs), (int)sc_arg2(regs)); + return; + } + + if (syscall_no == SYSCALL_RECVMSG) { + sc_ret(regs) = (uint32_t)syscall_recvmsg_impl( + (int)sc_arg0(regs), (void*)sc_arg1(regs), (int)sc_arg2(regs)); + return; + } + if (syscall_no == SYSCALL_SETITIMER) { /* setitimer(which, user_new_value, user_old_value) * struct itimerval { uint32_t it_interval; uint32_t it_value; } (ticks) */ -- 2.43.0