summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-03-13 14:22:27 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-03-13 14:22:27 +0100
commitb59d588c0482a78c9a69f88b82aa0e2bb8fe1955 (patch)
tree9ae7da7329de52f8e7593de0b508eb511dc4daf5
parent562663df7c13d27834adacaa1fa5cb9a4ef47c2e (diff)
downloadserenity-b59d588c0482a78c9a69f88b82aa0e2bb8fe1955.zip
Kernel: Start fleshing out an UDP implementation.
-rw-r--r--Kernel/IPv4Socket.cpp22
-rw-r--r--Kernel/IPv4Socket.h6
-rw-r--r--Kernel/NetworkTask.cpp42
-rw-r--r--Kernel/UDP.h32
-rw-r--r--Kernel/UnixTypes.h1
-rw-r--r--LibC/sys/socket.h1
6 files changed, 100 insertions, 4 deletions
diff --git a/Kernel/IPv4Socket.cpp b/Kernel/IPv4Socket.cpp
index 4945049dba..6ceae409ea 100644
--- a/Kernel/IPv4Socket.cpp
+++ b/Kernel/IPv4Socket.cpp
@@ -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)
diff --git a/Kernel/IPv4Socket.h b/Kernel/IPv4Socket.h
index 416798e606..417ffe0e4d 100644
--- a/Kernel/IPv4Socket.h
+++ b/Kernel/IPv4Socket.h
@@ -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 };
};
diff --git a/Kernel/NetworkTask.cpp b/Kernel/NetworkTask.cpp
index b579bd8dfe..e85d5ab7bd 100644
--- a/Kernel/NetworkTask.cpp
+++ b/Kernel/NetworkTask.cpp
@@ -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;
+ }
+}
diff --git a/Kernel/UDP.h b/Kernel/UDP.h
new file mode 100644
index 0000000000..c4da36b7a5
--- /dev/null
+++ b/Kernel/UDP.h
@@ -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);
diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h
index 5c54c1a228..57d390656f 100644
--- a/Kernel/UnixTypes.h
+++ b/Kernel/UnixTypes.h
@@ -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
diff --git a/LibC/sys/socket.h b/LibC/sys/socket.h
index 63d99ab466..875bb5223a 100644
--- a/LibC/sys/socket.h
+++ b/LibC/sys/socket.h
@@ -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