Kernel: Implement basic recvfrom
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <kernel/Memory/PageTable.h>
|
||||
#include <kernel/MMIO.h>
|
||||
#include <kernel/Networking/E1000/E1000.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
|
||||
#define DEBUG_E1000 1
|
||||
|
||||
@@ -69,14 +70,7 @@ namespace Kernel
|
||||
TRY(read_mac_address());
|
||||
#if DEBUG_E1000
|
||||
dprintln("E1000 at PCI {}:{}.{}", m_pci_device.bus(), m_pci_device.dev(), m_pci_device.func());
|
||||
dprintln(" MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}",
|
||||
m_mac_address[0],
|
||||
m_mac_address[1],
|
||||
m_mac_address[2],
|
||||
m_mac_address[3],
|
||||
m_mac_address[4],
|
||||
m_mac_address[5]
|
||||
);
|
||||
dprintln(" MAC: {}", m_mac_address);
|
||||
#endif
|
||||
|
||||
TRY(initialize_rx());
|
||||
@@ -141,16 +135,16 @@ namespace Kernel
|
||||
if (m_has_eerprom)
|
||||
{
|
||||
uint32_t temp = eeprom_read(0);
|
||||
m_mac_address[0] = temp;
|
||||
m_mac_address[1] = temp >> 8;
|
||||
m_mac_address.address[0] = temp;
|
||||
m_mac_address.address[1] = temp >> 8;
|
||||
|
||||
temp = eeprom_read(1);
|
||||
m_mac_address[2] = temp;
|
||||
m_mac_address[3] = temp >> 8;
|
||||
m_mac_address.address[2] = temp;
|
||||
m_mac_address.address[3] = temp >> 8;
|
||||
|
||||
temp = eeprom_read(2);
|
||||
m_mac_address[4] = temp;
|
||||
m_mac_address[5] = temp >> 8;
|
||||
m_mac_address.address[4] = temp;
|
||||
m_mac_address.address[5] = temp >> 8;
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -162,7 +156,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8);
|
||||
m_mac_address.address[i] = (uint8_t)read32(0x5400 + i * 8);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -175,7 +169,6 @@ namespace Kernel
|
||||
auto* rx_descriptors = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr());
|
||||
for (size_t i = 0; i < E1000_RX_DESCRIPTOR_COUNT; i++)
|
||||
{
|
||||
m_rx_buffers[i] = reinterpret_cast<void*>(m_rx_buffer_region->vaddr() + E1000_RX_BUFFER_SIZE * i);
|
||||
rx_descriptors[i].addr = m_rx_buffer_region->paddr() + E1000_RX_BUFFER_SIZE * i;
|
||||
rx_descriptors[i].status = 0;
|
||||
}
|
||||
@@ -209,7 +202,6 @@ namespace Kernel
|
||||
auto* tx_descriptors = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr());
|
||||
for (size_t i = 0; i < E1000_TX_DESCRIPTOR_COUNT; i++)
|
||||
{
|
||||
m_tx_buffers[i] = reinterpret_cast<void*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * i);
|
||||
tx_descriptors[i].addr = m_tx_buffer_region->paddr() + E1000_TX_BUFFER_SIZE * i;
|
||||
tx_descriptors[i].cmd = 0;
|
||||
}
|
||||
@@ -300,8 +292,10 @@ namespace Kernel
|
||||
break;
|
||||
ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE);
|
||||
|
||||
// FIXME: do something with the packet :)
|
||||
dprintln("got {} byte packet", (uint16_t)descriptor.length);
|
||||
NetworkManager::get().on_receive(BAN::ConstByteSpan {
|
||||
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
|
||||
descriptor.length
|
||||
});
|
||||
|
||||
descriptor.status = 0;
|
||||
write32(REG_RDT0, rx_current);
|
||||
|
||||
@@ -4,50 +4,19 @@
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
||||
struct IPv4Header
|
||||
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol)
|
||||
{
|
||||
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 {};
|
||||
auto& header = packet.as<IPv4Header>();
|
||||
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.checksum = header.calculate_checksum();
|
||||
header.src_address = src_ipv4;
|
||||
header.dst_address = dst_ipv4;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace Kernel
|
||||
|
||||
struct EthernetHeader
|
||||
{
|
||||
uint8_t dst_mac[6];
|
||||
uint8_t src_mac[6];
|
||||
BAN::MACAddress dst_mac;
|
||||
BAN::MACAddress src_mac;
|
||||
BAN::NetworkEndian<uint16_t> ether_type;
|
||||
};
|
||||
static_assert(sizeof(EthernetHeader) == 14);
|
||||
@@ -40,19 +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])
|
||||
size_t NetworkInterface::interface_header_size() const
|
||||
{
|
||||
ASSERT(m_type == Type::Ethernet);
|
||||
return sizeof(EthernetHeader);
|
||||
}
|
||||
|
||||
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 {};
|
||||
void NetworkInterface::add_interface_header(BAN::ByteSpan packet, BAN::MACAddress destination)
|
||||
{
|
||||
ASSERT(m_type == Type::Ethernet);
|
||||
auto& header = packet.as<EthernetHeader>();
|
||||
header.dst_mac = destination;
|
||||
header.src_mac = get_mac_address();
|
||||
header.ether_type = 0x0800;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include <BAN/Endianness.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/Networking/E1000/E1000.h>
|
||||
#include <kernel/Networking/E1000/E1000E.h>
|
||||
#include <kernel/Networking/IPv4.h>
|
||||
#include <kernel/Networking/NetworkManager.h>
|
||||
#include <kernel/Networking/UDPSocket.h>
|
||||
|
||||
@@ -106,4 +108,27 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
void NetworkManager::on_receive(BAN::ConstByteSpan packet)
|
||||
{
|
||||
// FIXME: properly handle packet parsing
|
||||
|
||||
auto ipv4 = packet.slice(14);
|
||||
auto& ipv4_header = ipv4.as<const IPv4Header>();
|
||||
auto src_ipv4 = ipv4_header.src_address;
|
||||
|
||||
auto udp = ipv4.slice(20);
|
||||
auto& udp_header = udp.as<const UDPHeader>();
|
||||
uint16_t src_port = udp_header.src_port;
|
||||
uint16_t dst_port = udp_header.dst_port;
|
||||
|
||||
if (!m_bound_sockets.contains(dst_port))
|
||||
{
|
||||
dprintln("no one is listening on port {}", dst_port);
|
||||
return;
|
||||
}
|
||||
|
||||
auto raw = udp.slice(8);
|
||||
m_bound_sockets[dst_port].lock()->add_packet(raw, src_ipv4, src_port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,18 +65,62 @@ namespace Kernel
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
static uint8_t dest_mac[6] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
static BAN::MACAddress dest_mac {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
|
||||
|
||||
const size_t interface_header_offset = 0;
|
||||
const size_t interface_header_size = m_interface->interface_header_size();
|
||||
|
||||
const size_t ipv4_header_offset = interface_header_offset + interface_header_size;
|
||||
const size_t ipv4_header_size = sizeof(IPv4Header);
|
||||
|
||||
const size_t protocol_header_offset = ipv4_header_offset + ipv4_header_size;
|
||||
const size_t protocol_header_size = this->protocol_header_size();
|
||||
|
||||
const size_t payload_offset = protocol_header_offset + protocol_header_size;
|
||||
const size_t payload_size = message.size();
|
||||
|
||||
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(full_packet.resize(payload_offset + payload_size));
|
||||
|
||||
TRY(m_interface->send_raw_bytes(BAN::ConstByteSpan { full_packet.span() }));
|
||||
BAN::ByteSpan packet_bytespan { full_packet.span() };
|
||||
|
||||
memcpy(full_packet.data() + payload_offset, message.data(), payload_size);
|
||||
add_protocol_header(packet_bytespan.slice(protocol_header_offset), m_port, destination->sin_port);
|
||||
add_ipv4_header(packet_bytespan.slice(ipv4_header_offset), m_interface->get_ipv4_address(), destination->sin_addr.s_addr, protocol());
|
||||
m_interface->add_interface_header(packet_bytespan.slice(interface_header_offset), dest_mac);
|
||||
TRY(m_interface->send_raw_bytes(packet_bytespan));
|
||||
|
||||
return arguments->length;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<ssize_t> NetworkSocket::recvfrom_impl(sys_recvfrom_t* arguments)
|
||||
{
|
||||
sockaddr_in* sender_addr = nullptr;
|
||||
if (arguments->address)
|
||||
{
|
||||
ASSERT(arguments->address_len);
|
||||
if (*arguments->address_len < (socklen_t)sizeof(sockaddr_in))
|
||||
*arguments->address_len = 0;
|
||||
else
|
||||
{
|
||||
sender_addr = reinterpret_cast<sockaddr_in*>(arguments->address);
|
||||
*arguments->address_len = sizeof(sockaddr_in);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_interface)
|
||||
{
|
||||
dprintln("No interface bound");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (m_port == PORT_NONE)
|
||||
{
|
||||
dprintln("No port bound");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
return TRY(read_packet(BAN::ByteSpan { reinterpret_cast<uint8_t*>(arguments->buffer), arguments->length }, sender_addr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,39 +1,101 @@
|
||||
#include <BAN/Endianness.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
#include <kernel/Networking/UDPSocket.h>
|
||||
#include <kernel/Thread.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));
|
||||
auto socket = TRY(BAN::RefPtr<UDPSocket>::create(mode, uid, gid));
|
||||
socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||
PageTable::kernel(),
|
||||
KERNEL_OFFSET,
|
||||
~(uintptr_t)0,
|
||||
packet_buffer_size,
|
||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||
true
|
||||
));
|
||||
return socket;
|
||||
}
|
||||
|
||||
UDPSocket::UDPSocket(mode_t mode, uid_t uid, gid_t gid)
|
||||
: NetworkSocket(mode, uid, gid)
|
||||
{ }
|
||||
|
||||
BAN::ErrorOr<void> UDPSocket::add_protocol_header(BAN::Vector<uint8_t>& packet, uint16_t src_port, uint16_t dst_port)
|
||||
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port)
|
||||
{
|
||||
TRY(packet.resize(packet.size() + sizeof(UDPHeader)));
|
||||
memmove(packet.data() + sizeof(UDPHeader), packet.data(), packet.size() - sizeof(UDPHeader));
|
||||
auto& header = packet.as<UDPHeader>();
|
||||
header.src_port = src_port;
|
||||
header.dst_port = dst_port;
|
||||
header.length = packet.size();
|
||||
header.checksum = 0;
|
||||
}
|
||||
|
||||
auto* header = reinterpret_cast<UDPHeader*>(packet.data());
|
||||
header->src_port = src_port;
|
||||
header->dst_port = dst_port;
|
||||
header->length = packet.size();
|
||||
header->checksum = 0;
|
||||
void UDPSocket::add_packet(BAN::ConstByteSpan packet, BAN::IPv4Address sender_addr, uint16_t sender_port)
|
||||
{
|
||||
CriticalScope _;
|
||||
|
||||
return {};
|
||||
if (m_packets.full())
|
||||
{
|
||||
dprintln("Packet buffer full, dropping packet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_packets.empty() && m_packet_total_size > m_packet_buffer->size())
|
||||
{
|
||||
dprintln("Packet buffer full, dropping packet");
|
||||
return;
|
||||
}
|
||||
|
||||
void* buffer = reinterpret_cast<void*>(m_packet_buffer->vaddr() + m_packet_total_size);
|
||||
memcpy(buffer, packet.data(), packet.size());
|
||||
|
||||
m_packets.push(PacketInfo {
|
||||
.sender_addr = sender_addr,
|
||||
.sender_port = sender_port,
|
||||
.packet_size = packet.size()
|
||||
});
|
||||
m_packet_total_size += packet.size();
|
||||
|
||||
m_semaphore.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> UDPSocket::read_packet(BAN::ByteSpan buffer, sockaddr_in* sender_addr)
|
||||
{
|
||||
while (m_packets.empty())
|
||||
TRY(Thread::current().block_or_eintr(m_semaphore));
|
||||
|
||||
CriticalScope _;
|
||||
if (m_packets.empty())
|
||||
return read_packet(buffer, sender_addr);
|
||||
|
||||
auto packet_info = m_packets.front();
|
||||
m_packets.pop();
|
||||
|
||||
size_t nread = BAN::Math::min<size_t>(packet_info.packet_size, buffer.size());
|
||||
|
||||
memcpy(
|
||||
buffer.data(),
|
||||
(const void*)m_packet_buffer->vaddr(),
|
||||
nread
|
||||
);
|
||||
memmove(
|
||||
(void*)m_packet_buffer->vaddr(),
|
||||
(void*)(m_packet_buffer->vaddr() + packet_info.packet_size),
|
||||
m_packet_total_size - packet_info.packet_size
|
||||
);
|
||||
|
||||
m_packet_total_size -= packet_info.packet_size;
|
||||
|
||||
if (sender_addr)
|
||||
{
|
||||
sender_addr->sin_family = AF_INET;
|
||||
sender_addr->sin_port = packet_info.sender_port;
|
||||
sender_addr->sin_addr.s_addr = packet_info.sender_addr.as_u32();
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user