Kernel: Implement loopback network interface
This commit is contained in:
parent
a8844ddd28
commit
8e0a56b49a
|
@ -55,6 +55,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/Networking/E1000/E1000.cpp
|
kernel/Networking/E1000/E1000.cpp
|
||||||
kernel/Networking/E1000/E1000E.cpp
|
kernel/Networking/E1000/E1000E.cpp
|
||||||
kernel/Networking/IPv4Layer.cpp
|
kernel/Networking/IPv4Layer.cpp
|
||||||
|
kernel/Networking/Loopback.cpp
|
||||||
kernel/Networking/NetworkInterface.cpp
|
kernel/Networking/NetworkInterface.cpp
|
||||||
kernel/Networking/NetworkLayer.cpp
|
kernel/Networking/NetworkLayer.cpp
|
||||||
kernel/Networking/NetworkManager.cpp
|
kernel/Networking/NetworkManager.cpp
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace Kernel
|
||||||
NVMeController,
|
NVMeController,
|
||||||
NVMeNamespace,
|
NVMeNamespace,
|
||||||
Ethernet,
|
Ethernet,
|
||||||
|
Loopback,
|
||||||
TmpFS,
|
TmpFS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ namespace Kernel
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
E1000(PCI::Device& pci_device)
|
E1000(PCI::Device& pci_device)
|
||||||
: m_pci_device(pci_device)
|
: NetworkInterface(Type::Ethernet)
|
||||||
|
, m_pci_device(pci_device)
|
||||||
{ }
|
{ }
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class LoopbackInterface : public NetworkInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr size_t buffer_size = BAN::numeric_limits<uint16_t>::max() + 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> 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<void> 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<VirtualRange> m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -32,10 +32,11 @@ namespace Kernel
|
||||||
enum class Type
|
enum class Type
|
||||||
{
|
{
|
||||||
Ethernet,
|
Ethernet,
|
||||||
|
Loopback,
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NetworkInterface();
|
NetworkInterface(Type);
|
||||||
virtual ~NetworkInterface() {}
|
virtual ~NetworkInterface() {}
|
||||||
|
|
||||||
virtual BAN::MACAddress get_mac_address() const = 0;
|
virtual BAN::MACAddress get_mac_address() const = 0;
|
||||||
|
@ -49,6 +50,8 @@ namespace Kernel
|
||||||
BAN::IPv4Address get_gateway() const { return m_gateway; }
|
BAN::IPv4Address get_gateway() const { return m_gateway; }
|
||||||
void set_gateway(BAN::IPv4Address new_gateway) { m_gateway = new_gateway; }
|
void set_gateway(BAN::IPv4Address new_gateway) { m_gateway = new_gateway; }
|
||||||
|
|
||||||
|
Type type() const { return m_type; }
|
||||||
|
|
||||||
virtual bool link_up() = 0;
|
virtual bool link_up() = 0;
|
||||||
virtual int link_speed() = 0;
|
virtual int link_speed() = 0;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> add_interface(PCI::Device& pci_device);
|
BAN::ErrorOr<void> add_interface(PCI::Device& pci_device);
|
||||||
|
|
||||||
BAN::Vector<BAN::RefPtr<NetworkInterface>> interfaces() { return m_interfaces; }
|
BAN::Vector<BAN::RefPtr<NetworkInterface>>& interfaces() { return m_interfaces; }
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t);
|
BAN::ErrorOr<BAN::RefPtr<Socket>> create_socket(Socket::Domain, Socket::Type, mode_t, uid_t, gid_t);
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
NetworkManager() {}
|
NetworkManager() {}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> add_interface(BAN::RefPtr<NetworkInterface>);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::UniqPtr<IPv4Layer> m_ipv4_layer;
|
BAN::UniqPtr<IPv4Layer> m_ipv4_layer;
|
||||||
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
|
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
|
||||||
|
|
|
@ -26,7 +26,8 @@ namespace Kernel
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RTL8169(PCI::Device& pci_device)
|
RTL8169(PCI::Device& pci_device)
|
||||||
: m_pci_device(pci_device)
|
: NetworkInterface(Type::Ethernet)
|
||||||
|
, m_pci_device(pci_device)
|
||||||
{ }
|
{ }
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,22 @@ namespace Kernel
|
||||||
if (ipv4_address == s_broadcast_ipv4)
|
if (ipv4_address == s_broadcast_ipv4)
|
||||||
return s_broadcast_mac;
|
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 })
|
if (interface.get_ipv4_address() == BAN::IPv4Address { 0 })
|
||||||
return BAN::Error::from_errno(EINVAL);
|
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();
|
ipv4_address = interface.get_gateway();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -107,9 +107,6 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_address(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_address(BAN::RefPtr<NetworkSocket> 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))
|
if (!address || address_len < (socklen_t)sizeof(sockaddr_in))
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
if (address->sa_family != AF_INET)
|
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);
|
const uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
||||||
if (port == NetworkSocket::PORT_NONE)
|
if (port == NetworkSocket::PORT_NONE)
|
||||||
return bind_socket_to_unused(socket, address, address_len);
|
return bind_socket_to_unused(socket, address, address_len);
|
||||||
|
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||||
|
|
||||||
|
BAN::RefPtr<NetworkInterface> 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);
|
SpinLockGuard _(m_bound_socket_lock);
|
||||||
|
|
||||||
|
@ -126,9 +139,7 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EADDRINUSE);
|
return BAN::Error::from_errno(EADDRINUSE);
|
||||||
TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr())));
|
TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr())));
|
||||||
|
|
||||||
// FIXME: actually determine proper interface
|
socket->bind_interface_and_port(bind_interface.ptr(), port);
|
||||||
auto interface = NetworkManager::get().interfaces().front();
|
|
||||||
socket->bind_interface_and_port(interface.ptr(), port);
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include <kernel/Networking/Loopback.h>
|
||||||
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> LoopbackInterface::create()
|
||||||
|
{
|
||||||
|
auto* loopback_ptr = new LoopbackInterface();
|
||||||
|
if (loopback_ptr == nullptr)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
auto loopback = BAN::RefPtr<LoopbackInterface>::adopt(loopback_ptr);
|
||||||
|
loopback->m_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
|
PageTable::kernel(),
|
||||||
|
KERNEL_OFFSET,
|
||||||
|
BAN::numeric_limits<vaddr_t>::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<void> 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<uint8_t*>(m_buffer->vaddr());
|
||||||
|
|
||||||
|
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(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 {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,22 +9,39 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static dev_t get_network_rdev_minor()
|
static BAN::Atomic<dev_t> s_ethernet_rdev_minor = 0;
|
||||||
|
static BAN::Atomic<dev_t> s_loopback_rdev_minor = 0;
|
||||||
|
|
||||||
|
static dev_t get_rdev(NetworkInterface::Type type)
|
||||||
{
|
{
|
||||||
static dev_t minor = 0;
|
switch (type)
|
||||||
return minor++;
|
{
|
||||||
|
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)
|
: CharacterDevice(0400, 0, 0)
|
||||||
, m_type(Type::Ethernet)
|
, m_type(type)
|
||||||
, m_rdev(makedev(DeviceNumber::Ethernet, get_network_rdev_minor()))
|
, m_rdev(get_rdev(type))
|
||||||
{
|
{
|
||||||
ASSERT(minor(m_rdev) < 10);
|
ASSERT(minor(m_rdev) < 10);
|
||||||
ASSERT(m_type == Type::Ethernet);
|
|
||||||
|
|
||||||
strcpy(m_name, "ethx");
|
switch (type)
|
||||||
m_name[3] = minor(m_rdev) + '0';
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <kernel/Networking/E1000/E1000.h>
|
#include <kernel/Networking/E1000/E1000.h>
|
||||||
#include <kernel/Networking/E1000/E1000E.h>
|
#include <kernel/Networking/E1000/E1000E.h>
|
||||||
#include <kernel/Networking/ICMP.h>
|
#include <kernel/Networking/ICMP.h>
|
||||||
|
#include <kernel/Networking/Loopback.h>
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/Networking/RTL8169/RTL8169.h>
|
#include <kernel/Networking/RTL8169/RTL8169.h>
|
||||||
#include <kernel/Networking/TCPSocket.h>
|
#include <kernel/Networking/TCPSocket.h>
|
||||||
|
@ -19,6 +20,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
ASSERT(!s_instance);
|
ASSERT(!s_instance);
|
||||||
auto manager = TRY(BAN::UniqPtr<NetworkManager>::create());
|
auto manager = TRY(BAN::UniqPtr<NetworkManager>::create());
|
||||||
|
TRY(manager->add_interface(TRY(LoopbackInterface::create())));
|
||||||
manager->m_ipv4_layer = TRY(IPv4Layer::create());
|
manager->m_ipv4_layer = TRY(IPv4Layer::create());
|
||||||
s_instance = BAN::move(manager);
|
s_instance = BAN::move(manager);
|
||||||
return {};
|
return {};
|
||||||
|
@ -62,9 +64,13 @@ namespace Kernel
|
||||||
|
|
||||||
ASSERT(interface);
|
ASSERT(interface);
|
||||||
|
|
||||||
|
return add_interface(interface);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> NetworkManager::add_interface(BAN::RefPtr<NetworkInterface> interface)
|
||||||
|
{
|
||||||
TRY(m_interfaces.push_back(interface));
|
TRY(m_interfaces.push_back(interface));
|
||||||
DevFileSystem::get().add_device(interface);
|
DevFileSystem::get().add_device(interface);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue