Skip to content

Commit

Permalink
Kernel/libc: getifaddrs, set/getsockopt
Browse files Browse the repository at this point in the history
  • Loading branch information
byteduck committed Mar 16, 2024
1 parent 85dcbb8 commit 1bde068
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 10 deletions.
23 changes: 23 additions & 0 deletions kernel/api/ifaddrs.h
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#pragma once
#include "types.h"
#include "socket.h"

__DECL_BEGIN

struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
union {
struct sockaddr *ifu_broadaddr;
struct sockaddr *ifu_dstaddr;
} ifa_ifu;
void *ifa_data;
};

__DECL_END
5 changes: 3 additions & 2 deletions kernel/api/in.h
Expand Up @@ -23,7 +23,8 @@ struct sockaddr_in {
# define INADDR_ANY ((uint32_t) 0x00000000)
# define INADDR_NONE 0xffffffff
# define INPORT_ANY 0
#define IPPROTO_TCP 0
#define IPPROTO_UDP 0
#define IPPROTO_IP 1
#define IPPROTO_TCP 2
#define IPPROTO_UDP 3

__DECL_END
6 changes: 6 additions & 0 deletions kernel/api/socket.h
Expand Up @@ -21,6 +21,12 @@ __DECL_BEGIN
#define SOCK_DGRAM 2
#define SOCK_RAW 3

// sockopt
#define SOL_SOCKET 0
#define SO_BINDTODEVICE 1
#define SO_BROADCAST 2
#define SO_ERROR 3

typedef uint16_t sa_family_t;
typedef uint32_t socklen_t;

Expand Down
4 changes: 2 additions & 2 deletions kernel/memory/SafePointer.h
Expand Up @@ -160,8 +160,8 @@ class SafePointer {
}

private:
T* const m_ptr = nullptr;
const bool m_is_user = false;
T* m_ptr = nullptr;
bool m_is_user = false;
};

template<typename T>
Expand Down
1 change: 0 additions & 1 deletion kernel/net/IPSocket.h
Expand Up @@ -39,7 +39,6 @@ class IPSocket: public Socket {
IPv4Address m_bound_addr, m_dest_addr;
kstd::circular_queue<RecvdPacket*> m_receive_queue { 16 };
Mutex m_receive_queue_lock { "IPSocket::receive_queue" };
Mutex m_lock { "IPSocket::lock" };
BooleanBlocker m_receive_blocker;
uint8_t m_type_of_service = 0;
uint8_t m_ttl = 64;
Expand Down
2 changes: 1 addition & 1 deletion kernel/net/NetworkAdapter.cpp
Expand Up @@ -38,7 +38,7 @@ ResultRet<kstd::Arc<NetworkAdapter>> NetworkAdapter::get_interface(const kstd::s
if (interface->name() == name)
return interface;
}
return Result(ENOENT);
return Result(ENODEV);
}

