From 9c4fe1a594bbec8bb6721169ae5e3c4642d2762e Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 7 Apr 2024 16:40:02 -0300 Subject: [PATCH] syscall: multiple syscalls related to sockets --- kernel-src/arch/x86-64/main.c | 8 ++++ kernel-src/arch/x86-64/syscall.asm | 12 ++++- kernel-src/arch/x86-64/syscalllog.c | 16 +++++-- kernel-src/sys/syscalls/bind.c | 56 ++++++++++++++++++++++ kernel-src/sys/syscalls/recvmsg.c | 59 ++++++++++++++++++++++++ kernel-src/sys/syscalls/sendmsg.c | 59 ++++++++++++++++++++++++ kernel-src/sys/syscalls/setsockopt.c | 69 ++++++++++++++++++++++++++++ kernel-src/sys/syscalls/socket.c | 58 +++++++++++++++++++++++ 8 files changed, 333 insertions(+), 4 deletions(-) create mode 100644 kernel-src/sys/syscalls/bind.c create mode 100644 kernel-src/sys/syscalls/recvmsg.c create mode 100644 kernel-src/sys/syscalls/sendmsg.c create mode 100644 kernel-src/sys/syscalls/setsockopt.c create mode 100644 kernel-src/sys/syscalls/socket.c diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index 36aedb74..f8ebdf25 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include static cpu_t bsp_cpu; @@ -63,8 +65,14 @@ void kernel_entry() { tmpfs_init(); devfs_init(); pipefs_init(); + sockfs_init(); ext2_init(); + netdev_init(); + arp_init(); + ipv4_init(); + udp_init(); + block_init(); pseudodevices_init(); arch_e9_initdev(); diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index f28969e8..a7de3533 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -40,6 +40,11 @@ extern syscall_mount extern syscall_fchownat extern syscall_utimensat extern syscall_renameat +extern syscall_socket +extern syscall_bind +extern syscall_sendmsg +extern syscall_setsockopt +extern syscall_recvmsg syscalltab: dq syscall_print dq syscall_mmap @@ -82,7 +87,12 @@ dq syscall_mount dq syscall_fchownat dq syscall_utimensat dq syscall_renameat -syscallcount equ 41 +dq syscall_socket +dq syscall_bind +dq syscall_sendmsg +dq syscall_setsockopt +dq syscall_recvmsg +syscallcount equ 46 section .text global arch_syscall_entry ; on entry: diff --git a/kernel-src/arch/x86-64/syscalllog.c b/kernel-src/arch/x86-64/syscalllog.c index 0b2e8908..6ba58b7c 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -4,7 +4,7 @@ #ifdef SYSCALL_LOGGING -#define SYSCALL_COUNT 41 +#define SYSCALL_COUNT 46 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -48,7 +48,12 @@ static char *name[] = { "mount", "fchownat", "utimensat", - "renameat" + "renameat", + "socket", + "bind", + "sendmsg", + "setsockopt", + "recvmsg" }; static char *args[] = { @@ -92,7 +97,12 @@ static char *args[] = { "backing %p mountpoint %s fs %s flags %d data %p", // mount "fd %d path %s owner %d group %d flags %x", // fchownat "dirfd %d path %p times %p flags %x", // utimensat - "olddirfd %d oldpath %s newdirfd %d newpath %s flags %d" // renameat + "olddirfd %d oldpath %s newdirfd %d newpath %s flags %d", // renameat + "domain %d type %d protocol %d\n", // socket + "fd %d addr %p len %d\n", // bind + "fd %d msghdr %p flags %d", // sendmsg + "fd %d level %d optname %d optval %p optlen %lu", // setsockopt + "fd %d msghdr %p flags %d", // recvmsg }; #endif diff --git a/kernel-src/sys/syscalls/bind.c b/kernel-src/sys/syscalls/bind.c new file mode 100644 index 00000000..e5b742c4 --- /dev/null +++ b/kernel-src/sys/syscalls/bind.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +syscallret_t syscall_bind(context_t *, int fd, void *uaddr, size_t addrlen) { + syscallret_t ret = { + .ret = -1 + }; + + if (addrlen > 1024) { + ret.errno = EINVAL; + return ret; + } + + abisockaddr_t *addr = alloc(addrlen); + if (addr == NULL) { + ret.errno = ENOMEM; + return ret; + } + + file_t *file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + goto cleanup; + } + + if (file->vnode->type != V_TYPE_SOCKET) { + ret.errno = ENOTSOCK; + goto cleanup; + } + + memcpy(addr, uaddr, addrlen); + + sockaddr_t sockaddr; + ret.errno = sock_convertaddress(&sockaddr, addr); + if (ret.errno) + goto cleanup; + + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + + ret.errno = socket->ops->bind(socket, &sockaddr); + ret.ret = ret.errno ? -1 : 0; + + cleanup: + if (file) + fd_release(file); + + free(addr); + return ret; +} diff --git a/kernel-src/sys/syscalls/recvmsg.c b/kernel-src/sys/syscalls/recvmsg.c new file mode 100644 index 00000000..f2655cb4 --- /dev/null +++ b/kernel-src/sys/syscalls/recvmsg.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include + +syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) { + __assert(flags == 0); + syscallret_t ret; + + msghdr_t msghdr; + ret.errno = sock_copymsghdr(&msghdr, umsghdr); + if (ret.errno) + return ret; + + file_t *file = NULL; + size_t buffersize = iovec_size(msghdr.iov, msghdr.iovcount); + void *buffer = vmm_map(NULL, buffersize, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL); + if (buffer == NULL) { + ret.errno = ENOMEM; + goto cleanup; + } + + file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + goto cleanup; + } + + sockaddr_t sockaddr; + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + size_t recvcount; + ret.errno = socket->ops->recv(socket, &sockaddr, buffer, buffersize, 0, &recvcount); + ret.ret = ret.errno ? -1 : recvcount; + + uintmax_t iovoffset = 0; + for (int i = 0; i < msghdr.iovcount; ++i) { + memcpy(msghdr.iov[i].addr, (void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].len); + iovoffset += msghdr.iov[i].len; + } + + if (umsghdr->addr) { + ret.errno = sock_addrtoabiaddr(socket->type, &sockaddr, umsghdr->addr); + if (ret.errno) + goto cleanup; + } + + cleanup: + if (file) + fd_release(file); + + if (buffer) + vmm_unmap(buffer, buffersize, 0); + + sock_freemsghdr(&msghdr); + return ret; +} diff --git a/kernel-src/sys/syscalls/sendmsg.c b/kernel-src/sys/syscalls/sendmsg.c new file mode 100644 index 00000000..2c51cd2e --- /dev/null +++ b/kernel-src/sys/syscalls/sendmsg.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include + +syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) { + __assert(flags == 0); + syscallret_t ret; + + msghdr_t msghdr; + ret.errno = sock_copymsghdr(&msghdr, umsghdr); + if (ret.errno) + return ret; + + file_t *file = NULL; + size_t buffersize = iovec_size(msghdr.iov, msghdr.iovcount); + void *buffer = vmm_map(NULL, buffersize, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL); + if (buffer == NULL) { + ret.errno = ENOMEM; + goto cleanup; + } + + uintmax_t iovoffset = 0; + + for (int i = 0; i < msghdr.iovcount; ++i) { + memcpy((void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].addr, msghdr.iov[i].len); + iovoffset += msghdr.iov[i].len; + } + + file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + goto cleanup; + } + + sockaddr_t sockaddr; + if (msghdr.addr) { + ret.errno = sock_convertaddress(&sockaddr, msghdr.addr); + if (ret.errno) + goto cleanup; + } + + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + size_t sendcount; + ret.errno = socket->ops->send(socket, msghdr.addr ? &sockaddr : NULL, buffer, buffersize, 0, &sendcount); + ret.ret = ret.errno ? -1 : sendcount; + + cleanup: + if (file) + fd_release(file); + + if (buffer) + vmm_unmap(buffer, buffersize, 0); + + sock_freemsghdr(&msghdr); + return ret; +} diff --git a/kernel-src/sys/syscalls/setsockopt.c b/kernel-src/sys/syscalls/setsockopt.c new file mode 100644 index 00000000..f019edb6 --- /dev/null +++ b/kernel-src/sys/syscalls/setsockopt.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include + +syscallret_t syscall_setsockopt(context_t *, int fd, int level, int optname, void *val, size_t len) { + syscallret_t ret = { + .ret = -1 + }; + + if (level != SOL_SOCKET) { + ret.errno = ENOPROTOOPT; + return ret; + } + + void *buffer = NULL; + if (val) { + buffer = alloc(len); + if (buffer == NULL) { + ret.errno = ENOMEM; + return ret; + } + memcpy(buffer, val, len); + } + + file_t *file = fd_get(fd); + if (file == NULL) { + free(buffer); + ret.errno = EBADF; + return ret; + } + + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + + + MUTEX_ACQUIRE(&socket->mutex, false); + switch (optname) { + case SO_BINDTODEVICE: + if (val) { + socket->netdev = netdev_getdev(val); + ret.errno = socket->netdev ? 0 : ENODEV; + } else { + socket->netdev = NULL; + } + break; + case SO_BROADCAST: + if (val == NULL) { + ret.errno = EFAULT; + } else { + socket->broadcast = *((int *)buffer); + ret.errno = 0; + } + break; + default: + ret.errno = ENOPROTOOPT; + } + + MUTEX_RELEASE(&socket->mutex); + + ret.ret = ret.errno ? -1 : 0; + + fd_release(file); + + if (val) + free(buffer); + + return ret; +} diff --git a/kernel-src/sys/syscalls/socket.c b/kernel-src/sys/syscalls/socket.c new file mode 100644 index 00000000..e4d5633a --- /dev/null +++ b/kernel-src/sys/syscalls/socket.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +syscallret_t syscall_socket(context_t *, int domain, int type, int protocol) { + syscallret_t ret = { + .ret = -1 + }; + + int socktype = -1; + + switch (domain) { + case AF_INET: + if (type != SOCK_DGRAM) + break; + + socktype = SOCKET_TYPE_UDP; + break; + } + + if (socktype == -1) { + ret.errno = EAFNOSUPPORT; + return ret; + } + + socket_t *socket = socket_create(socktype); + if (socket == NULL) { + ret.errno = ENOMEM; + return ret; + } + + vnode_t *vnode; + ret.errno = sockfs_newsocket(&vnode, socket); + if (ret.errno) { + // TODO delete socket + return ret; + } + + file_t *file; + int fd; + + ret.errno = fd_new(0, &file, &fd); + if (ret.errno) { + // socket gets deleted by node cleanup + VOP_RELEASE(vnode); + return ret; + } + + file->vnode = vnode; + file->flags = FILE_READ | FILE_WRITE; + file->offset = 0; + file->mode = 0777; + + ret.ret = fd; + + return ret; +}