diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-03-13 14:22:27 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-03-13 14:22:27 +0100 |
commit | b59d588c0482a78c9a69f88b82aa0e2bb8fe1955 (patch) | |
tree | 9ae7da7329de52f8e7593de0b508eb511dc4daf5 | |
parent | 562663df7c13d27834adacaa1fa5cb9a4ef47c2e (diff) | |
download | serenity-b59d588c0482a78c9a69f88b82aa0e2bb8fe1955.zip |
Kernel: Start fleshing out an UDP implementation.
-rw-r--r-- | Kernel/IPv4Socket.cpp | 22 | ||||
-rw-r--r-- | Kernel/IPv4Socket.h | 6 | ||||
-rw-r--r-- | Kernel/NetworkTask.cpp | 42 | ||||
-rw-r--r-- | Kernel/UDP.h | 32 | ||||
-rw-r--r-- | Kernel/UnixTypes.h | 1 | ||||
-rw-r--r-- | LibC/sys/socket.h | 1 |
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 |