diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index 7355f143..944d2d2f 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -113,6 +113,8 @@ namespace Kernel BAN::ErrorOr recvmsg(msghdr& message, int flags); BAN::ErrorOr getsockname(sockaddr* address, socklen_t* address_len); BAN::ErrorOr getpeername(sockaddr* address, socklen_t* address_len); + BAN::ErrorOr getsockopt(int level, int option, void* value, socklen_t* value_len); + BAN::ErrorOr setsockopt(int level, int option, const void* value, socklen_t value_len); // General API BAN::ErrorOr read(off_t, BAN::ByteSpan buffer); @@ -161,6 +163,8 @@ namespace Kernel virtual BAN::ErrorOr sendmsg_impl(const msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } + virtual BAN::ErrorOr getsockopt_impl(int, int, void*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } + virtual BAN::ErrorOr setsockopt_impl(int, int, const void*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } // General API virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); } diff --git a/kernel/include/kernel/Networking/TCPSocket.h b/kernel/include/kernel/Networking/TCPSocket.h index a3298d57..fe21d1e6 100644 --- a/kernel/include/kernel/Networking/TCPSocket.h +++ b/kernel/include/kernel/Networking/TCPSocket.h @@ -63,6 +63,7 @@ namespace Kernel virtual BAN::ErrorOr recvmsg_impl(msghdr& message, int flags) override; virtual BAN::ErrorOr sendmsg_impl(const msghdr& message, int flags) override; virtual BAN::ErrorOr getpeername_impl(sockaddr*, socklen_t*) override; + virtual BAN::ErrorOr getsockopt_impl(int, int, void*, socklen_t*) override; virtual BAN::ErrorOr ioctl_impl(int, void*) override; diff --git a/kernel/include/kernel/Networking/UDPSocket.h b/kernel/include/kernel/Networking/UDPSocket.h index f5791025..bb3226d4 100644 --- a/kernel/include/kernel/Networking/UDPSocket.h +++ b/kernel/include/kernel/Networking/UDPSocket.h @@ -38,6 +38,7 @@ namespace Kernel virtual BAN::ErrorOr recvmsg_impl(msghdr& message, int flags) override; virtual BAN::ErrorOr sendmsg_impl(const msghdr& message, int flags) override; virtual BAN::ErrorOr getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); } + virtual BAN::ErrorOr getsockopt_impl(int, int, void*, socklen_t*) override; virtual BAN::ErrorOr ioctl_impl(int, void*) override; diff --git a/kernel/include/kernel/Networking/UNIX/Socket.h b/kernel/include/kernel/Networking/UNIX/Socket.h index 926f8074..efd97c2c 100644 --- a/kernel/include/kernel/Networking/UNIX/Socket.h +++ b/kernel/include/kernel/Networking/UNIX/Socket.h @@ -32,6 +32,8 @@ namespace Kernel virtual BAN::ErrorOr recvmsg_impl(msghdr& message, int flags) override; virtual BAN::ErrorOr sendmsg_impl(const msghdr& message, int flags) override; virtual BAN::ErrorOr getpeername_impl(sockaddr*, socklen_t*) override; + virtual BAN::ErrorOr getsockopt_impl(int, int, void*, socklen_t*) override; + virtual BAN::ErrorOr setsockopt_impl(int, int, const void*, socklen_t) override; virtual bool can_read_impl() const override; virtual bool can_write_impl() const override; diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp index db197901..06119d06 100644 --- a/kernel/kernel/FS/Inode.cpp +++ b/kernel/kernel/FS/Inode.cpp @@ -222,6 +222,22 @@ namespace Kernel return getpeername_impl(address, address_len); } + BAN::ErrorOr Inode::getsockopt(int level, int option, void* value, socklen_t* value_len) + { + LockGuard _(m_mutex); + if (!mode().ifsock()) + return BAN::Error::from_errno(ENOTSOCK); + return getsockopt_impl(level, option, value, value_len); + } + + BAN::ErrorOr Inode::setsockopt(int level, int option, const void* value, socklen_t value_len) + { + LockGuard _(m_mutex); + if (!mode().ifsock()) + return BAN::Error::from_errno(ENOTSOCK); + return setsockopt_impl(level, option, value, value_len); + } + BAN::ErrorOr Inode::read(off_t offset, BAN::ByteSpan buffer) { LockGuard _(m_mutex); diff --git a/kernel/kernel/Networking/TCPSocket.cpp b/kernel/kernel/Networking/TCPSocket.cpp index ae11e71d..0a81522a 100644 --- a/kernel/kernel/Networking/TCPSocket.cpp +++ b/kernel/kernel/Networking/TCPSocket.cpp @@ -297,6 +297,34 @@ namespace Kernel return {}; } + BAN::ErrorOr TCPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) + { + if (level != SOL_SOCKET) + return BAN::Error::from_errno(EINVAL); + + int result; + switch (option) + { + case SO_ERROR: + result = 0; + break; + case SO_SNDBUF: + result = m_send_window.scaled_size(); + break; + case SO_RCVBUF: + result = m_recv_window.buffer->size(); + break; + default: + return BAN::Error::from_errno(ENOTSUP); + } + + const size_t len = BAN::Math::min(sizeof(result), *value_len); + memcpy(value, &result, len); + *value_len = sizeof(int); + + return {}; + } + BAN::ErrorOr TCPSocket::ioctl_impl(int request, void* argument) { switch (request) diff --git a/kernel/kernel/Networking/UDPSocket.cpp b/kernel/kernel/Networking/UDPSocket.cpp index c1795502..9d452fa8 100644 --- a/kernel/kernel/Networking/UDPSocket.cpp +++ b/kernel/kernel/Networking/UDPSocket.cpp @@ -213,6 +213,34 @@ namespace Kernel return TRY(m_network_layer.sendto(*this, buffer.span(), address, address_len)); } + BAN::ErrorOr UDPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) + { + if (level != SOL_SOCKET) + return BAN::Error::from_errno(EINVAL); + + int result; + switch (option) + { + case SO_ERROR: + result = 0; + break; + case SO_SNDBUF: + result = m_packet_buffer->size(); + break; + case SO_RCVBUF: + result = m_packet_buffer->size(); + break; + default: + return BAN::Error::from_errno(ENOTSUP); + } + + const size_t len = BAN::Math::min(sizeof(result), *value_len); + memcpy(value, &result, len); + *value_len = sizeof(int); + + return {}; + } + BAN::ErrorOr UDPSocket::ioctl_impl(int request, void* argument) { switch (request) diff --git a/kernel/kernel/Networking/UNIX/Socket.cpp b/kernel/kernel/Networking/UNIX/Socket.cpp index b811beb8..ae492498 100644 --- a/kernel/kernel/Networking/UNIX/Socket.cpp +++ b/kernel/kernel/Networking/UNIX/Socket.cpp @@ -678,4 +678,33 @@ namespace Kernel return {}; } + BAN::ErrorOr UnixDomainSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) + { + if (level != SOL_SOCKET) + return BAN::Error::from_errno(EINVAL); + + int result; + switch (option) + { + case SO_ERROR: + result = 0; + break; + case SO_SNDBUF: + result = m_packet_buffer->size(); + break; + case SO_RCVBUF: + result = m_packet_buffer->size(); + break; + default: + dwarnln("getsockopt(SOL_SOCKET, {})", option); + return BAN::Error::from_errno(ENOTSUP); + } + + const size_t len = BAN::Math::min(sizeof(result), *value_len); + memcpy(value, &result, len); + *value_len = sizeof(int); + + return {}; + } + } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index bc283369..0535c3ec 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1674,20 +1674,13 @@ namespace Kernel if (!inode->mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); - switch (option_name) - { - case SO_ERROR: - { - option_len = BAN::Math::min(option_len, sizeof(int)); - const int zero { 0 }; - TRY(write_to_user(user_option_value, &zero, option_len)); - TRY(write_to_user(user_option_len, &option_len, sizeof(socklen_t))); - return 0; - } - } + auto* buffer = TRY(validate_and_pin_pointer_access(user_option_value, option_len, true)); + BAN::ScopeGuard _([buffer] { buffer->unpin(); }); - dwarnln("getsockopt(SOL_SOCKET, {})", option_name); - return BAN::Error::from_errno(ENOTSUP); + TRY(inode->getsockopt(level, option_name, user_option_value, &option_len)); + TRY(write_to_user(user_option_len, &option_len, sizeof(socklen_t))); + + return 0; } BAN::ErrorOr Process::sys_setsockopt(int socket, int level, int option_name, const void* user_option_value, socklen_t option_len) @@ -1705,10 +1698,12 @@ namespace Kernel if (!inode->mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); - (void)user_option_value; + auto* buffer = TRY(validate_and_pin_pointer_access(user_option_value, option_len, false)); + BAN::ScopeGuard _([buffer] { buffer->unpin(); }); - dwarnln("setsockopt(SOL_SOCKET, {})", option_name); - return BAN::Error::from_errno(ENOTSUP); + TRY(inode->setsockopt(level, option_name, user_option_value, option_len)); + + return 0; } BAN::ErrorOr Process::sys_accept(int socket, sockaddr* address, socklen_t* address_len, int flags)