mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:08:10 +00:00
Kernel: Start fleshing out an UDP implementation.
This commit is contained in:
parent
562663df7c
commit
b59d588c04
6 changed files with 100 additions and 4 deletions
|
@ -4,9 +4,12 @@
|
||||||
#include <Kernel/NetworkAdapter.h>
|
#include <Kernel/NetworkAdapter.h>
|
||||||
#include <Kernel/IPv4.h>
|
#include <Kernel/IPv4.h>
|
||||||
#include <Kernel/ICMP.h>
|
#include <Kernel/ICMP.h>
|
||||||
|
#include <Kernel/UDP.h>
|
||||||
#include <Kernel/ARP.h>
|
#include <Kernel/ARP.h>
|
||||||
#include <LibC/errno_numbers.h>
|
#include <LibC/errno_numbers.h>
|
||||||
|
|
||||||
|
#define IPV4_SOCKET_DEBUG
|
||||||
|
|
||||||
Lockable<HashTable<IPv4Socket*>>& IPv4Socket::all_sockets()
|
Lockable<HashTable<IPv4Socket*>>& IPv4Socket::all_sockets()
|
||||||
{
|
{
|
||||||
static Lockable<HashTable<IPv4Socket*>>* s_table;
|
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());
|
ASSERT(!packet_buffer.is_null());
|
||||||
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
|
auto& ipv4_packet = *(const IPv4Packet*)(packet_buffer.pointer());
|
||||||
ASSERT(buffer_length >= ipv4_packet.payload_size());
|
|
||||||
memcpy(buffer, ipv4_packet.payload(), ipv4_packet.payload_size());
|
if (type() == SOCK_RAW) {
|
||||||
return ipv4_packet.payload_size();
|
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)
|
void IPv4Socket::did_receive(ByteBuffer&& packet)
|
||||||
|
|
|
@ -29,6 +29,9 @@ public:
|
||||||
|
|
||||||
Lock& lock() { return m_lock; }
|
Lock& lock() { return m_lock; }
|
||||||
|
|
||||||
|
word source_port() const { return m_source_port; }
|
||||||
|
word destination_port() const { return m_destination_port; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IPv4Socket(int type, int protocol);
|
IPv4Socket(int type, int protocol);
|
||||||
virtual bool is_ipv4() const override { return true; }
|
virtual bool is_ipv4() const override { return true; }
|
||||||
|
@ -42,6 +45,9 @@ private:
|
||||||
|
|
||||||
SinglyLinkedList<ByteBuffer> m_receive_queue;
|
SinglyLinkedList<ByteBuffer> m_receive_queue;
|
||||||
|
|
||||||
|
word m_source_port { 0 };
|
||||||
|
word m_destination_port { 0 };
|
||||||
|
|
||||||
Lock m_lock;
|
Lock m_lock;
|
||||||
bool m_can_read { false };
|
bool m_can_read { false };
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <Kernel/EthernetFrameHeader.h>
|
#include <Kernel/EthernetFrameHeader.h>
|
||||||
#include <Kernel/ARP.h>
|
#include <Kernel/ARP.h>
|
||||||
#include <Kernel/ICMP.h>
|
#include <Kernel/ICMP.h>
|
||||||
|
#include <Kernel/UDP.h>
|
||||||
#include <Kernel/IPv4.h>
|
#include <Kernel/IPv4.h>
|
||||||
#include <Kernel/IPv4Socket.h>
|
#include <Kernel/IPv4Socket.h>
|
||||||
#include <Kernel/Process.h>
|
#include <Kernel/Process.h>
|
||||||
|
@ -10,10 +11,13 @@
|
||||||
|
|
||||||
//#define ETHERNET_DEBUG
|
//#define ETHERNET_DEBUG
|
||||||
//#define IPV4_DEBUG
|
//#define IPV4_DEBUG
|
||||||
|
//#define ICMP_DEBUG
|
||||||
|
#define UDP_DEBUG
|
||||||
|
|
||||||
static void handle_arp(const EthernetFrameHeader&, int frame_size);
|
static void handle_arp(const EthernetFrameHeader&, int frame_size);
|
||||||
static void handle_ipv4(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_icmp(const EthernetFrameHeader&, int frame_size);
|
||||||
|
static void handle_udp(const EthernetFrameHeader&, int frame_size);
|
||||||
|
|
||||||
Lockable<HashMap<IPv4Address, MACAddress>>& arp_table()
|
Lockable<HashMap<IPv4Address, MACAddress>>& arp_table()
|
||||||
{
|
{
|
||||||
|
@ -146,6 +150,8 @@ void handle_ipv4(const EthernetFrameHeader& eth, int frame_size)
|
||||||
switch ((IPv4Protocol)packet.protocol()) {
|
switch ((IPv4Protocol)packet.protocol()) {
|
||||||
case IPv4Protocol::ICMP:
|
case IPv4Protocol::ICMP:
|
||||||
return handle_icmp(eth, frame_size);
|
return handle_icmp(eth, frame_size);
|
||||||
|
case IPv4Protocol::UDP:
|
||||||
|
return handle_udp(eth, frame_size);
|
||||||
default:
|
default:
|
||||||
kprintf("handle_ipv4: Unhandled protocol %u\n", packet.protocol());
|
kprintf("handle_ipv4: Unhandled protocol %u\n", packet.protocol());
|
||||||
break;
|
break;
|
||||||
|
@ -158,7 +164,7 @@ void handle_icmp(const EthernetFrameHeader& eth, int frame_size)
|
||||||
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
|
auto& ipv4_packet = *static_cast<const IPv4Packet*>(eth.payload());
|
||||||
auto& icmp_header = *static_cast<const ICMPHeader*>(ipv4_packet.payload());
|
auto& icmp_header = *static_cast<const ICMPHeader*>(ipv4_packet.payload());
|
||||||
#ifdef ICMP_DEBUG
|
#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.source().to_string().characters(),
|
||||||
ipv4_packet.destination().to_string().characters(),
|
ipv4_packet.destination().to_string().characters(),
|
||||||
icmp_header.type(),
|
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));
|
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_TYPE_MASK 0xff
|
||||||
#define SOCK_STREAM 1
|
#define SOCK_STREAM 1
|
||||||
#define SOCK_RAW 3
|
#define SOCK_RAW 3
|
||||||
|
#define SOCK_DGRAM 2
|
||||||
#define SOCK_NONBLOCK 04000
|
#define SOCK_NONBLOCK 04000
|
||||||
#define SOCK_CLOEXEC 02000000
|
#define SOCK_CLOEXEC 02000000
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ __BEGIN_DECLS
|
||||||
|
|
||||||
#define SOCK_TYPE_MASK 0xff
|
#define SOCK_TYPE_MASK 0xff
|
||||||
#define SOCK_STREAM 1
|
#define SOCK_STREAM 1
|
||||||
|
#define SOCK_DGRAM 2
|
||||||
#define SOCK_RAW 3
|
#define SOCK_RAW 3
|
||||||
#define SOCK_NONBLOCK 04000
|
#define SOCK_NONBLOCK 04000
|
||||||
#define SOCK_CLOEXEC 02000000
|
#define SOCK_CLOEXEC 02000000
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue