Kernel: Cleanup network code and implement basic ARP request
This commit is contained in:
parent
a0138955cd
commit
5cfe249945
|
@ -1,9 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/HashMap.h>
|
#include <BAN/HashMap.h>
|
||||||
#include <BAN/IPv4.h>
|
|
||||||
#include <BAN/MAC.h>
|
|
||||||
#include <BAN/UniqPtr.h>
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -16,14 +15,28 @@ namespace Kernel
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create();
|
static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create();
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(BAN::IPv4Address);
|
BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address);
|
||||||
|
|
||||||
|
void handle_arp_packet(BAN::ConstByteSpan);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ARPTable();
|
ARPTable();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ARPReply
|
||||||
|
{
|
||||||
|
BAN::IPv4Address ipv4_address { 0 };
|
||||||
|
BAN::MACAddress mac_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpinLock m_lock;
|
||||||
|
|
||||||
BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table;
|
BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table;
|
||||||
|
|
||||||
|
BAN::Atomic<bool> m_has_got_reply;
|
||||||
|
ARPReply m_reply;
|
||||||
|
|
||||||
friend class BAN::UniqPtr<ARPTable>;
|
friend class BAN::UniqPtr<ARPTable>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,20 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct EthernetHeader
|
||||||
|
{
|
||||||
|
BAN::MACAddress dst_mac;
|
||||||
|
BAN::MACAddress src_mac;
|
||||||
|
BAN::NetworkEndian<uint16_t> ether_type;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(EthernetHeader) == 14);
|
||||||
|
|
||||||
|
enum EtherType : uint16_t
|
||||||
|
{
|
||||||
|
IPv4 = 0x0800,
|
||||||
|
ARP = 0x0806,
|
||||||
|
};
|
||||||
|
|
||||||
class NetworkInterface : public CharacterDevice
|
class NetworkInterface : public CharacterDevice
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(NetworkInterface);
|
BAN_NON_COPYABLE(NetworkInterface);
|
||||||
|
|
|
@ -9,6 +9,11 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
enum NetworkProtocol : uint8_t
|
||||||
|
{
|
||||||
|
UDP = 0x11,
|
||||||
|
};
|
||||||
|
|
||||||
class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
|
class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(NetworkSocket);
|
BAN_NON_COPYABLE(NetworkSocket);
|
||||||
|
@ -23,7 +28,7 @@ namespace Kernel
|
||||||
|
|
||||||
virtual size_t protocol_header_size() const = 0;
|
virtual size_t protocol_header_size() const = 0;
|
||||||
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port) = 0;
|
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port) = 0;
|
||||||
virtual uint8_t protocol() const = 0;
|
virtual NetworkProtocol protocol() const = 0;
|
||||||
|
|
||||||
virtual void add_packet(BAN::ConstByteSpan, BAN::IPv4Address sender_address, uint16_t sender_port) = 0;
|
virtual void add_packet(BAN::ConstByteSpan, BAN::IPv4Address sender_address, uint16_t sender_port) = 0;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Kernel
|
||||||
|
|
||||||
virtual size_t protocol_header_size() const override { return sizeof(UDPHeader); }
|
virtual size_t protocol_header_size() const override { return sizeof(UDPHeader); }
|
||||||
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port) override;
|
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port) override;
|
||||||
virtual uint8_t protocol() const override { return 0x11; }
|
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void add_packet(BAN::ConstByteSpan, BAN::IPv4Address sender_addr, uint16_t sender_port) override;
|
virtual void add_packet(BAN::ConstByteSpan, BAN::IPv4Address sender_addr, uint16_t sender_port) override;
|
||||||
|
|
|
@ -1,8 +1,30 @@
|
||||||
|
#include <kernel/LockGuard.h>
|
||||||
#include <kernel/Networking/ARPTable.h>
|
#include <kernel/Networking/ARPTable.h>
|
||||||
|
#include <kernel/Timer/Timer.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct ARPPacket
|
||||||
|
{
|
||||||
|
BAN::NetworkEndian<uint16_t> htype;
|
||||||
|
BAN::NetworkEndian<uint16_t> ptype;
|
||||||
|
BAN::NetworkEndian<uint8_t> hlen;
|
||||||
|
BAN::NetworkEndian<uint8_t> plen;
|
||||||
|
BAN::NetworkEndian<uint16_t> oper;
|
||||||
|
BAN::MACAddress sha;
|
||||||
|
BAN::IPv4Address spa;
|
||||||
|
BAN::MACAddress tha;
|
||||||
|
BAN::IPv4Address tpa;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ARPPacket) == 28);
|
||||||
|
|
||||||
|
enum ARPOperation : uint16_t
|
||||||
|
{
|
||||||
|
Request = 1,
|
||||||
|
Reply = 2,
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr BAN::IPv4Address s_broadcast_ipv4 { 0xFFFFFFFF };
|
static constexpr BAN::IPv4Address s_broadcast_ipv4 { 0xFFFFFFFF };
|
||||||
static constexpr BAN::MACAddress s_broadcast_mac {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
|
static constexpr BAN::MACAddress s_broadcast_mac {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
|
||||||
|
|
||||||
|
@ -16,12 +38,71 @@ namespace Kernel
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(BAN::IPv4Address ipv4_address)
|
BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address)
|
||||||
{
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
if (ipv4_address == s_broadcast_ipv4)
|
if (ipv4_address == s_broadcast_ipv4)
|
||||||
return s_broadcast_mac;
|
return s_broadcast_mac;
|
||||||
dprintln("No MAC for IPv4 {}", ipv4_address);
|
if (m_arp_table.contains(ipv4_address))
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return m_arp_table[ipv4_address];
|
||||||
|
|
||||||
|
BAN::Vector<uint8_t> full_packet_buffer;
|
||||||
|
TRY(full_packet_buffer.resize(sizeof(ARPPacket) + sizeof(EthernetHeader)));
|
||||||
|
auto full_packet = BAN::ByteSpan { full_packet_buffer.span() };
|
||||||
|
|
||||||
|
auto& ethernet_header = full_packet.as<EthernetHeader>();
|
||||||
|
ethernet_header.dst_mac = s_broadcast_mac;
|
||||||
|
ethernet_header.src_mac = interface.get_mac_address();
|
||||||
|
ethernet_header.ether_type = EtherType::ARP;
|
||||||
|
|
||||||
|
auto& arp_request = full_packet.slice(sizeof(EthernetHeader)).as<ARPPacket>();
|
||||||
|
arp_request.htype = 0x0001;
|
||||||
|
arp_request.ptype = EtherType::IPv4;
|
||||||
|
arp_request.hlen = 0x06;
|
||||||
|
arp_request.plen = 0x04;
|
||||||
|
arp_request.oper = ARPOperation::Request;
|
||||||
|
arp_request.sha = interface.get_mac_address();
|
||||||
|
arp_request.spa = interface.get_ipv4_address();
|
||||||
|
arp_request.tha = {{ 0, 0, 0, 0, 0, 0 }};
|
||||||
|
arp_request.tpa = ipv4_address;
|
||||||
|
|
||||||
|
TRY(interface.send_raw_bytes(full_packet));
|
||||||
|
|
||||||
|
uint64_t timeout = SystemTimer::get().ms_since_boot() + 5'000;
|
||||||
|
while (!m_has_got_reply)
|
||||||
|
if (SystemTimer::get().ms_since_boot() >= timeout)
|
||||||
|
return BAN::Error::from_errno(ETIMEDOUT);
|
||||||
|
ASSERT_EQ(m_reply.ipv4_address, ipv4_address);
|
||||||
|
|
||||||
|
BAN::MACAddress mac_address = m_reply.mac_address;
|
||||||
|
(void)m_arp_table.insert(ipv4_address, m_reply.mac_address);
|
||||||
|
m_has_got_reply = false;
|
||||||
|
|
||||||
|
dprintln("IPv4 {} resolved to MAC {}", ipv4_address, mac_address);
|
||||||
|
|
||||||
|
return mac_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ARPTable::handle_arp_packet(BAN::ConstByteSpan buffer)
|
||||||
|
{
|
||||||
|
auto& arp_packet = buffer.as<const ARPPacket>();
|
||||||
|
if (arp_packet.oper != ARPOperation::Reply)
|
||||||
|
{
|
||||||
|
dprintln("Unhandled non-rely ARP packet (operation {2H})", (uint16_t)arp_packet.oper);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arp_packet.ptype != EtherType::IPv4)
|
||||||
|
{
|
||||||
|
dprintln("Unhandled non-ipv4 ARP packet (ptype {2H})", (uint16_t)arp_packet.ptype);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(!m_has_got_reply);
|
||||||
|
m_has_got_reply = true;
|
||||||
|
m_reply.ipv4_address = arp_packet.spa;
|
||||||
|
m_reply.mac_address = arp_packet.sha;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,6 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
struct EthernetHeader
|
|
||||||
{
|
|
||||||
BAN::MACAddress dst_mac;
|
|
||||||
BAN::MACAddress src_mac;
|
|
||||||
BAN::NetworkEndian<uint16_t> ether_type;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(EthernetHeader) == 14);
|
|
||||||
|
|
||||||
static dev_t get_network_rdev_major()
|
static dev_t get_network_rdev_major()
|
||||||
{
|
{
|
||||||
static dev_t major = DevFileSystem::get().get_next_dev();
|
static dev_t major = DevFileSystem::get().get_next_dev();
|
||||||
|
|
|
@ -111,25 +111,49 @@ namespace Kernel
|
||||||
|
|
||||||
void NetworkManager::on_receive(BAN::ConstByteSpan packet)
|
void NetworkManager::on_receive(BAN::ConstByteSpan packet)
|
||||||
{
|
{
|
||||||
// FIXME: properly handle packet parsing
|
auto ethernet_header = packet.as<const EthernetHeader>();
|
||||||
|
|
||||||
auto ipv4 = packet.slice(14);
|
switch (ethernet_header.ether_type)
|
||||||
auto& ipv4_header = ipv4.as<const IPv4Header>();
|
|
||||||
auto src_ipv4 = ipv4_header.src_address;
|
|
||||||
|
|
||||||
auto udp = ipv4.slice(20);
|
|
||||||
auto& udp_header = udp.as<const UDPHeader>();
|
|
||||||
uint16_t src_port = udp_header.src_port;
|
|
||||||
uint16_t dst_port = udp_header.dst_port;
|
|
||||||
|
|
||||||
if (!m_bound_sockets.contains(dst_port))
|
|
||||||
{
|
{
|
||||||
dprintln("no one is listening on port {}", dst_port);
|
case EtherType::ARP:
|
||||||
return;
|
{
|
||||||
}
|
m_arp_table->handle_arp_packet(packet.slice(sizeof(EthernetHeader)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EtherType::IPv4:
|
||||||
|
{
|
||||||
|
auto ipv4 = packet.slice(sizeof(EthernetHeader));
|
||||||
|
auto& ipv4_header = ipv4.as<const IPv4Header>();
|
||||||
|
auto src_ipv4 = ipv4_header.src_address;
|
||||||
|
switch (ipv4_header.protocol)
|
||||||
|
{
|
||||||
|
case NetworkProtocol::UDP:
|
||||||
|
{
|
||||||
|
auto udp = ipv4.slice(sizeof(IPv4Header));
|
||||||
|
auto& udp_header = udp.as<const UDPHeader>();
|
||||||
|
uint16_t src_port = udp_header.src_port;
|
||||||
|
uint16_t dst_port = udp_header.dst_port;
|
||||||
|
|
||||||
auto raw = udp.slice(8);
|
if (!m_bound_sockets.contains(dst_port))
|
||||||
m_bound_sockets[dst_port].lock()->add_packet(raw, src_ipv4, src_port);
|
{
|
||||||
|
dprintln("no one is listening on port {}", dst_port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto raw = udp.slice(8);
|
||||||
|
m_bound_sockets[dst_port].lock()->add_packet(raw, src_ipv4, src_port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dprintln("Unknown network protocol 0x{2H}", ipv4_header.protocol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dprintln("Unknown EtherType 0x{4H}", (uint16_t)ethernet_header.ether_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
auto dst_addr = BAN::IPv4Address(destination->sin_addr.s_addr);
|
auto dst_addr = BAN::IPv4Address(destination->sin_addr.s_addr);
|
||||||
auto dst_mac = TRY(NetworkManager::get().arp_table().get_mac_from_ipv4(dst_addr));
|
auto dst_mac = TRY(NetworkManager::get().arp_table().get_mac_from_ipv4(*m_interface, dst_addr));
|
||||||
|
|
||||||
const size_t interface_header_offset = 0;
|
const size_t interface_header_offset = 0;
|
||||||
const size_t interface_header_size = m_interface->interface_header_size();
|
const size_t interface_header_size = m_interface->interface_header_size();
|
||||||
|
|
Loading…
Reference in New Issue