Compare commits

..

No commits in common. "79897e77dcb7d19aded77b5a2760cc87216cd329" and "2138eeb87f0c018826f60a014f177f9253197ae9" have entirely different histories.

7 changed files with 73 additions and 165 deletions

View File

@ -8,17 +8,6 @@ namespace BAN
struct MACAddress struct MACAddress
{ {
uint8_t address[6]; uint8_t address[6];
constexpr bool operator==(const MACAddress& other) const
{
return
address[0] == other.address[0] &&
address[1] == other.address[1] &&
address[2] == other.address[2] &&
address[3] == other.address[3] &&
address[4] == other.address[4] &&
address[5] == other.address[5];
}
}; };
} }

View File

@ -1,29 +1,12 @@
#pragma once #pragma once
#include <BAN/CircularQueue.h>
#include <BAN/HashMap.h> #include <BAN/HashMap.h>
#include <BAN/UniqPtr.h> #include <BAN/UniqPtr.h>
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
#include <kernel/Process.h>
#include <kernel/Semaphore.h>
namespace Kernel namespace Kernel
{ {
struct ARPPacket
{
BAN::NetworkEndian<uint16_t> htype { 0 };
BAN::NetworkEndian<uint16_t> ptype { 0 };
BAN::NetworkEndian<uint8_t> hlen { 0 };
BAN::NetworkEndian<uint8_t> plen { 0 };
BAN::NetworkEndian<uint16_t> 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 class ARPTable
{ {
BAN_NON_COPYABLE(ARPTable); BAN_NON_COPYABLE(ARPTable);
@ -34,19 +17,16 @@ namespace Kernel
BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address); BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address);
void add_arp_packet(NetworkInterface&, BAN::ConstByteSpan); void handle_arp_packet(BAN::ConstByteSpan);
private: private:
ARPTable(); ARPTable();
void packet_handle_task();
BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, const ARPPacket&);
private: private:
struct PendingArpPacket struct ARPReply
{ {
NetworkInterface& interface; BAN::IPv4Address ipv4_address { 0 };
ARPPacket packet; BAN::MACAddress mac_address;
}; };
private: private:
@ -54,9 +34,8 @@ namespace Kernel
BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table; BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table;
Process* m_process = nullptr; BAN::Atomic<bool> m_has_got_reply;
BAN::CircularQueue<PendingArpPacket, 128> m_pending_packets; ARPReply m_reply;
Semaphore m_pending_semaphore;
friend class BAN::UniqPtr<ARPTable>; friend class BAN::UniqPtr<ARPTable>;
}; };

View File

@ -38,7 +38,7 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> create_socket(SocketType, mode_t, uid_t, gid_t); BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> create_socket(SocketType, mode_t, uid_t, gid_t);
void on_receive(NetworkInterface&, BAN::ConstByteSpan); void on_receive(BAN::ConstByteSpan);
private: private:
NetworkManager(); NetworkManager();

View File

@ -5,6 +5,20 @@
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 enum ARPOperation : uint16_t
{ {
Request = 1, Request = 1,
@ -16,31 +30,22 @@ namespace Kernel
BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create() BAN::ErrorOr<BAN::UniqPtr<ARPTable>> ARPTable::create()
{ {
auto arp_table = TRY(BAN::UniqPtr<ARPTable>::create()); return TRY(BAN::UniqPtr<ARPTable>::create());
arp_table->m_process = Process::create_kernel(
[](void* arp_table_ptr)
{
auto& arp_table = *reinterpret_cast<ARPTable*>(arp_table_ptr);
arp_table.packet_handle_task();
}, arp_table.ptr()
);
ASSERT(arp_table->m_process);
return arp_table;
} }
ARPTable::ARPTable() ARPTable::ARPTable()
{ {
} }
BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address) BAN::ErrorOr<BAN::MACAddress> ARPTable::get_mac_from_ipv4(NetworkInterface& interface, BAN::IPv4Address ipv4_address)
{
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
if (ipv4_address == s_broadcast_ipv4) if (ipv4_address == s_broadcast_ipv4)
return s_broadcast_mac; return s_broadcast_mac;
if (m_arp_table.contains(ipv4_address)) if (m_arp_table.contains(ipv4_address))
return m_arp_table[ipv4_address]; return m_arp_table[ipv4_address];
}
BAN::Vector<uint8_t> full_packet_buffer; BAN::Vector<uint8_t> full_packet_buffer;
TRY(full_packet_buffer.resize(sizeof(ARPPacket) + sizeof(EthernetHeader))); TRY(full_packet_buffer.resize(sizeof(ARPPacket) + sizeof(EthernetHeader)));
@ -65,121 +70,39 @@ namespace Kernel
TRY(interface.send_raw_bytes(full_packet)); TRY(interface.send_raw_bytes(full_packet));
uint64_t timeout = SystemTimer::get().ms_since_boot() + 5'000; uint64_t timeout = SystemTimer::get().ms_since_boot() + 5'000;
while (SystemTimer::get().ms_since_boot() < timeout) while (!m_has_got_reply)
{ if (SystemTimer::get().ms_since_boot() >= timeout)
{ return BAN::Error::from_errno(ETIMEDOUT);
LockGuard _(m_lock); ASSERT_EQ(m_reply.ipv4_address, ipv4_address);
if (m_arp_table.contains(ipv4_address))
return m_arp_table[ipv4_address]; BAN::MACAddress mac_address = m_reply.mac_address;
} (void)m_arp_table.insert(ipv4_address, m_reply.mac_address);
TRY(Thread::current().block_or_eintr(m_pending_semaphore)); 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<void> 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<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 = 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<ARPPacket>();
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<PendingArpPacket> 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<const ARPPacket>(); auto& arp_packet = buffer.as<const ARPPacket>();
if (arp_packet.oper != ARPOperation::Reply)
if (m_pending_packets.full())
{ {
dprintln("arp packet queue full"); dprintln("Unhandled non-rely ARP packet (operation {2H})", (uint16_t)arp_packet.oper);
return; return;
} }
m_pending_packets.push({ .interface = interface, .packet = arp_packet }); if (arp_packet.ptype != EtherType::IPv4)
m_pending_semaphore.unblock(); {
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;
} }
} }

View File

@ -292,7 +292,7 @@ namespace Kernel
break; break;
ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE); ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan { NetworkManager::get().on_receive(BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE), reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),
descriptor.length descriptor.length
}); });

View File

@ -109,7 +109,7 @@ namespace Kernel
return {}; return {};
} }
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet) void NetworkManager::on_receive(BAN::ConstByteSpan packet)
{ {
auto ethernet_header = packet.as<const EthernetHeader>(); auto ethernet_header = packet.as<const EthernetHeader>();
@ -117,7 +117,7 @@ namespace Kernel
{ {
case EtherType::ARP: case EtherType::ARP:
{ {
m_arp_table->add_arp_packet(interface, packet.slice(sizeof(EthernetHeader))); m_arp_table->handle_arp_packet(packet.slice(sizeof(EthernetHeader)));
break; break;
} }
case EtherType::IPv4: case EtherType::IPv4:

View File

@ -357,6 +357,23 @@ int main()
update_ipv4_info(socket, dhcp_ack->address, dhcp_ack->subnet); update_ipv4_info(socket, dhcp_ack->address, dhcp_ack->subnet);
if (true)
{
uint32_t packet = 0x12345678;
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = 67;
server_addr.sin_addr.s_addr = dhcp_ack->routers.front().as_u32();
server_addr.sin_addr.s_addr = (192 << 24) | (168 << 16) | (1 << 8) | 203;
if (sendto(socket, &packet, sizeof(packet), 0, (sockaddr*)&server_addr, sizeof(server_addr)) == -1)
{
perror("sendto");
exit(1);
}
}
close(socket); close(socket);
return 0; return 0;