Kernel/LibC: Implement SYS_SENDTO

This commit is contained in:
2024-02-02 03:16:01 +02:00
parent acd6c86f98
commit ec2f21bb9f
18 changed files with 222 additions and 20 deletions

View File

@@ -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 {};
}
}

View File

@@ -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 {};
}
}

View File

@@ -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 {};

View File

@@ -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;
}
}

View File

@@ -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 {};
}
}