From 649e9f4500af95d6e500b62743bf859d0ee71026 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sat, 3 Feb 2024 18:04:12 +0200 Subject: [PATCH] Kernel: ARP now replies to requests --- kernel/include/kernel/Networking/ARPTable.h | 33 +++- .../kernel/Networking/NetworkManager.h | 2 +- kernel/kernel/Networking/ARPTable.cpp | 169 +++++++++++++----- kernel/kernel/Networking/E1000/E1000.cpp | 2 +- kernel/kernel/Networking/NetworkManager.cpp | 4 +- 5 files changed, 154 insertions(+), 56 deletions(-) diff --git a/kernel/include/kernel/Networking/ARPTable.h b/kernel/include/kernel/Networking/ARPTable.h index 63f81fff63..499bbd393d 100644 --- a/kernel/include/kernel/Networking/ARPTable.h +++ b/kernel/include/kernel/Networking/ARPTable.h @@ -1,12 +1,29 @@ #pragma once +#include #include #include #include +#include +#include namespace Kernel { + struct ARPPacket + { + BAN::NetworkEndian htype { 0 }; + BAN::NetworkEndian ptype { 0 }; + BAN::NetworkEndian hlen { 0 }; + BAN::NetworkEndian plen { 0 }; + BAN::NetworkEndian oper { 0 }; + BAN::MACAddress sha { 0, 0, 0, 0, 0, 0 }; + BAN::IPv4Address spa { 0 }; + BAN::MACAddress tha { 0, 0, 0, 0, 0, 0 }; + BAN::IPv4Address tpa { 0 }; + }; + static_assert(sizeof(ARPPacket) == 28); + class ARPTable { BAN_NON_COPYABLE(ARPTable); @@ -17,16 +34,19 @@ namespace Kernel BAN::ErrorOr get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address); - void handle_arp_packet(BAN::ConstByteSpan); + void add_arp_packet(NetworkInterface&, BAN::ConstByteSpan); private: ARPTable(); + void packet_handle_task(); + BAN::ErrorOr handle_arp_packet(NetworkInterface&, const ARPPacket&); + private: - struct ARPReply + struct PendingArpPacket { - BAN::IPv4Address ipv4_address { 0 }; - BAN::MACAddress mac_address; + NetworkInterface& interface; + ARPPacket packet; }; private: @@ -34,8 +54,9 @@ namespace Kernel BAN::HashMap m_arp_table; - BAN::Atomic m_has_got_reply; - ARPReply m_reply; + Process* m_process = nullptr; + BAN::CircularQueue m_pending_packets; + Semaphore m_pending_semaphore; friend class BAN::UniqPtr; }; diff --git a/kernel/include/kernel/Networking/NetworkManager.h b/kernel/include/kernel/Networking/NetworkManager.h index 6d05f71726..1477406738 100644 --- a/kernel/include/kernel/Networking/NetworkManager.h +++ b/kernel/include/kernel/Networking/NetworkManager.h @@ -38,7 +38,7 @@ namespace Kernel BAN::ErrorOr> create_socket(SocketType, mode_t, uid_t, gid_t); - void on_receive(BAN::ConstByteSpan); + void on_receive(NetworkInterface&, BAN::ConstByteSpan); private: NetworkManager(); diff --git a/kernel/kernel/Networking/ARPTable.cpp b/kernel/kernel/Networking/ARPTable.cpp index 8d6b47ba1c..ff9cdc4d6d 100644 --- a/kernel/kernel/Networking/ARPTable.cpp +++ b/kernel/kernel/Networking/ARPTable.cpp @@ -5,20 +5,6 @@ namespace Kernel { - struct ARPPacket - { - BAN::NetworkEndian htype; - BAN::NetworkEndian ptype; - BAN::NetworkEndian hlen; - BAN::NetworkEndian plen; - BAN::NetworkEndian oper; - BAN::MACAddress sha; - BAN::IPv4Address spa; - BAN::MACAddress tha; - BAN::IPv4Address tpa; - }; - static_assert(sizeof(ARPPacket) == 28); - enum ARPOperation : uint16_t { Request = 1, @@ -30,22 +16,31 @@ namespace Kernel BAN::ErrorOr> ARPTable::create() { - return TRY(BAN::UniqPtr::create()); + auto arp_table = TRY(BAN::UniqPtr::create()); + arp_table->m_process = Process::create_kernel( + [](void* arp_table_ptr) + { + auto& arp_table = *reinterpret_cast(arp_table_ptr); + arp_table.packet_handle_task(); + }, arp_table.ptr() + ); + ASSERT(arp_table->m_process); + return arp_table; } ARPTable::ARPTable() { - } BAN::ErrorOr ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address) { - LockGuard _(m_lock); - - if (ipv4_address == s_broadcast_ipv4) - return s_broadcast_mac; - if (m_arp_table.contains(ipv4_address)) - return m_arp_table[ipv4_address]; + { + LockGuard _(m_lock); + if (ipv4_address == s_broadcast_ipv4) + return s_broadcast_mac; + if (m_arp_table.contains(ipv4_address)) + return m_arp_table[ipv4_address]; + } BAN::Vector full_packet_buffer; TRY(full_packet_buffer.resize(sizeof(ARPPacket) + sizeof(EthernetHeader))); @@ -70,39 +65,121 @@ namespace Kernel 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); + while (SystemTimer::get().ms_since_boot() < timeout) + { + { + LockGuard _(m_lock); + if (m_arp_table.contains(ipv4_address)) + return m_arp_table[ipv4_address]; + } + TRY(Thread::current().block_or_eintr(m_pending_semaphore)); + } - 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; + return BAN::Error::from_errno(EINVAL); } - void ARPTable::handle_arp_packet(BAN::ConstByteSpan buffer) + BAN::ErrorOr ARPTable::handle_arp_packet(NetworkInterface& interface, const ARPPacket& packet) + { + if (packet.ptype != EtherType::IPv4) + { + dprintln("Non IPv4 arp packet?"); + return {}; + } + + switch (packet.oper) + { + case ARPOperation::Request: + { + if (packet.tpa == interface.get_ipv4_address()) + { + BAN::Vector 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(); + ethernet_header.dst_mac = packet.sha; + ethernet_header.src_mac = interface.get_mac_address(); + ethernet_header.ether_type = EtherType::ARP; + + auto& arp_request = full_packet.slice(sizeof(EthernetHeader)).as(); + arp_request.htype = 0x0001; + arp_request.ptype = EtherType::IPv4; + arp_request.hlen = 0x06; + arp_request.plen = 0x04; + arp_request.oper = ARPOperation::Reply; + arp_request.sha = interface.get_mac_address(); + arp_request.spa = interface.get_ipv4_address(); + arp_request.tha = packet.sha; + arp_request.tpa = packet.spa; + + TRY(interface.send_raw_bytes(full_packet)); + } + break; + } + case ARPOperation::Reply: + { + LockGuard _(m_lock); + if (m_arp_table.contains(packet.spa)) + { + if (m_arp_table[packet.spa] != packet.sha) + { + dprintln("Update IPv4 {} MAC to {}", packet.spa, packet.sha); + m_arp_table[packet.spa] = packet.sha; + } + } + else + { + TRY(m_arp_table.insert(packet.spa, packet.sha)); + dprintln("Assign IPv4 {} MAC to {}", packet.spa, packet.sha); + } + break; + } + default: + dprintln("Unhandled ARP packet (oper {4H})", (uint16_t)packet.oper); + break; + } + + return {}; + } + + void ARPTable::packet_handle_task() + { + for (;;) + { + BAN::Optional pending; + + { + CriticalScope _; + if (!m_pending_packets.empty()) + { + pending = m_pending_packets.front(); + m_pending_packets.pop(); + } + } + + if (!pending.has_value()) + { + m_pending_semaphore.block(); + continue; + } + + if (auto ret = handle_arp_packet(pending->interface, pending->packet); ret.is_error()) + dwarnln("{}", ret.error()); + } + } + + void ARPTable::add_arp_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer) { auto& arp_packet = buffer.as(); - if (arp_packet.oper != ARPOperation::Reply) + + if (m_pending_packets.full()) { - dprintln("Unhandled non-rely ARP packet (operation {2H})", (uint16_t)arp_packet.oper); + dprintln("arp packet queue full"); 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; + m_pending_packets.push({ .interface = interface, .packet = arp_packet }); + m_pending_semaphore.unblock(); } } diff --git a/kernel/kernel/Networking/E1000/E1000.cpp b/kernel/kernel/Networking/E1000/E1000.cpp index 4e0732df34..4f5fb1076c 100644 --- a/kernel/kernel/Networking/E1000/E1000.cpp +++ b/kernel/kernel/Networking/E1000/E1000.cpp @@ -292,7 +292,7 @@ namespace Kernel break; ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE); - NetworkManager::get().on_receive(BAN::ConstByteSpan { + NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { reinterpret_cast(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE), descriptor.length }); diff --git a/kernel/kernel/Networking/NetworkManager.cpp b/kernel/kernel/Networking/NetworkManager.cpp index c081666e0d..00ab0c023d 100644 --- a/kernel/kernel/Networking/NetworkManager.cpp +++ b/kernel/kernel/Networking/NetworkManager.cpp @@ -109,7 +109,7 @@ namespace Kernel return {}; } - void NetworkManager::on_receive(BAN::ConstByteSpan packet) + void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet) { auto ethernet_header = packet.as(); @@ -117,7 +117,7 @@ namespace Kernel { case EtherType::ARP: { - m_arp_table->handle_arp_packet(packet.slice(sizeof(EthernetHeader))); + m_arp_table->add_arp_packet(interface, packet.slice(sizeof(EthernetHeader))); break; } case EtherType::IPv4: