mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-22 17:31:58 -05:00
Kernel/Net: Start work on IPv6
This commit introduces the first bit of IPv6 support into SerenityOS. An IPv6 packet header structure allows NetworkTask to recognize and log correctly shaped IPv6 packets, but nothing is done with those yet. A new logging flag, IPV6_DEBUG, allows debugging of IPv6 internals. Co-Authored-By: sdomi <ja@sdomi.pl>
This commit is contained in:
parent
93951597a5
commit
11d46a4a00
6 changed files with 140 additions and 1 deletions
|
@ -143,6 +143,10 @@
|
|||
#cmakedefine01 IPV4_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef IPV6_DEBUG
|
||||
#cmakedefine01 IPV6_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef IPV4_SOCKET_DEBUG
|
||||
#cmakedefine01 IPV4_SOCKET_DEBUG
|
||||
#endif
|
||||
|
|
85
Kernel/Net/IP/IPv6.h
Normal file
85
Kernel/Net/IP/IPv6.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2024, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||
* Copyright (c) 2024, sdomi <ja@sdomi.pl>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Endian.h>
|
||||
#include <AK/IPv6Address.h>
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Net/IP/IP.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
// Header extensions and special values only.
|
||||
// For transport protocol numbers, see Kernel::TransportProtocol
|
||||
enum class IPv6NextHeader : u8 {
|
||||
HopByHopOption = 0,
|
||||
Routing = 43,
|
||||
Fragment = 44,
|
||||
NoNextHeader = 59,
|
||||
DestinationOptions = 60,
|
||||
};
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc8200#section-3
|
||||
class [[gnu::packed]] IPv6PacketHeader {
|
||||
public:
|
||||
u8 version() const { return (m_version_and_traffic >> 28) & 0xf; }
|
||||
void set_version(u8 version) { m_version_and_traffic = (m_version_and_traffic & ~0xf0000000) | (version << 28); }
|
||||
|
||||
u8 traffic_class() const { return (m_version_and_traffic >> 20) & 0x0ff; }
|
||||
void set_traffic_class(u8 traffic_class) { m_version_and_traffic = (m_version_and_traffic & ~0x0ff00000) | (traffic_class << 20); }
|
||||
|
||||
u32 flow_label() const { return m_version_and_traffic & 0xfffff; }
|
||||
void set_flow_label(u32 flow_label) { m_version_and_traffic = (m_version_and_traffic & ~0xfffff) | flow_label; }
|
||||
|
||||
u16 length() const { return m_length; }
|
||||
void set_length(u16 length) { m_length = length; }
|
||||
|
||||
// Aka. TTL
|
||||
u8 hop_limit() const { return m_hop_limit; }
|
||||
void set_hop_limit(u8 hop_limit) { m_hop_limit = hop_limit; }
|
||||
|
||||
u8 next_header() const { return m_next_header; }
|
||||
void set_next_header(u8 next_header) { m_next_header = next_header; }
|
||||
|
||||
IPv6Address const& source() const { return m_source; }
|
||||
void set_source(IPv6Address const& address) { m_source = address; }
|
||||
|
||||
IPv6Address const& destination() const { return m_destination; }
|
||||
void set_destination(IPv6Address const& address) { m_destination = address; }
|
||||
|
||||
void* payload() { return &m_payload[0]; }
|
||||
void const* payload() const { return &m_payload[0]; }
|
||||
|
||||
u16 payload_size() const { return m_length; }
|
||||
|
||||
private:
|
||||
NetworkOrdered<u32> m_version_and_traffic;
|
||||
NetworkOrdered<u16> m_length;
|
||||
u8 m_next_header { static_cast<u8>(IPv6NextHeader::NoNextHeader) };
|
||||
u8 m_hop_limit { 0 };
|
||||
IPv6Address m_source;
|
||||
IPv6Address m_destination;
|
||||
u8 m_payload[0];
|
||||
};
|
||||
|
||||
static_assert(AssertSize<IPv6PacketHeader, 10 * 32 / 8>());
|
||||
|
||||
// https://www.rfc-editor.org/rfc/rfc2460
|
||||
// section 8.1, checksumming
|
||||
struct [[gnu::packed]] IPv6PseudoHeader {
|
||||
IPv6Address source_address;
|
||||
IPv6Address target_address;
|
||||
NetworkOrdered<u32> packet_length;
|
||||
u8 zero[3] { 0 };
|
||||
TransportProtocol next_header;
|
||||
};
|
||||
|
||||
static_assert(AssertSize<IPv6PseudoHeader, 2 * 16 + 8>());
|
||||
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include <Kernel/Net/IP/ARP.h>
|
||||
#include <Kernel/Net/IP/IP.h>
|
||||
#include <Kernel/Net/IP/IPv4.h>
|
||||
#include <Kernel/Net/IP/IPv6.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -108,6 +109,7 @@ public:
|
|||
|
||||
constexpr size_t layer3_payload_offset() const { return sizeof(EthernetFrameHeader); }
|
||||
constexpr size_t ipv4_payload_offset() const { return layer3_payload_offset() + sizeof(IPv4Packet); }
|
||||
constexpr size_t ipv6_payload_offset() const { return layer3_payload_offset() + sizeof(IPv6PacketHeader); }
|
||||
|
||||
Function<void()> on_receive;
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2024, sdomi <ja@sdomi.pl>
|
||||
* Copyright (c) 2024, kleines Filmröllchen <filmroellchen@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -13,6 +15,7 @@
|
|||
#include <Kernel/Net/IP/ARP.h>
|
||||
#include <Kernel/Net/IP/IP.h>
|
||||
#include <Kernel/Net/IP/IPv4.h>
|
||||
#include <Kernel/Net/IP/IPv6.h>
|
||||
#include <Kernel/Net/IP/Socket.h>
|
||||
#include <Kernel/Net/LoopbackAdapter.h>
|
||||
#include <Kernel/Net/NetworkTask.h>
|
||||
|
@ -29,6 +32,7 @@ namespace Kernel {
|
|||
static void handle_arp(EthernetFrameHeader const&, size_t frame_size);
|
||||
static void handle_ipv4(EthernetFrameHeader const&, size_t frame_size, UnixDateTime const& packet_timestamp, RefPtr<NetworkAdapter> adapter);
|
||||
static void handle_icmp(EthernetFrameHeader const&, IPv4Packet const&, UnixDateTime const& packet_timestamp, RefPtr<NetworkAdapter> adapter);
|
||||
static void handle_ipv6(EthernetFrameHeader const&, size_t frame_size, UnixDateTime const& packet_timestamp, RefPtr<NetworkAdapter> adapter);
|
||||
static void handle_udp(IPv4Packet const&, UnixDateTime const& packet_timestamp);
|
||||
static void handle_tcp(IPv4Packet const&, UnixDateTime const& packet_timestamp, RefPtr<NetworkAdapter> adapter);
|
||||
static void send_delayed_tcp_ack(TCPSocket& socket);
|
||||
|
@ -121,7 +125,7 @@ void NetworkTask_main(void*)
|
|||
handle_ipv4(eth, packet_size, meta.packet_timestamp, meta.adapter);
|
||||
break;
|
||||
case EtherType::IPv6:
|
||||
// ignore
|
||||
handle_ipv6(eth, packet_size, meta.packet_timestamp, meta.adapter);
|
||||
break;
|
||||
default:
|
||||
dbgln_if(ETHERNET_DEBUG, "NetworkTask: Unknown ethernet type {:#04x}", eth.ether_type());
|
||||
|
@ -225,6 +229,48 @@ void handle_ipv4(EthernetFrameHeader const& eth, size_t frame_size, UnixDateTime
|
|||
}
|
||||
}
|
||||
|
||||
void handle_ipv6(EthernetFrameHeader const& eth, size_t frame_size, UnixDateTime const& packet_timestamp, RefPtr<NetworkAdapter> adapter)
|
||||
{
|
||||
(void)packet_timestamp;
|
||||
|
||||
constexpr size_t minimum_ipv6_frame_size = sizeof(EthernetFrameHeader) + sizeof(IPv6PacketHeader);
|
||||
if (frame_size < minimum_ipv6_frame_size) {
|
||||
dbgln("handle_ipv6: Frame too small ({}, need {})", frame_size, minimum_ipv6_frame_size);
|
||||
return;
|
||||
}
|
||||
auto& packet = *static_cast<IPv6PacketHeader const*>(eth.payload());
|
||||
size_t const actual_ipv6_packet_length = frame_size - adapter->layer3_payload_offset();
|
||||
size_t const payload_length = frame_size - adapter->ipv6_payload_offset();
|
||||
|
||||
if (packet.length() < payload_length) {
|
||||
dbgln("handle_ipv6: IPv6 packet too short ({}, need {})", packet.length(), sizeof(IPv6PacketHeader));
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.length() > payload_length) {
|
||||
dbgln("handle_ipv6: IPv6 packet claims to be longer than it is ({}, actually {})", packet.length(), actual_ipv6_packet_length);
|
||||
return;
|
||||
}
|
||||
|
||||
dbgln_if(IPV6_DEBUG, "handle_ipv6: source={}, destination={}", packet.source(), packet.destination());
|
||||
|
||||
// TODO: Update ARP tables.
|
||||
|
||||
// TODO: skip or handle next headers that are not the next layer protocol header.
|
||||
|
||||
switch (static_cast<TransportProtocol>(packet.next_header())) {
|
||||
case TransportProtocol::UDP:
|
||||
dbgln_if(IPV6_DEBUG, "handle_ipv6: TODO: got UDP packet, what to do with it?");
|
||||
break;
|
||||
case TransportProtocol::TCP:
|
||||
dbgln_if(IPV6_DEBUG, "handle_ipv6: TODO: got TCP packet, what to do with it?");
|
||||
break;
|
||||
default:
|
||||
dbgln_if(IPV6_DEBUG, "handle_ipv6: Unhandled protocol {:#02x}", packet.next_header());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handle_icmp(EthernetFrameHeader const& eth, IPv4Packet const& ipv4_packet, UnixDateTime const& packet_timestamp, RefPtr<NetworkAdapter> adapter)
|
||||
{
|
||||
auto& icmp_header = *static_cast<ICMPHeader const*>(ipv4_packet.payload());
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/IPv4Address.h>
|
||||
#include <AK/IPv6Address.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <Kernel/Locking/MutexProtected.h>
|
||||
#include <Kernel/Net/NetworkAdapter.h>
|
||||
|
|
|
@ -87,6 +87,7 @@ set(INTERRUPT_DEBUG ON)
|
|||
set(IOAPIC_DEBUG ON)
|
||||
set(IO_DEBUG ON)
|
||||
set(IPV4_DEBUG ON)
|
||||
set(IPV6_DEBUG ON)
|
||||
set(IPV4_SOCKET_DEBUG ON)
|
||||
set(IRQ_DEBUG ON)
|
||||
set(ISO9660_DEBUG ON)
|
||||
|
|
Loading…
Reference in a new issue