mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
Kernel: Start fleshing out an UDP implementation.
This commit is contained in:
parent
562663df7c
commit
b59d588c04
Notes:
sideshowbarker
2024-07-19 15:04:24 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/b59d588c048
6 changed files with 100 additions and 4 deletions
|
@ -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)
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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
32
Kernel/UDP.h
Normal 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);
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue