Kernel: Start fleshing out an UDP implementation.

This commit is contained in:
Andreas Kling 2019-03-13 14:22:27 +01:00
parent 562663df7c
commit b59d588c04
Notes: sideshowbarker 2024-07-19 15:04:24 +09:00
6 changed files with 100 additions and 4 deletions

View file

@ -4,9 +4,12 @@
#include <Kernel/NetworkAdapter.h>
#include <Kernel/IPv4.h>
#include <Kernel/ICMP.h>
#include <Kernel/UDP.h>
#include <Kernel/ARP.h>
#include <LibC/errno_numbers.h>
#define IPV4_SOCKET_DEBUG
Lockable<HashTable<IPv4Socket*>>& IPv4Socket::all_sockets()
{
static Lockable<HashTable<IPv4Socket*>>* s_table;
@ -173,9 +176,22 @@ ssize_t IPv4Socket::recvfrom(void* buffer, size_t buffer_length, int flags, cons
}
ASSERT(!packet_buffer.is_null());
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
ASSERT(buffer_length >= ipv4_packet.payload_size());
memcpy(buffer, ipv4_packet.payload(), ipv4_packet.payload_size());
return ipv4_packet.payload_size();
if (type() == SOCK_RAW) {
ASSERT(buffer_length >= ipv4_packet.payload_size());
memcpy(buffer, ipv4_packet.payload(), ipv4_packet.payload_size());
return ipv4_packet.payload_size();
}
if (type() == SOCK_DGRAM) {
auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
ASSERT(udp_packet.length() >= sizeof(UDPPacket)); // FIXME: This should be rejected earlier.
ASSERT(buffer_length >= (udp_packet.length() - sizeof(UDPPacket)));
memcpy(buffer, udp_packet.payload(), udp_packet.length() - sizeof(UDPPacket));
return udp_packet.length() - sizeof(UDPPacket);
}
ASSERT_NOT_REACHED();
}
void IPv4Socket::did_receive(ByteBuffer&& packet)

View file

@ -29,6 +29,9 @@ public:
Lock& lock() { return m_lock; }
word source_port() const { return m_source_port; }
word destination_port() const { return m_destination_port; }
private:
IPv4Socket(int type, int protocol);
virtual bool is_ipv4() const override { return true; }
@ -42,6 +45,9 @@ private:
SinglyLinkedList<ByteBuffer> m_receive_queue;
word m_source_port { 0 };
word m_destination_port { 0 };
Lock m_lock;
bool m_can_read { false };
};

View file

@ -2,6 +2,7 @@
#include <Kernel/EthernetFrameHeader.h>
#include <Kernel/ARP.h>
#include <Kernel/ICMP.h>
#include <Kernel/UDP.h>
#include <Kernel/IPv4.h>
#include <Kernel/IPv4Socket.h>
#include <Kernel/Process.h>
@ -10,10 +11,13 @@
//#define ETHERNET_DEBUG
//#define IPV4_DEBUG
//#define ICMP_DEBUG
#define UDP_DEBUG
static void handle_arp(const EthernetFrameHeader&, int frame_size);
static void handle_ipv4(const EthernetFrameHeader&, int frame_size);
static void handle_icmp(const EthernetFrameHeader&, int frame_size);
static void handle_udp(const EthernetFrameHeader&, int frame_size);
Lockable<HashMap<IPv4Address, MACAddress>>& arp_table()
{
@ -146,6 +150,8 @@ void handle_ipv4(const EthernetFrameHeader& eth, int frame_size)
switch ((IPv4Protocol)packet.protocol()) {
case IPv4Protocol::ICMP:
return handle_icmp(eth, frame_size);
case IPv4Protocol::UDP:
return handle_udp(eth, frame_size);
default:
kprintf("handle_ipv4: Unhandled protocol %u\n", packet.protocol());
break;
@ -158,7 +164,7 @@ void handle_icmp(const EthernetFrameHeader& eth, int frame_size)
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
auto& icmp_header = *static_cast<const ICMPHeader*>(ipv4_packet.payload());
#ifdef ICMP_DEBUG
kprintf("handle_icmp: source=%s, destination=%d type=%b, code=%b\n",
kprintf("handle_icmp: source=%s, destination=%s, type=%b, code=%b\n",
ipv4_packet.source().to_string().characters(),
ipv4_packet.destination().to_string().characters(),
icmp_header.type(),
@ -200,3 +206,37 @@ void handle_icmp(const EthernetFrameHeader& eth, int frame_size)
adapter->send_ipv4(eth.source(), ipv4_packet.source(), IPv4Protocol::ICMP, move(buffer));
}
}
void handle_udp(const EthernetFrameHeader& eth, int frame_size)
{
(void)frame_size;
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
auto* adapter = NetworkAdapter::from_ipv4_address(ipv4_packet.destination());
if (!adapter) {
kprintf("handle_udp: this packet is not for me, it's for %s\n", ipv4_packet.destination().to_string().characters());
return;
}
auto& udp_packet = *static_cast<const UDPPacket*>(ipv4_packet.payload());
#ifdef UDP_DEBUG
kprintf("handle_udp: source=%s:%u, destination=%s:%u length=%u\n",
ipv4_packet.source().to_string().characters(),
udp_packet.source_port(),
ipv4_packet.destination().to_string().characters(),
udp_packet.destination_port(),
udp_packet.length()
);
#endif
LOCKER(IPv4Socket::all_sockets().lock());
for (RetainPtr<IPv4Socket> socket : IPv4Socket::all_sockets().resource()) {
LOCKER(socket->lock());
if (socket->protocol() != (unsigned)IPv4Protocol::UDP)
continue;
if (socket->source_port() != udp_packet.destination_port())
continue;
socket->did_receive(ByteBuffer::copy((const byte*)&ipv4_packet, sizeof(IPv4Packet) + ipv4_packet.payload_size()));
return;
}
}

32
Kernel/UDP.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include <Kernel/IPv4.h>
class [[gnu::packed]] UDPPacket {
public:
UDPPacket() { }
~UDPPacket() { }
word source_port() const { return m_source_port; }
void set_source_port(word port) { m_source_port = port; }
word destination_port() const { return m_destination_port; }
void set_destination_port(word port) { m_destination_port = port; }
word length() const { return m_length; }
void set_length(word length) { m_length = length; }
word checksum() const { return m_checksum; }
void set_checksum(word checksum) { m_checksum = checksum; }
const void* payload() const { return this + 1; }
void* payload() { return this + 1; }
private:
NetworkOrdered<word> m_source_port;
NetworkOrdered<word> m_destination_port;
NetworkOrdered<word> m_length;
NetworkOrdered<word> m_checksum;
};
static_assert(sizeof(UDPPacket) == 8);

View file

@ -322,6 +322,7 @@ struct pollfd {
#define SOCK_TYPE_MASK 0xff
#define SOCK_STREAM 1
#define SOCK_RAW 3
#define SOCK_DGRAM 2
#define SOCK_NONBLOCK 04000
#define SOCK_CLOEXEC 02000000

View file

@ -15,6 +15,7 @@ __BEGIN_DECLS
#define SOCK_TYPE_MASK 0xff
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define SOCK_RAW 3
#define SOCK_NONBLOCK 04000
#define SOCK_CLOEXEC 02000000