From 8e0a56b49a88b0a88142d009ce0ec1889a9ed075 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 11 May 2025 03:22:19 +0300 Subject: [PATCH] Kernel: Implement loopback network interface --- kernel/CMakeLists.txt | 1 + kernel/include/kernel/Device/DeviceNumbers.h | 1 + .../include/kernel/Networking/E1000/E1000.h | 3 +- kernel/include/kernel/Networking/Loopback.h | 39 +++++++++++++++ .../kernel/Networking/NetworkInterface.h | 5 +- .../kernel/Networking/NetworkManager.h | 4 +- .../kernel/Networking/RTL8169/RTL8169.h | 3 +- kernel/kernel/Networking/ARPTable.cpp | 14 +++++- kernel/kernel/Networking/IPv4Layer.cpp | 23 ++++++--- kernel/kernel/Networking/Loopback.cpp | 49 +++++++++++++++++++ kernel/kernel/Networking/NetworkInterface.cpp | 35 +++++++++---- kernel/kernel/Networking/NetworkManager.cpp | 8 ++- 12 files changed, 164 insertions(+), 21 deletions(-) create mode 100644 kernel/include/kernel/Networking/Loopback.h create mode 100644 kernel/kernel/Networking/Loopback.cpp diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 4bb961bb..eb470b67 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -55,6 +55,7 @@ set(KERNEL_SOURCES kernel/Networking/E1000/E1000.cpp kernel/Networking/E1000/E1000E.cpp kernel/Networking/IPv4Layer.cpp + kernel/Networking/Loopback.cpp kernel/Networking/NetworkInterface.cpp kernel/Networking/NetworkLayer.cpp kernel/Networking/NetworkManager.cpp diff --git a/kernel/include/kernel/Device/DeviceNumbers.h b/kernel/include/kernel/Device/DeviceNumbers.h index 3a3617ac..e2c43fcb 100644 --- a/kernel/include/kernel/Device/DeviceNumbers.h +++ b/kernel/include/kernel/Device/DeviceNumbers.h @@ -20,6 +20,7 @@ namespace Kernel NVMeController, NVMeNamespace, Ethernet, + Loopback, TmpFS, }; diff --git a/kernel/include/kernel/Networking/E1000/E1000.h b/kernel/include/kernel/Networking/E1000/E1000.h index 7aa12f53..34d3c720 100644 --- a/kernel/include/kernel/Networking/E1000/E1000.h +++ b/kernel/include/kernel/Networking/E1000/E1000.h @@ -34,7 +34,8 @@ namespace Kernel protected: E1000(PCI::Device& pci_device) - : m_pci_device(pci_device) + : NetworkInterface(Type::Ethernet) + , m_pci_device(pci_device) { } BAN::ErrorOr initialize(); diff --git a/kernel/include/kernel/Networking/Loopback.h b/kernel/include/kernel/Networking/Loopback.h new file mode 100644 index 00000000..e7875544 --- /dev/null +++ b/kernel/include/kernel/Networking/Loopback.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace Kernel +{ + + class LoopbackInterface : public NetworkInterface + { + public: + static constexpr size_t buffer_size = BAN::numeric_limits::max() + 1; + + public: + static BAN::ErrorOr> create(); + + BAN::MACAddress get_mac_address() const override { return {}; } + + bool link_up() override { return true; } + int link_speed() override { return 1000; } + + size_t payload_mtu() const override { return buffer_size - sizeof(EthernetHeader); } + + protected: + LoopbackInterface() + : NetworkInterface(Type::Loopback) + {} + + BAN::ErrorOr send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; + + bool can_read_impl() const override { return false; } + bool can_write_impl() const override { return false; } + bool has_error_impl() const override { return false; } + + private: + SpinLock m_buffer_lock; + BAN::UniqPtr m_buffer; + }; + +} diff --git a/kernel/include/kernel/Networking/NetworkInterface.h b/kernel/include/kernel/Networking/NetworkInterface.h index 6980e621..892c6434 100644 --- a/kernel/include/kernel/Networking/NetworkInterface.h +++ b/kernel/include/kernel/Networking/NetworkInterface.h @@ -32,10 +32,11 @@ namespace Kernel enum class Type { Ethernet, + Loopback, }; public: - NetworkInterface(); + NetworkInterface(Type); virtual ~NetworkInterface() {} virtual BAN::MACAddress get_mac_address() const = 0; @@ -49,6 +50,8 @@ namespace Kernel BAN::IPv4Address get_gateway() const { return m_gateway; } void set_gateway(BAN::IPv4Address new_gateway) { m_gateway = new_gateway; } + Type type() const { return m_type; } + virtual bool link_up() = 0; virtual int link_speed() = 0; diff --git a/kernel/include/kernel/Networking/NetworkManager.h b/kernel/include/kernel/Networking/NetworkManager.h index 1835ac5a..aa0f1d10 100644 --- a/kernel/include/kernel/Networking/NetworkManager.h +++ b/kernel/include/kernel/Networking/NetworkManager.h @@ -22,7 +22,7 @@ namespace Kernel BAN::ErrorOr add_interface(PCI::Device& pci_device); - BAN::Vector> interfaces() { return m_interfaces; } + BAN::Vector>& interfaces() { return m_interfaces; } BAN::ErrorOr> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t); @@ -31,6 +31,8 @@ namespace Kernel private: NetworkManager() {} + BAN::ErrorOr add_interface(BAN::RefPtr); + private: BAN::UniqPtr m_ipv4_layer; BAN::Vector> m_interfaces; diff --git a/kernel/include/kernel/Networking/RTL8169/RTL8169.h b/kernel/include/kernel/Networking/RTL8169/RTL8169.h index def4033d..0d041084 100644 --- a/kernel/include/kernel/Networking/RTL8169/RTL8169.h +++ b/kernel/include/kernel/Networking/RTL8169/RTL8169.h @@ -26,7 +26,8 @@ namespace Kernel protected: RTL8169(PCI::Device& pci_device) - : m_pci_device(pci_device) + : NetworkInterface(Type::Ethernet) + , m_pci_device(pci_device) { } BAN::ErrorOr initialize(); diff --git a/kernel/kernel/Networking/ARPTable.cpp b/kernel/kernel/Networking/ARPTable.cpp index d67b5098..1bb85e7e 100644 --- a/kernel/kernel/Networking/ARPTable.cpp +++ b/kernel/kernel/Networking/ARPTable.cpp @@ -44,10 +44,22 @@ namespace Kernel if (ipv4_address == s_broadcast_ipv4) return s_broadcast_mac; + const auto netmask = interface.get_netmask(); + const bool same_subnet = ipv4_address.mask(netmask) == interface.get_ipv4_address().mask(netmask); + + if (interface.type() == NetworkInterface::Type::Loopback) + { + if (!same_subnet) + return BAN::Error::from_errno(EADDRNOTAVAIL); + return BAN::MACAddress {}; + } + + ASSERT(interface.type() == NetworkInterface::Type::Ethernet); + if (interface.get_ipv4_address() == BAN::IPv4Address { 0 }) return BAN::Error::from_errno(EINVAL); - if (interface.get_ipv4_address().mask(interface.get_netmask()) != ipv4_address.mask(interface.get_netmask())) + if (!same_subnet) ipv4_address = interface.get_gateway(); { diff --git a/kernel/kernel/Networking/IPv4Layer.cpp b/kernel/kernel/Networking/IPv4Layer.cpp index 0ee5f578..9553cb90 100644 --- a/kernel/kernel/Networking/IPv4Layer.cpp +++ b/kernel/kernel/Networking/IPv4Layer.cpp @@ -107,9 +107,6 @@ namespace Kernel BAN::ErrorOr IPv4Layer::bind_socket_to_address(BAN::RefPtr socket, const sockaddr* address, socklen_t address_len) { - if (NetworkManager::get().interfaces().empty()) - return BAN::Error::from_errno(EADDRNOTAVAIL); - if (!address || address_len < (socklen_t)sizeof(sockaddr_in)) return BAN::Error::from_errno(EINVAL); if (address->sa_family != AF_INET) @@ -119,6 +116,22 @@ namespace Kernel const uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port); if (port == NetworkSocket::PORT_NONE) return bind_socket_to_unused(socket, address, address_len); + const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr }; + + BAN::RefPtr bind_interface; + for (auto interface : NetworkManager::get().interfaces()) + { + if (interface->type() != NetworkInterface::Type::Loopback) + bind_interface = interface; + const auto netmask = interface->get_netmask(); + if (ipv4.mask(netmask) != interface->get_ipv4_address().mask(netmask)) + continue; + bind_interface = interface; + break; + } + + if (!bind_interface) + return BAN::Error::from_errno(EADDRNOTAVAIL); SpinLockGuard _(m_bound_socket_lock); @@ -126,9 +139,7 @@ namespace Kernel return BAN::Error::from_errno(EADDRINUSE); TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr()))); - // FIXME: actually determine proper interface - auto interface = NetworkManager::get().interfaces().front(); - socket->bind_interface_and_port(interface.ptr(), port); + socket->bind_interface_and_port(bind_interface.ptr(), port); return {}; } diff --git a/kernel/kernel/Networking/Loopback.cpp b/kernel/kernel/Networking/Loopback.cpp new file mode 100644 index 00000000..3ec98106 --- /dev/null +++ b/kernel/kernel/Networking/Loopback.cpp @@ -0,0 +1,49 @@ +#include +#include + +namespace Kernel +{ + + BAN::ErrorOr> LoopbackInterface::create() + { + auto* loopback_ptr = new LoopbackInterface(); + if (loopback_ptr == nullptr) + return BAN::Error::from_errno(ENOMEM); + auto loopback = BAN::RefPtr::adopt(loopback_ptr); + loopback->m_buffer = TRY(VirtualRange::create_to_vaddr_range( + PageTable::kernel(), + KERNEL_OFFSET, + BAN::numeric_limits::max(), + buffer_size, + PageTable::Flags::ReadWrite | PageTable::Flags::Present, + true + )); + loopback->set_ipv4_address({ 127, 0, 0, 1 }); + loopback->set_netmask({ 255, 0, 0, 0 }); + return loopback; + } + + BAN::ErrorOr LoopbackInterface::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer) + { + ASSERT(buffer.size() + sizeof(EthernetHeader) <= buffer_size); + + SpinLockGuard _(m_buffer_lock); + + uint8_t* buffer_vaddr = reinterpret_cast(m_buffer->vaddr()); + + auto& ethernet_header = *reinterpret_cast(buffer_vaddr); + ethernet_header.dst_mac = destination; + ethernet_header.src_mac = get_mac_address(); + ethernet_header.ether_type = protocol; + + memcpy(buffer_vaddr + sizeof(EthernetHeader), buffer.data(), buffer.size()); + + NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { + buffer_vaddr, + buffer.size() + sizeof(EthernetHeader) + }); + + return {}; + } + +} diff --git a/kernel/kernel/Networking/NetworkInterface.cpp b/kernel/kernel/Networking/NetworkInterface.cpp index 6518414a..0c27e20e 100644 --- a/kernel/kernel/Networking/NetworkInterface.cpp +++ b/kernel/kernel/Networking/NetworkInterface.cpp @@ -9,22 +9,39 @@ namespace Kernel { - static dev_t get_network_rdev_minor() + static BAN::Atomic s_ethernet_rdev_minor = 0; + static BAN::Atomic s_loopback_rdev_minor = 0; + + static dev_t get_rdev(NetworkInterface::Type type) { - static dev_t minor = 0; - return minor++; + switch (type) + { + case NetworkInterface::Type::Ethernet: + return makedev(DeviceNumber::Ethernet, s_ethernet_rdev_minor++); + case NetworkInterface::Type::Loopback: + return makedev(DeviceNumber::Ethernet, s_loopback_rdev_minor++); + } + ASSERT_NOT_REACHED(); } - NetworkInterface::NetworkInterface() + NetworkInterface::NetworkInterface(Type type) : CharacterDevice(0400, 0, 0) - , m_type(Type::Ethernet) - , m_rdev(makedev(DeviceNumber::Ethernet, get_network_rdev_minor())) + , m_type(type) + , m_rdev(get_rdev(type)) { ASSERT(minor(m_rdev) < 10); - ASSERT(m_type == Type::Ethernet); - strcpy(m_name, "ethx"); - m_name[3] = minor(m_rdev) + '0'; + switch (type) + { + case Type::Ethernet: + strcpy(m_name, "ethx"); + m_name[3] = minor(m_rdev) + '0'; + break; + case Type::Loopback: + strcpy(m_name, "lox"); + m_name[2] = minor(m_rdev) + '0'; + break; + } } } diff --git a/kernel/kernel/Networking/NetworkManager.cpp b/kernel/kernel/Networking/NetworkManager.cpp index 7aa519b8..b0b3920f 100644 --- a/kernel/kernel/Networking/NetworkManager.cpp +++ b/kernel/kernel/Networking/NetworkManager.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ namespace Kernel { ASSERT(!s_instance); auto manager = TRY(BAN::UniqPtr::create()); + TRY(manager->add_interface(TRY(LoopbackInterface::create()))); manager->m_ipv4_layer = TRY(IPv4Layer::create()); s_instance = BAN::move(manager); return {}; @@ -62,9 +64,13 @@ namespace Kernel ASSERT(interface); + return add_interface(interface); + } + + BAN::ErrorOr NetworkManager::add_interface(BAN::RefPtr interface) + { TRY(m_interfaces.push_back(interface)); DevFileSystem::get().add_device(interface); - return {}; }