Kernel: Cleanup network code and implement basic ARP request
This commit is contained in:
		
							parent
							
								
									a0138955cd
								
							
						
					
					
						commit
						5cfe249945
					
				|  | @ -1,9 +1,8 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/HashMap.h> | ||||
| #include <BAN/IPv4.h> | ||||
| #include <BAN/MAC.h> | ||||
| #include <BAN/UniqPtr.h> | ||||
| #include <kernel/Networking/NetworkInterface.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
|  | @ -16,14 +15,28 @@ namespace Kernel | |||
| 	public: | ||||
| 		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: | ||||
| 		ARPTable(); | ||||
| 
 | ||||
| 	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::Atomic<bool>	m_has_got_reply; | ||||
| 		ARPReply			m_reply; | ||||
| 
 | ||||
| 		friend class BAN::UniqPtr<ARPTable>; | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,20 @@ | |||
| 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 | ||||
| 	{ | ||||
| 		BAN_NON_COPYABLE(NetworkInterface); | ||||
|  |  | |||
|  | @ -9,6 +9,11 @@ | |||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	enum NetworkProtocol : uint8_t | ||||
| 	{ | ||||
| 		UDP = 0x11, | ||||
| 	}; | ||||
| 
 | ||||
| 	class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket> | ||||
| 	{ | ||||
| 		BAN_NON_COPYABLE(NetworkSocket); | ||||
|  | @ -23,7 +28,7 @@ namespace Kernel | |||
| 
 | ||||
| 		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 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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,7 +26,7 @@ namespace Kernel | |||
| 
 | ||||
| 		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 uint8_t protocol() const override { return 0x11; } | ||||
| 		virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; } | ||||
| 
 | ||||
| 	protected: | ||||
| 		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/Timer/Timer.h> | ||||
| 
 | ||||
| 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::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) | ||||
| 			return s_broadcast_mac; | ||||
| 		dprintln("No MAC for IPv4 {}", ipv4_address); | ||||
| 		return BAN::Error::from_errno(ENOTSUP); | ||||
| 		if (m_arp_table.contains(ipv4_address)) | ||||
| 			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 | ||||
| { | ||||
| 
 | ||||
| 	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 major = DevFileSystem::get().get_next_dev(); | ||||
|  |  | |||
|  | @ -111,13 +111,25 @@ namespace Kernel | |||
| 
 | ||||
| 	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) | ||||
| 		{ | ||||
| 			case EtherType::ARP: | ||||
| 			{ | ||||
| 				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; | ||||
| 
 | ||||
| 		auto udp = ipv4.slice(20); | ||||
| 				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; | ||||
|  | @ -130,6 +142,18 @@ namespace Kernel | |||
| 
 | ||||
| 						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); | ||||
| 
 | ||||
| 		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_size		= m_interface->interface_header_size(); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue