forked from Bananymous/banan-os
Kernel/LibC: Implement SYS_SENDTO
This commit is contained in:
parent
acd6c86f98
commit
ec2f21bb9f
|
@ -51,6 +51,7 @@ set(KERNEL_SOURCES
|
|||
kernel/Memory/VirtualRange.cpp
|
||||
kernel/Networking/E1000/E1000.cpp
|
||||
kernel/Networking/E1000/E1000E.cpp
|
||||
kernel/Networking/IPv4.cpp
|
||||
kernel/Networking/NetworkInterface.cpp
|
||||
kernel/Networking/NetworkManager.cpp
|
||||
kernel/Networking/NetworkSocket.cpp
|
||||
|
|
|
@ -101,6 +101,7 @@ namespace Kernel
|
|||
|
||||
// Socket API
|
||||
BAN::ErrorOr<void> bind(const sockaddr* address, socklen_t address_len);
|
||||
BAN::ErrorOr<ssize_t> sendto(const sys_sendto_t*);
|
||||
|
||||
// General API
|
||||
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
|
||||
|
@ -125,6 +126,7 @@ namespace Kernel
|
|||
|
||||
// Socket API
|
||||
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<ssize_t> sendto_impl(const sys_sendto_t*) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
||||
// General API
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<void> add_ipv4_header(BAN::Vector<uint8_t>&, uint32_t src_ipv4, uint32_t dst_ipv4, uint8_t protocol);
|
||||
|
||||
}
|
|
@ -20,14 +20,16 @@ namespace Kernel
|
|||
virtual ~NetworkInterface() {}
|
||||
|
||||
virtual uint8_t* get_mac_address() = 0;
|
||||
uint32_t get_ipv4_address() const { return m_ipv4_address; }
|
||||
|
||||
virtual bool link_up() = 0;
|
||||
virtual int link_speed() = 0;
|
||||
|
||||
BAN::ErrorOr<void> add_interface_header(BAN::Vector<uint8_t>&, uint8_t destination_mac[6]);
|
||||
|
||||
virtual dev_t rdev() const override { return m_rdev; }
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) = 0;
|
||||
|
||||
private:
|
||||
|
|
|
@ -9,20 +9,27 @@ namespace Kernel
|
|||
|
||||
class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t PORT_NONE = 0;
|
||||
|
||||
public:
|
||||
void bind_interface_and_port(NetworkInterface*, uint16_t port);
|
||||
~NetworkSocket();
|
||||
|
||||
virtual BAN::ErrorOr<void> add_protocol_header(BAN::Vector<uint8_t>&, uint16_t src_port, uint16_t dst_port) = 0;
|
||||
virtual uint8_t protocol() const = 0;
|
||||
|
||||
protected:
|
||||
NetworkSocket(mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
virtual void on_close_impl() override;
|
||||
|
||||
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
|
||||
virtual BAN::ErrorOr<ssize_t> sendto_impl(const sys_sendto_t*) override;
|
||||
|
||||
protected:
|
||||
NetworkInterface* m_interface = nullptr;
|
||||
uint16_t m_port = 0;
|
||||
NetworkInterface* m_interface = nullptr;
|
||||
uint16_t m_port = PORT_NONE;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,18 +11,13 @@ namespace Kernel
|
|||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(mode_t, uid_t, gid_t);
|
||||
|
||||
void bind_interface(NetworkInterface*);
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
virtual BAN::ErrorOr<void> add_protocol_header(BAN::Vector<uint8_t>&, uint16_t src_port, uint16_t dst_port) override;
|
||||
virtual uint8_t protocol() const override { return 0x11; }
|
||||
|
||||
private:
|
||||
UDPSocket(mode_t, uid_t, gid_t);
|
||||
|
||||
private:
|
||||
NetworkInterface* m_interface = nullptr;
|
||||
|
||||
friend class BAN::RefPtr<UDPSocket>;
|
||||
};
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
|
||||
BAN::ErrorOr<long> sys_bind(int socket, const sockaddr* address, socklen_t address_len);
|
||||
BAN::ErrorOr<long> sys_sendto(const sys_sendto_t*);
|
||||
|
||||
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
|
||||
BAN::ErrorOr<long> sys_dup(int fildes);
|
||||
|
|
|
@ -124,6 +124,14 @@ namespace Kernel
|
|||
return bind_impl(address, address_len);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<ssize_t> Inode::sendto(const sys_sendto_t* arguments)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
if (!mode().ifsock())
|
||||
return BAN::Error::from_errno(ENOTSOCK);
|
||||
return sendto_impl(arguments);
|
||||
};
|
||||
|
||||
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
#include <BAN/Endianness.h>
|
||||
#include <kernel/Networking/IPv4.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
||||
struct IPv4Header
|
||||
{
|
||||
uint8_t version_IHL;
|
||||
uint8_t DSCP_ECN;
|
||||
BAN::NetworkEndian<uint16_t> total_length;
|
||||
BAN::NetworkEndian<uint16_t> identification;
|
||||
BAN::NetworkEndian<uint16_t> flags_frament;
|
||||
uint8_t time_to_live;
|
||||
uint8_t protocol;
|
||||
BAN::NetworkEndian<uint16_t> header_checksum;
|
||||
BAN::NetworkEndian<uint32_t> src_address;
|
||||
BAN::NetworkEndian<uint32_t> dst_address;
|
||||
|
||||
uint16_t checksum() const
|
||||
{
|
||||
return 0xFFFF
|
||||
- (((uint16_t)version_IHL << 8) | DSCP_ECN)
|
||||
- total_length
|
||||
- identification
|
||||
- flags_frament
|
||||
- (((uint16_t)time_to_live << 8) | protocol);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(IPv4Header) == 20);
|
||||
|
||||
BAN::ErrorOr<void> add_ipv4_header(BAN::Vector<uint8_t>& packet, uint32_t src_ipv4, uint32_t dst_ipv4, uint8_t protocol)
|
||||
{
|
||||
TRY(packet.resize(packet.size() + sizeof(IPv4Header)));
|
||||
memmove(packet.data() + sizeof(IPv4Header), packet.data(), packet.size() - sizeof(IPv4Header));
|
||||
|
||||
auto* header = reinterpret_cast<IPv4Header*>(packet.data());
|
||||
header->version_IHL = 0x45;
|
||||
header->DSCP_ECN = 0x10;
|
||||
header->total_length = packet.size();
|
||||
header->identification = 1;
|
||||
header->flags_frament = 0x00;
|
||||
header->time_to_live = 0x40;
|
||||
header->protocol = protocol;
|
||||
header->header_checksum = header->checksum();
|
||||
header->src_address = src_ipv4;
|
||||
header->dst_address = dst_ipv4;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
#include <BAN/Endianness.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
|
||||
|
@ -7,6 +8,14 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
struct EthernetHeader
|
||||
{
|
||||
uint8_t dst_mac[6];
|
||||
uint8_t src_mac[6];
|
||||
BAN::NetworkEndian<uint16_t> ether_type;
|
||||
};
|
||||
static_assert(sizeof(EthernetHeader) == 14);
|
||||
|
||||
static dev_t get_network_rdev_major()
|
||||
{
|
||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||
|
@ -31,4 +40,19 @@ namespace Kernel
|
|||
m_name[3] = minor(m_rdev) + '0';
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> NetworkInterface::add_interface_header(BAN::Vector<uint8_t>& packet, uint8_t destination_mac[6])
|
||||
{
|
||||
ASSERT(m_type == Type::Ethernet);
|
||||
|
||||
TRY(packet.resize(packet.size() + sizeof(EthernetHeader)));
|
||||
memmove(packet.data() + sizeof(EthernetHeader), packet.data(), packet.size() - sizeof(EthernetHeader));
|
||||
|
||||
auto* header = reinterpret_cast<EthernetHeader*>(packet.data());
|
||||
memcpy(header->dst_mac, destination_mac, 6);
|
||||
memcpy(header->src_mac, get_mac_address(), 6);
|
||||
header->ether_type = 0x0800; // ipv4
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,7 +65,6 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> NetworkManager::create_socket(SocketType type, mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
|
||||
|
@ -92,12 +91,16 @@ namespace Kernel
|
|||
{
|
||||
if (m_interfaces.empty())
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
if (m_bound_sockets.contains(port))
|
||||
return BAN::Error::from_errno(EADDRINUSE);
|
||||
|
||||
if (port != NetworkSocket::PORT_NONE)
|
||||
{
|
||||
if (m_bound_sockets.contains(port))
|
||||
return BAN::Error::from_errno(EADDRINUSE);
|
||||
TRY(m_bound_sockets.insert(port, socket));
|
||||
}
|
||||
|
||||
// FIXME: actually determine proper interface
|
||||
auto interface = m_interfaces.front();
|
||||
TRY(m_bound_sockets.insert(port, socket));
|
||||
socket->bind_interface_and_port(interface.ptr(), port);
|
||||
|
||||
return {};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <kernel/Networking/IPv4.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/Networking/NetworkSocket.h>
|
||||
|
||||
|
@ -39,4 +40,43 @@ namespace Kernel
|
|||
return NetworkManager::get().bind_socket(addr_in->sin_port, this);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<ssize_t> NetworkSocket::sendto_impl(const sys_sendto_t* arguments)
|
||||
{
|
||||
if (arguments->dest_len != sizeof(sockaddr_in))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (arguments->flags)
|
||||
{
|
||||
dprintln("flags not supported");
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
if (!m_interface)
|
||||
TRY(NetworkManager::get().bind_socket(PORT_NONE, this));
|
||||
|
||||
auto* destination = reinterpret_cast<const sockaddr_in*>(arguments->dest_addr);
|
||||
auto message = BAN::ConstByteSpan((const uint8_t*)arguments->message, arguments->length);
|
||||
|
||||
if (destination->sin_port == PORT_NONE)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
if (destination->sin_addr.s_addr != 0xFFFFFFFF)
|
||||
{
|
||||
dprintln("Only broadcast ip supported");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
static uint8_t dest_mac[6] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
BAN::Vector<uint8_t> full_packet;
|
||||
TRY(full_packet.resize(message.size()));
|
||||
memcpy(full_packet.data(), message.data(), message.size());
|
||||
TRY(add_protocol_header(full_packet, m_port, destination->sin_port));
|
||||
TRY(add_ipv4_header(full_packet, m_interface->get_ipv4_address(), destination->sin_addr.s_addr, protocol()));
|
||||
TRY(m_interface->add_interface_header(full_packet, dest_mac));
|
||||
|
||||
TRY(m_interface->send_raw_bytes(BAN::ConstByteSpan { full_packet.span() }));
|
||||
|
||||
return arguments->length;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
#include <BAN/Endianness.h>
|
||||
#include <kernel/Networking/UDPSocket.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
struct UDPHeader
|
||||
{
|
||||
BAN::NetworkEndian<uint16_t> src_port;
|
||||
BAN::NetworkEndian<uint16_t> dst_port;
|
||||
BAN::NetworkEndian<uint16_t> length;
|
||||
BAN::NetworkEndian<uint16_t> checksum;
|
||||
};
|
||||
static_assert(sizeof(UDPHeader) == 8);
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<UDPSocket>> UDPSocket::create(mode_t mode, uid_t uid, gid_t gid)
|
||||
{
|
||||
return TRY(BAN::RefPtr<UDPSocket>::create(mode, uid, gid));
|
||||
|
@ -12,14 +22,18 @@ namespace Kernel
|
|||
: NetworkSocket(mode, uid, gid)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<size_t> UDPSocket::read_impl(off_t, BAN::ByteSpan)
|
||||
BAN::ErrorOr<void> UDPSocket::add_protocol_header(BAN::Vector<uint8_t>& packet, uint16_t src_port, uint16_t dst_port)
|
||||
{
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
TRY(packet.resize(packet.size() + sizeof(UDPHeader)));
|
||||
memmove(packet.data() + sizeof(UDPHeader), packet.data(), packet.size() - sizeof(UDPHeader));
|
||||
|
||||
BAN::ErrorOr<size_t> UDPSocket::write_impl(off_t, BAN::ConstByteSpan)
|
||||
{
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
auto* header = reinterpret_cast<UDPHeader*>(packet.data());
|
||||
header->src_port = src_port;
|
||||
header->dst_port = dst_port;
|
||||
header->length = packet.size();
|
||||
header->checksum = 0;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -915,6 +915,21 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_sendto(const sys_sendto_t* arguments)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
TRY(validate_pointer_access(arguments, sizeof(sys_sendto_t)));
|
||||
TRY(validate_pointer_access(arguments->message, arguments->length));
|
||||
TRY(validate_pointer_access(arguments->dest_addr, arguments->dest_len));
|
||||
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(arguments->socket));
|
||||
if (!inode->mode().ifsock())
|
||||
return BAN::Error::from_errno(ENOTSOCK);
|
||||
|
||||
return TRY(inode->sendto(arguments));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
|
|
@ -219,6 +219,9 @@ namespace Kernel
|
|||
case SYS_BIND:
|
||||
ret = Process::current().sys_bind((int)arg1, (const sockaddr*)arg2, (socklen_t)arg3);
|
||||
break;
|
||||
case SYS_SENDTO:
|
||||
ret = Process::current().sys_sendto((const sys_sendto_t*)arg1);
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unknown syscall {}", syscall);
|
||||
break;
|
||||
|
|
|
@ -105,6 +105,16 @@ struct linger
|
|||
#define SHUT_WR 0x02
|
||||
#define SHUT_RDWR (SHUT_RD | SHUT_WR)
|
||||
|
||||
struct sys_sendto_t
|
||||
{
|
||||
int socket;
|
||||
const void* message;
|
||||
size_t length;
|
||||
int flags;
|
||||
const struct sockaddr* dest_addr;
|
||||
socklen_t dest_len;
|
||||
};
|
||||
|
||||
int accept(int socket, struct sockaddr* __restrict address, socklen_t* __restrict address_len);
|
||||
int bind(int socket, const struct sockaddr* address, socklen_t address_len);
|
||||
int connect(int socket, const struct sockaddr* address, socklen_t address_len);
|
||||
|
|
|
@ -65,6 +65,7 @@ __BEGIN_DECLS
|
|||
#define SYS_LOAD_KEYMAP 64
|
||||
#define SYS_SOCKET 65
|
||||
#define SYS_BIND 66
|
||||
#define SYS_SENDTO 67
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -7,6 +7,19 @@ int bind(int socket, const struct sockaddr* address, socklen_t address_len)
|
|||
return syscall(SYS_BIND, socket, address, address_len);
|
||||
}
|
||||
|
||||
ssize_t sendto(int socket, const void* message, size_t length, int flags, const struct sockaddr* dest_addr, socklen_t dest_len)
|
||||
{
|
||||
sys_sendto_t arguments {
|
||||
.socket = socket,
|
||||
.message = message,
|
||||
.length = length,
|
||||
.flags = flags,
|
||||
.dest_addr = dest_addr,
|
||||
.dest_len = dest_len
|
||||
};
|
||||
return syscall(SYS_SENDTO, &arguments);
|
||||
}
|
||||
|
||||
int socket(int domain, int type, int protocol)
|
||||
{
|
||||
return syscall(SYS_SOCKET, domain, type, protocol);
|
||||
|
|
Loading…
Reference in New Issue