diff --git a/kernel-src/arch/x86-64/syscall.asm b/kernel-src/arch/x86-64/syscall.asm index ba17b970..dc00958d 100644 --- a/kernel-src/arch/x86-64/syscall.asm +++ b/kernel-src/arch/x86-64/syscall.asm @@ -101,6 +101,7 @@ extern syscall_readv extern syscall_yield extern syscall_fstatvfs extern syscall_fstatvfsat +extern syscall_getsockopt syscalltab: dq syscall_print dq syscall_mmap @@ -204,7 +205,8 @@ dq syscall_readv dq syscall_yield dq syscall_fstatvfs dq syscall_fstatvfsat -syscallcount equ 102 +dq syscall_getsockopt +syscallcount equ 103 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 07202c44..6272eca7 100644 --- a/kernel-src/arch/x86-64/syscalllog.c +++ b/kernel-src/arch/x86-64/syscalllog.c @@ -8,7 +8,7 @@ void arch_interrupt_disable(); void arch_interrupt_enable(); -#define SYSCALL_COUNT 102 +#define SYSCALL_COUNT 103 #define LOGSTR(x) arch_e9_puts(x) static char *name[] = { @@ -114,6 +114,7 @@ static char *name[] = { "yield", "fstatvfs", "fstatvfsat", + "getsockopt", }; static char *args[] = { @@ -219,6 +220,7 @@ static char *args[] = { "N/A", // yield "fd %d ustat %p", // fstatvfs "dirfd %d path %s ustat %p flags %d", // fstatvfsat + "fd %d level %d optname %d optval %p optlen %p", // getsockopt }; #endif diff --git a/kernel-src/include/kernel/abi.h b/kernel-src/include/kernel/abi.h index 777a7fd8..dcddff6e 100644 --- a/kernel-src/include/kernel/abi.h +++ b/kernel-src/include/kernel/abi.h @@ -98,9 +98,29 @@ typedef struct { #define MSG_WAITALL 0x100 #define MSG_NOSIGNAL 0x4000 -#define SO_BROADCAST 6 +#define TCP_NODELAY 1 +#define TCP_KEEPIDLE 4 +#define TCP_KEEPINTVL 5 + +#define IP_TOS 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_LINGER 13 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 #define SO_BINDTODEVICE 25 -#define SO_KEEPALIVE 9 +#define SO_ACCEPTCONN 30 +#define SO_PROTOCOL 38 +#define SO_DOMAIN 39 #define SOL_SOCKET 1 diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index e9b89bc2..62a1ba66 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -73,7 +73,8 @@ typedef struct socketops_t { int (*getpeername)(socket_t *socket, sockaddr_t *addr); size_t (*datacount)(socket_t *socket); void (*destroy)(socket_t *socket); - int (*setopt)(socket_t *socket, int optname, void *buffer, size_t len, cred_t *cred); + int (*setopt)(socket_t *socket, int layer, int optname, void *buffer, socklen_t len, cred_t *cred); + int (*getopt)(socket_t *socket, int layer, int optname, void *buffer, socklen_t *len, cred_t *cred); int (*shutdown)(socket_t *socket, int how); } socketops_t; diff --git a/kernel-src/sys/syscalls/getsockopt.c b/kernel-src/sys/syscalls/getsockopt.c new file mode 100644 index 00000000..b4e3e8c7 --- /dev/null +++ b/kernel-src/sys/syscalls/getsockopt.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +syscallret_t syscall_getsockopt(context_t *, int fd, int level, int optname, void *val, socklen_t *len) { + syscallret_t ret = { + .ret = -1 + }; + + if (!IS_USER_ADDRESS(val) || !IS_USER_ADDRESS(len)) { + ret.errno = EFAULT; + } + + file_t *file = fd_get(fd); + if (file == NULL) { + ret.errno = EBADF; + return ret; + } + + if (file->vnode->type != V_TYPE_SOCKET) { + ret.errno = ENOTSOCK; + goto cleanup; + } + + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(file->vnode); + + MUTEX_ACQUIRE(&socket->mutex); + if (level == SOL_SOCKET) { + // handle some general cases + switch (optname) { + case SO_ERROR: { + socklen_t l; + ret.errno = usercopy_fromuser(&l, len, sizeof(l)); + if (ret.errno) + break; + + if (l != 4) { + ret.errno = EINVAL; + break; + } + + int error = socket->error; + ret.errno = usercopy_touser(val, &error, sizeof(error)); + if (!ret.errno) + socket->error = 0; + + break; + } + default: { + ret.errno = socket->ops->getopt ? socket->ops->getopt(socket, level, optname, val, len, ¤t_thread()->proc->cred) : ENOPROTOOPT; + } + } + } else { + ret.errno = socket->ops->getopt ? socket->ops->getopt(socket, level, optname, val, len, ¤t_thread()->proc->cred) : ENOPROTOOPT; + } + + MUTEX_RELEASE(&socket->mutex); + + cleanup: + ret.ret = ret.errno ? -1 : 0; + + fd_release(file); + return ret; +}