void NetworkAdapter::register_interface(kstd::Arc<NetworkAdapter> adapter) {
Expand Down
49 changes: 49 additions & 0 deletions kernel/net/Socket.cpp
Expand Up @@ -22,3 +22,52 @@ ResultRet<kstd::Arc<Socket>> Socket::make(Socket::Domain domain, Socket::Type ty
ssize_t Socket::read(FileDescriptor& fd, size_t offset, SafePointer<uint8_t> buffer, size_t count) {
return recvfrom(fd, buffer, count, 0, {}, {});
}

Result Socket::setsockopt(int level, int optname, UserspacePointer<void*> optval, socklen_t optlen) {
if (level != SOL_SOCKET)
return Result(EINVAL);

LOCK(m_lock);

switch (optname) {
case SO_BINDTODEVICE:
if (optlen < IFNAMESIZ)
return Result(EINVAL);
m_bound_device = TRY(NetworkAdapter::get_interface(optval.str()));
return Result(SUCCESS);

case SO_BROADCAST:
if (optlen < sizeof(int))
return Result(EINVAL);
m_allow_broadcast = optval.as<int>().get();
return Result(SUCCESS);

default:
return Result(EINVAL);
}
}


Result Socket::getsockopt(int level, int optname, UserspacePointer<void*> optval, UserspacePointer<socklen_t> optlen) {
if (level != SOL_SOCKET)
return Result(EINVAL);

LOCK(m_lock);

switch (optname) {
case SO_BROADCAST:
if (optlen.get() < sizeof(int))
return Result(EINVAL);
optval.as<int>().set(m_allow_broadcast);
optlen.set(sizeof(int));
return Result(SUCCESS);

case SO_ERROR:
optval.as<int>().set(m_error);
optlen.set(sizeof(int));
return Result(SUCCESS);

default:
return Result(EINVAL);
}
}
6 changes: 6 additions & 0 deletions kernel/net/Socket.h
Expand Up @@ -5,6 +5,7 @@

#include "../filesystem/File.h"
#include "../api/socket.h"
#include "NetworkAdapter.h"

class Socket: public File {
public:
Expand All @@ -28,6 +29,8 @@ class Socket: public File {
virtual ssize_t recvfrom(FileDescriptor& fd, SafePointer<uint8_t> buf, size_t len, int flags, SafePointer<sockaddr> src_addr, SafePointer<socklen_t> addrlen) = 0;
virtual ssize_t sendto(FileDescriptor& fd, SafePointer<uint8_t> buf, size_t len, int flags, SafePointer<sockaddr> dest_addr, socklen_t addrlen) = 0;
virtual Result recv_packet(const void* buf, size_t len) = 0;
virtual Result setsockopt(int level, int optname, UserspacePointer<void*> optval, socklen_t optlen);
virtual Result getsockopt(int level, int optname, UserspacePointer<void*> optval, UserspacePointer<socklen_t> optlen);

[[nodiscard]] int error() const { return m_error; }

Expand All @@ -45,4 +48,7 @@ class Socket: public File {
const Domain m_domain;
const Type m_type;
const int m_protocol;
kstd::Arc<NetworkAdapter> m_bound_device;
Mutex m_lock { "Socket::lock" };
bool m_allow_broadcast = false;
};
2 changes: 1 addition & 1 deletion kernel/net/UDPSocket.cpp
Expand Up @@ -85,7 +85,7 @@ ssize_t UDPSocket::do_recv(RecvdPacket* pkt, SafePointer<uint8_t> buf, size_t le
}

ResultRet<size_t> UDPSocket::do_send(SafePointer<uint8_t> buf, size_t len) {
auto route = Router::get_route(m_dest_addr, {}, {});
auto route = Router::get_route(m_dest_addr, m_bound_addr, m_bound_device);
if (!route.mac || !route.adapter)
return Result(set_error(EHOSTUNREACH));

Expand Down
79 changes: 77 additions & 2 deletions kernel/syscall/socket.cpp
Expand Up @@ -5,6 +5,9 @@
#include "../memory/SafePointer.h"
#include "../net/Socket.h"
#include "../filesystem/FileDescriptor.h"
#include "../net/NetworkAdapter.h"
#include "../api/ifaddrs.h"
#include "syscall_numbers.h"

int Process::sys_socket(int domain, int type, int protocol) {
auto socket_res = Socket::make((Socket::Domain) domain, (Socket::Type) type, protocol);
Expand Down Expand Up @@ -36,11 +39,17 @@ int Process::sys_bind(int sockfd, UserspacePointer<sockaddr> addr, uint32_t addr
}

int Process::sys_setsockopt(UserspacePointer<struct setsockopt_args> ptr) {
return -1;
auto args = ptr.get();
get_socket(args.sockfd);
auto res = socket->setsockopt(args.level, args.option_name, (void**) args.option_value, args.option_len);
return res.code();
}

int Process::sys_getsockopt(UserspacePointer<struct getsockopt_args> ptr) {
return -1;
auto args = ptr.get();
get_socket(args.sockfd);
auto res = socket->getsockopt(args.level, args.option_name, (void**) args.option_value, args.option_len);
return res.code();
}

int Process::sys_recvmsg(int sockfd, UserspacePointer<struct msghdr> msg_ptr, int flags) {
Expand Down Expand Up @@ -80,4 +89,70 @@ int Process::sys_sendmsg(int sockfd, UserspacePointer<struct msghdr> msg_ptr, in
UserspacePointer(&msg_ptr.raw()->msg_controllen).set(0);

return socket->sendto(*desc, buf, iov.iov_len, flags, addr_ptr, addrlen_ptr.get());
}

template<typename T>
T* writebuf(SafePointer<uint8_t>& buf, const T& val) {
buf.write((const uint8_t*) &val, 0, sizeof(val));
auto ret = buf.raw();
buf = UserspacePointer(buf.raw() + sizeof(val));
return (T*) ret;
}

char* writebuf(SafePointer<uint8_t>& buf, const kstd::string& val) {
buf.write((const uint8_t*) val.c_str(), 0, val.length() + 1);
auto ret = buf.raw();
buf = UserspacePointer(buf.raw() + val.length() + 1);
return (char*) ret;
}

int Process::sys_getifaddrs(UserspacePointer<struct ifaddrs> buf, size_t bufsz) {
auto ifaces = NetworkAdapter::interfaces();

// Makes sure the provided buffer is large enough
size_t memsz = (sizeof(struct ifaddrs) + sizeof(sockaddr) * 2) * ifaces.size();
for (auto& iface : ifaces)
memsz += iface->name().length() + 1;
if (bufsz < memsz)
return -EOVERFLOW;

// Fill in the data
auto u8buf = buf.as<uint8_t>();
struct ifaddrs* prev = nullptr;
for (auto& iface : ifaces) {
// First, reserve space for the actual struct
auto* addrs_ptr = writebuf<struct ifaddrs>(u8buf, {});
struct ifaddrs addrs;

// First, the name and addresses
addrs.ifa_name = writebuf(u8buf, iface->name());

auto addr = iface->ipv4_address();
addrs.ifa_addr = writebuf<struct sockaddr>(u8buf, {
.sa_family = AF_INET,
.sa_data = {(char) addr[0], (char) addr[1], (char) addr[2], (char) addr[3]}
});

auto netmask = iface->netmask();
addrs.ifa_netmask = writebuf<struct sockaddr>(u8buf, {
.sa_family = AF_INET,
.sa_data = {(char) netmask[0], (char) netmask[1], (char) netmask[2], (char) netmask[3]}
});

// Then, fill out the rest of the struct and write it
addrs.ifa_flags = 0;
addrs.ifa_next = nullptr;
addrs.ifa_data = nullptr;
addrs.ifa_ifu.ifu_broadaddr = nullptr;
UserspacePointer(addrs_ptr).set(addrs);

// Write ifa_next for previous one
if (prev)
UserspacePointer(&prev->ifa_next).set(addrs_ptr);

prev = addrs_ptr;
}

// Return success
return SUCCESS;
}
2 changes: 2 additions & 0 deletions kernel/syscall/syscall.cpp
Expand Up @@ -194,6 +194,8 @@ int handle_syscall(ThreadRegisters& regs, uint32_t call, uint32_t arg1, uint32_t
return cur_proc->sys_sendmsg(arg1, (struct msghdr*) arg2, arg3);
case SYS_RECVMSG:
return cur_proc->sys_recvmsg(arg1, (struct msghdr*) arg2, arg3);
case SYS_GETIFADDRS:
return cur_proc->sys_getifaddrs((struct ifaddrs*) arg1, (size_t) arg2);

//TODO: Implement these syscalls
case SYS_TIMES:
Expand Down
1 change: 1 addition & 0 deletions kernel/syscall/syscall_numbers.h
Expand Up @@ -85,6 +85,7 @@
#define SYS_GETSOCKOPT 82
#define SYS_RECVMSG 83
#define SYS_SENDMSG 84
#define SYS_GETIFADDRS 85

#ifndef DUCKOS_KERNEL
#include <sys/types.h>
Expand Down
1 change: 1 addition & 0 deletions kernel/tasking/Process.h
Expand Up @@ -173,6 +173,7 @@ class Process {
int sys_getsockopt(UserspacePointer<struct getsockopt_args> ptr);
int sys_recvmsg(int sockfd, UserspacePointer<struct msghdr> msg, int flags);
int sys_sendmsg(int sockfd, UserspacePointer<struct msghdr> msg, int flags);
int sys_getifaddrs(UserspacePointer<struct ifaddrs> buf, size_t memsz);

private:
friend class Thread;
Expand Down
2 changes: 1 addition & 1 deletion kernel/tasking/Thread.cpp
Expand Up @@ -516,7 +516,7 @@ void Thread::handle_pagefault(PageFault fault) {
if(fault.registers->interrupt_frame.eip > HIGHER_HALF) {
PANIC("SYSCALL_PAGEFAULT", "A page fault occurred in the kernel (pid: %d, tid: %d, ptr: 0x%x, ip: 0x%x).", _process->pid(), _tid, fault.address, fault.registers->interrupt_frame.eip);
}
KLog::warn("Thread", "PID {} thread {} made illegal memory access at {#x} (eip: {#x}})", _process->pid(), _tid,
KLog::warn("Thread", "PID {} thread {} made illegal memory access at {#x} (eip: {#x})", _process->pid(), _tid,
fault.address, fault.registers->interrupt_frame.eip);
_process->kill(SIGSEGV);
}
Expand Down
1 change: 1 addition & 0 deletions libraries/libc/CMakeLists.txt
Expand Up @@ -8,6 +8,7 @@ SET(SOURCES
dlfcn.cpp
errno.c
fcntl.c
ifaddrs.c
locale.c
poll.c
signal.c
Expand Down
33 changes: 33 additions & 0 deletions libraries/libc/ifaddrs.c
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#include "ifaddrs.h"
#include "sys/syscall.h"
#include "stdlib.h"
#include "errno.h"

int getifaddrs(struct ifaddrs **ifap) {
size_t alloc_size = 128; // Start with a reasonable size
struct ifaddrs* ptr = NULL;
int res;
do {
alloc_size *= 2;
if (ptr)
free(ptr);
ptr = malloc(alloc_size);
res = syscall3_noerr(SYS_GETIFADDRS, (int) ptr, (int) alloc_size);
} while(res == -EOVERFLOW && alloc_size < 4096);

if (!res) {
*ifap = ptr;
return 0;
} else {
free(ptr);
errno = -res;
return -1;
}
}

void freeifaddrs(struct ifaddrs *ifa) {
free(ifa);
}
12 changes: 12 additions & 0 deletions libraries/libc/ifaddrs.h
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright © 2016-2024 Byteduck */

#pragma once
#include <kernel/api/ifaddrs.h>

__DECL_BEGIN

int getifaddrs(struct ifaddrs **ifap);
void freeifaddrs(struct ifaddrs *ifa);

__DECL_END

0 comments on commit 1bde068

Please sign in to comment.