forked from Bananymous/banan-os
Kernel: Make better abstractions for networking
This commit is contained in:
parent
f804e87f7d
commit
5da59c9151
|
@ -53,7 +53,7 @@ set(KERNEL_SOURCES
|
||||||
kernel/Networking/ARPTable.cpp
|
kernel/Networking/ARPTable.cpp
|
||||||
kernel/Networking/E1000/E1000.cpp
|
kernel/Networking/E1000/E1000.cpp
|
||||||
kernel/Networking/E1000/E1000E.cpp
|
kernel/Networking/E1000/E1000E.cpp
|
||||||
kernel/Networking/IPv4.cpp
|
kernel/Networking/IPv4Layer.cpp
|
||||||
kernel/Networking/NetworkInterface.cpp
|
kernel/Networking/NetworkInterface.cpp
|
||||||
kernel/Networking/NetworkManager.cpp
|
kernel/Networking/NetworkManager.cpp
|
||||||
kernel/Networking/NetworkSocket.cpp
|
kernel/Networking/NetworkSocket.cpp
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace Kernel
|
||||||
uint32_t read32(uint16_t reg);
|
uint32_t read32(uint16_t reg);
|
||||||
void write32(uint16_t reg, uint32_t value);
|
void write32(uint16_t reg, uint32_t value);
|
||||||
|
|
||||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) override;
|
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::ErrorOr<void> read_mac_address();
|
BAN::ErrorOr<void> read_mac_address();
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
struct ICMPHeader
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t code;
|
||||||
|
BAN::NetworkEndian<uint16_t> checksum;
|
||||||
|
BAN::NetworkEndian<uint32_t> rest;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ICMPHeader) == 8);
|
||||||
|
|
||||||
|
enum ICMPType : uint8_t
|
||||||
|
{
|
||||||
|
EchoReply = 0x00,
|
||||||
|
EchoRequest = 0x08,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <BAN/ByteSpan.h>
|
|
||||||
#include <BAN/Endianness.h>
|
|
||||||
#include <BAN/IPv4.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
struct IPv4Header
|
|
||||||
{
|
|
||||||
uint8_t version_IHL;
|
|
||||||
uint8_t DSCP_ECN;
|
|
||||||
BAN::NetworkEndian<uint16_t> total_length { 0 };
|
|
||||||
BAN::NetworkEndian<uint16_t> identification { 0 };
|
|
||||||
BAN::NetworkEndian<uint16_t> flags_frament { 0 };
|
|
||||||
uint8_t time_to_live;
|
|
||||||
uint8_t protocol;
|
|
||||||
BAN::NetworkEndian<uint16_t> checksum { 0 };
|
|
||||||
BAN::IPv4Address src_address;
|
|
||||||
BAN::IPv4Address dst_address;
|
|
||||||
|
|
||||||
constexpr uint16_t calculate_checksum() const
|
|
||||||
{
|
|
||||||
uint32_t total_sum = 0;
|
|
||||||
for (size_t i = 0; i < sizeof(IPv4Header) / sizeof(uint16_t); i++)
|
|
||||||
total_sum += reinterpret_cast<const BAN::NetworkEndian<uint16_t>*>(this)[i];
|
|
||||||
total_sum -= checksum;
|
|
||||||
while (total_sum >> 16)
|
|
||||||
total_sum = (total_sum >> 16) + (total_sum & 0xFFFF);
|
|
||||||
return ~(uint16_t)total_sum;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(IPv4Header) == 20);
|
|
||||||
|
|
||||||
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol);
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/CircularQueue.h>
|
||||||
|
#include <BAN/Endianness.h>
|
||||||
|
#include <BAN/IPv4.h>
|
||||||
|
#include <BAN/NoCopyMove.h>
|
||||||
|
#include <BAN/UniqPtr.h>
|
||||||
|
#include <kernel/Networking/ARPTable.h>
|
||||||
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
#include <kernel/Networking/NetworkLayer.h>
|
||||||
|
#include <kernel/Networking/NetworkSocket.h>
|
||||||
|
#include <kernel/Process.h>
|
||||||
|
#include <kernel/SpinLock.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
struct IPv4Header
|
||||||
|
{
|
||||||
|
uint8_t version_IHL;
|
||||||
|
uint8_t DSCP_ECN;
|
||||||
|
BAN::NetworkEndian<uint16_t> total_length { 0 };
|
||||||
|
BAN::NetworkEndian<uint16_t> identification { 0 };
|
||||||
|
BAN::NetworkEndian<uint16_t> flags_frament { 0 };
|
||||||
|
uint8_t time_to_live;
|
||||||
|
uint8_t protocol;
|
||||||
|
BAN::NetworkEndian<uint16_t> checksum { 0 };
|
||||||
|
BAN::IPv4Address src_address;
|
||||||
|
BAN::IPv4Address dst_address;
|
||||||
|
|
||||||
|
constexpr uint16_t calculate_checksum() const
|
||||||
|
{
|
||||||
|
uint32_t total_sum = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(IPv4Header) / sizeof(uint16_t); i++)
|
||||||
|
total_sum += reinterpret_cast<const BAN::NetworkEndian<uint16_t>*>(this)[i];
|
||||||
|
total_sum -= checksum;
|
||||||
|
while (total_sum >> 16)
|
||||||
|
total_sum = (total_sum >> 16) + (total_sum & 0xFFFF);
|
||||||
|
return ~(uint16_t)total_sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_valid_checksum() const
|
||||||
|
{
|
||||||
|
uint32_t total_sum = 0;
|
||||||
|
for (size_t i = 0; i < sizeof(IPv4Header) / sizeof(uint16_t); i++)
|
||||||
|
total_sum += reinterpret_cast<const BAN::NetworkEndian<uint16_t>*>(this)[i];
|
||||||
|
while (total_sum >> 16)
|
||||||
|
total_sum = (total_sum >> 16) + (total_sum & 0xFFFF);
|
||||||
|
return total_sum == 0xFFFF;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IPv4Header) == 20);
|
||||||
|
|
||||||
|
class IPv4Layer : public NetworkLayer
|
||||||
|
{
|
||||||
|
BAN_NON_COPYABLE(IPv4Layer);
|
||||||
|
BAN_NON_MOVABLE(IPv4Layer);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> create();
|
||||||
|
~IPv4Layer();
|
||||||
|
|
||||||
|
ARPTable& arp_table() { return *m_arp_table; }
|
||||||
|
|
||||||
|
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
virtual void unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>) override;
|
||||||
|
virtual BAN::ErrorOr<void> bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>) override;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, const sys_sendto_t*) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IPv4Layer();
|
||||||
|
|
||||||
|
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const;
|
||||||
|
|
||||||
|
void packet_handle_task();
|
||||||
|
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PendingIPv4Packet
|
||||||
|
{
|
||||||
|
NetworkInterface& interface;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpinLock m_lock;
|
||||||
|
|
||||||
|
BAN::UniqPtr<ARPTable> m_arp_table;
|
||||||
|
Process* m_process { nullptr };
|
||||||
|
|
||||||
|
static constexpr size_t pending_packet_buffer_size = 128 * PAGE_SIZE;
|
||||||
|
BAN::UniqPtr<VirtualRange> m_pending_packet_buffer;
|
||||||
|
BAN::CircularQueue<PendingIPv4Packet, 128> m_pending_packets;
|
||||||
|
Semaphore m_pending_semaphore;
|
||||||
|
size_t m_pending_total_size { 0 };
|
||||||
|
|
||||||
|
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
|
||||||
|
|
||||||
|
friend class BAN::UniqPtr<IPv4Layer>;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Errors.h>
|
|
||||||
#include <BAN/ByteSpan.h>
|
#include <BAN/ByteSpan.h>
|
||||||
|
#include <BAN/Errors.h>
|
||||||
|
#include <BAN/IPv4.h>
|
||||||
#include <BAN/MAC.h>
|
#include <BAN/MAC.h>
|
||||||
#include <kernel/Device/Device.h>
|
#include <kernel/Device/Device.h>
|
||||||
#include <kernel/Networking/IPv4.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
@ -52,13 +52,10 @@ namespace Kernel
|
||||||
virtual bool link_up() = 0;
|
virtual bool link_up() = 0;
|
||||||
virtual int link_speed() = 0;
|
virtual int link_speed() = 0;
|
||||||
|
|
||||||
size_t interface_header_size() const;
|
|
||||||
void add_interface_header(BAN::ByteSpan packet, BAN::MACAddress destination);
|
|
||||||
|
|
||||||
virtual dev_t rdev() const override { return m_rdev; }
|
virtual dev_t rdev() const override { return m_rdev; }
|
||||||
virtual BAN::StringView name() const override { return m_name; }
|
virtual BAN::StringView name() const override { return m_name; }
|
||||||
|
|
||||||
virtual BAN::ErrorOr<void> send_raw_bytes(BAN::ConstByteSpan) = 0;
|
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Type m_type;
|
const Type m_type;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class NetworkSocket;
|
||||||
|
enum class SocketType;
|
||||||
|
|
||||||
|
class NetworkLayer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~NetworkLayer() {}
|
||||||
|
|
||||||
|
virtual void unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>) = 0;
|
||||||
|
virtual BAN::ErrorOr<void> bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>) = 0;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<size_t> sendto(NetworkSocket&, const sys_sendto_t*) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NetworkLayer() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
#include <kernel/FS/TmpFS/FileSystem.h>
|
#include <kernel/FS/TmpFS/FileSystem.h>
|
||||||
#include <kernel/Networking/ARPTable.h>
|
#include <kernel/Networking/IPv4Layer.h>
|
||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
#include <kernel/Networking/NetworkSocket.h>
|
#include <kernel/Networking/NetworkSocket.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
|
@ -17,26 +17,15 @@ namespace Kernel
|
||||||
BAN_NON_COPYABLE(NetworkManager);
|
BAN_NON_COPYABLE(NetworkManager);
|
||||||
BAN_NON_MOVABLE(NetworkManager);
|
BAN_NON_MOVABLE(NetworkManager);
|
||||||
|
|
||||||
public:
|
|
||||||
enum class SocketType
|
|
||||||
{
|
|
||||||
STREAM,
|
|
||||||
DGRAM,
|
|
||||||
SEQPACKET,
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<void> initialize();
|
static BAN::ErrorOr<void> initialize();
|
||||||
static NetworkManager& get();
|
static NetworkManager& get();
|
||||||
|
|
||||||
ARPTable& arp_table() { return *m_arp_table; }
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> add_interface(PCI::Device& pci_device);
|
BAN::ErrorOr<void> add_interface(PCI::Device& pci_device);
|
||||||
|
|
||||||
void unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>);
|
BAN::Vector<BAN::RefPtr<NetworkInterface>> interfaces() { return m_interfaces; }
|
||||||
BAN::ErrorOr<void> bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket>);
|
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> create_socket(SocketType, mode_t, uid_t, gid_t);
|
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> create_socket(SocketDomain, SocketType, mode_t, uid_t, gid_t);
|
||||||
|
|
||||||
void on_receive(NetworkInterface&, BAN::ConstByteSpan);
|
void on_receive(NetworkInterface&, BAN::ConstByteSpan);
|
||||||
|
|
||||||
|
@ -44,9 +33,8 @@ namespace Kernel
|
||||||
NetworkManager();
|
NetworkManager();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::UniqPtr<ARPTable> m_arp_table;
|
BAN::UniqPtr<IPv4Layer> m_ipv4_layer;
|
||||||
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
|
BAN::Vector<BAN::RefPtr<NetworkInterface>> m_interfaces;
|
||||||
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <BAN/WeakPtr.h>
|
#include <BAN/WeakPtr.h>
|
||||||
#include <kernel/FS/TmpFS/Inode.h>
|
#include <kernel/FS/TmpFS/Inode.h>
|
||||||
#include <kernel/Networking/NetworkInterface.h>
|
#include <kernel/Networking/NetworkInterface.h>
|
||||||
|
#include <kernel/Networking/NetworkLayer.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
@ -11,9 +12,24 @@ namespace Kernel
|
||||||
|
|
||||||
enum NetworkProtocol : uint8_t
|
enum NetworkProtocol : uint8_t
|
||||||
{
|
{
|
||||||
|
ICMP = 0x01,
|
||||||
UDP = 0x11,
|
UDP = 0x11,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SocketDomain
|
||||||
|
{
|
||||||
|
INET,
|
||||||
|
INET6,
|
||||||
|
UNIX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SocketType
|
||||||
|
{
|
||||||
|
STREAM,
|
||||||
|
DGRAM,
|
||||||
|
SEQPACKET,
|
||||||
|
};
|
||||||
|
|
||||||
class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
|
class NetworkSocket : public TmpInode, public BAN::Weakable<NetworkSocket>
|
||||||
{
|
{
|
||||||
BAN_NON_COPYABLE(NetworkSocket);
|
BAN_NON_COPYABLE(NetworkSocket);
|
||||||
|
@ -26,14 +42,16 @@ namespace Kernel
|
||||||
void bind_interface_and_port(NetworkInterface*, uint16_t port);
|
void bind_interface_and_port(NetworkInterface*, uint16_t port);
|
||||||
~NetworkSocket();
|
~NetworkSocket();
|
||||||
|
|
||||||
|
NetworkInterface& interface() { ASSERT(m_interface); return *m_interface; }
|
||||||
|
|
||||||
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 dst_port) = 0;
|
||||||
virtual NetworkProtocol 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;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NetworkSocket(mode_t mode, uid_t uid, gid_t gid);
|
NetworkSocket(NetworkLayer&, ino_t, const TmpInodeInfo&);
|
||||||
|
|
||||||
virtual BAN::ErrorOr<size_t> read_packet(BAN::ByteSpan, sockaddr_in* sender_address) = 0;
|
virtual BAN::ErrorOr<size_t> read_packet(BAN::ByteSpan, sockaddr_in* sender_address) = 0;
|
||||||
|
|
||||||
|
@ -46,6 +64,7 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
|
virtual BAN::ErrorOr<long> ioctl_impl(int request, void* arg) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
NetworkLayer& m_network_layer;
|
||||||
NetworkInterface* m_interface = nullptr;
|
NetworkInterface* m_interface = nullptr;
|
||||||
uint16_t m_port = PORT_NONE;
|
uint16_t m_port = PORT_NONE;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,10 +22,10 @@ namespace Kernel
|
||||||
class UDPSocket final : public NetworkSocket
|
class UDPSocket final : public NetworkSocket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(mode_t, uid_t, gid_t);
|
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, ino_t, const TmpInodeInfo&);
|
||||||
|
|
||||||
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 dst_port) override;
|
||||||
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
|
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -33,7 +33,7 @@ namespace Kernel
|
||||||
virtual BAN::ErrorOr<size_t> read_packet(BAN::ByteSpan, sockaddr_in* sender_address) override;
|
virtual BAN::ErrorOr<size_t> read_packet(BAN::ByteSpan, sockaddr_in* sender_address) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UDPSocket(mode_t, uid_t, gid_t);
|
UDPSocket(NetworkLayer&, ino_t, const TmpInodeInfo&);
|
||||||
|
|
||||||
struct PacketInfo
|
struct PacketInfo
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,6 +45,9 @@ namespace Kernel
|
||||||
if (ipv4_address == s_broadcast_ipv4)
|
if (ipv4_address == s_broadcast_ipv4)
|
||||||
return s_broadcast_mac;
|
return s_broadcast_mac;
|
||||||
|
|
||||||
|
if (interface.get_ipv4_address() == BAN::IPv4Address { 0 })
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
if (interface.get_ipv4_address().mask(interface.get_netmask()) != ipv4_address.mask(interface.get_netmask()))
|
if (interface.get_ipv4_address().mask(interface.get_netmask()) != ipv4_address.mask(interface.get_netmask()))
|
||||||
ipv4_address = interface.get_gateway();
|
ipv4_address = interface.get_gateway();
|
||||||
|
|
||||||
|
@ -54,16 +57,7 @@ namespace Kernel
|
||||||
return m_arp_table[ipv4_address];
|
return m_arp_table[ipv4_address];
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::Vector<uint8_t> full_packet_buffer;
|
ARPPacket arp_request;
|
||||||
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.htype = 0x0001;
|
||||||
arp_request.ptype = EtherType::IPv4;
|
arp_request.ptype = EtherType::IPv4;
|
||||||
arp_request.hlen = 0x06;
|
arp_request.hlen = 0x06;
|
||||||
|
@ -74,7 +68,7 @@ namespace Kernel
|
||||||
arp_request.tha = {{ 0, 0, 0, 0, 0, 0 }};
|
arp_request.tha = {{ 0, 0, 0, 0, 0, 0 }};
|
||||||
arp_request.tpa = ipv4_address;
|
arp_request.tpa = ipv4_address;
|
||||||
|
|
||||||
TRY(interface.send_raw_bytes(full_packet));
|
TRY(interface.send_bytes(s_broadcast_mac, EtherType::ARP, BAN::ConstByteSpan::from(arp_request)));
|
||||||
|
|
||||||
uint64_t timeout = SystemTimer::get().ms_since_boot() + 1'000;
|
uint64_t timeout = SystemTimer::get().ms_since_boot() + 1'000;
|
||||||
while (SystemTimer::get().ms_since_boot() < timeout)
|
while (SystemTimer::get().ms_since_boot() < timeout)
|
||||||
|
@ -104,27 +98,17 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (packet.tpa == interface.get_ipv4_address())
|
if (packet.tpa == interface.get_ipv4_address())
|
||||||
{
|
{
|
||||||
BAN::Vector<uint8_t> full_packet_buffer;
|
ARPPacket arp_reply;
|
||||||
TRY(full_packet_buffer.resize(sizeof(ARPPacket) + sizeof(EthernetHeader)));
|
arp_reply.htype = 0x0001;
|
||||||
auto full_packet = BAN::ByteSpan { full_packet_buffer.span() };
|
arp_reply.ptype = EtherType::IPv4;
|
||||||
|
arp_reply.hlen = 0x06;
|
||||||
auto& ethernet_header = full_packet.as<EthernetHeader>();
|
arp_reply.plen = 0x04;
|
||||||
ethernet_header.dst_mac = packet.sha;
|
arp_reply.oper = ARPOperation::Reply;
|
||||||
ethernet_header.src_mac = interface.get_mac_address();
|
arp_reply.sha = interface.get_mac_address();
|
||||||
ethernet_header.ether_type = EtherType::ARP;
|
arp_reply.spa = interface.get_ipv4_address();
|
||||||
|
arp_reply.tha = packet.sha;
|
||||||
auto& arp_request = full_packet.slice(sizeof(EthernetHeader)).as<ARPPacket>();
|
arp_reply.tpa = packet.spa;
|
||||||
arp_request.htype = 0x0001;
|
TRY(interface.send_bytes(packet.sha, EtherType::ARP, BAN::ConstByteSpan::from(arp_reply)));
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,19 +256,26 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> E1000::send_raw_bytes(BAN::ConstByteSpan buffer)
|
|
||||||
|
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
|
||||||
{
|
{
|
||||||
ASSERT_LTE(buffer.size(), E1000_TX_BUFFER_SIZE);
|
ASSERT_LTE(buffer.size() + sizeof(EthernetHeader), E1000_TX_BUFFER_SIZE);
|
||||||
|
|
||||||
CriticalScope _;
|
CriticalScope _;
|
||||||
|
|
||||||
size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT;
|
size_t tx_current = read32(REG_TDT) % E1000_TX_DESCRIPTOR_COUNT;
|
||||||
|
|
||||||
auto* tx_buffer = reinterpret_cast<void*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current);
|
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + E1000_TX_BUFFER_SIZE * tx_current);
|
||||||
memcpy(tx_buffer, buffer.data(), buffer.size());
|
|
||||||
|
auto& ethernet_header = *reinterpret_cast<EthernetHeader*>(tx_buffer);
|
||||||
|
ethernet_header.dst_mac = destination;
|
||||||
|
ethernet_header.src_mac = get_mac_address();
|
||||||
|
ethernet_header.ether_type = protocol;
|
||||||
|
|
||||||
|
memcpy(tx_buffer + sizeof(EthernetHeader), buffer.data(), buffer.size());
|
||||||
|
|
||||||
auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current];
|
auto& descriptor = reinterpret_cast<volatile e1000_tx_desc*>(m_tx_descriptor_region->vaddr())[tx_current];
|
||||||
descriptor.length = buffer.size();
|
descriptor.length = sizeof(EthernetHeader) + buffer.size();
|
||||||
descriptor.status = 0;
|
descriptor.status = 0;
|
||||||
descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS;
|
descriptor.cmd = CMD_EOP | CMD_IFCS | CMD_RS;
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
#include <BAN/Endianness.h>
|
|
||||||
#include <kernel/Networking/IPv4.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
|
||||||
{
|
|
||||||
|
|
||||||
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol)
|
|
||||||
{
|
|
||||||
auto& header = packet.as<IPv4Header>();
|
|
||||||
header.version_IHL = 0x45;
|
|
||||||
header.DSCP_ECN = 0x00;
|
|
||||||
header.total_length = packet.size();
|
|
||||||
header.identification = 1;
|
|
||||||
header.flags_frament = 0x00;
|
|
||||||
header.time_to_live = 0x40;
|
|
||||||
header.protocol = protocol;
|
|
||||||
header.src_address = src_ipv4;
|
|
||||||
header.dst_address = dst_ipv4;
|
|
||||||
header.checksum = header.calculate_checksum();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,284 @@
|
||||||
|
#include <kernel/Memory/Heap.h>
|
||||||
|
#include <kernel/Memory/PageTable.h>
|
||||||
|
#include <kernel/Networking/ICMP.h>
|
||||||
|
#include <kernel/Networking/IPv4Layer.h>
|
||||||
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
|
#include <kernel/Networking/UDPSocket.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#define DEBUG_IPV4 0
|
||||||
|
|
||||||
|
namespace Kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> IPv4Layer::create()
|
||||||
|
{
|
||||||
|
auto ipv4_manager = TRY(BAN::UniqPtr<IPv4Layer>::create());
|
||||||
|
ipv4_manager->m_process = Process::create_kernel(
|
||||||
|
[](void* ipv4_manager_ptr)
|
||||||
|
{
|
||||||
|
auto& ipv4_manager = *reinterpret_cast<IPv4Layer*>(ipv4_manager_ptr);
|
||||||
|
ipv4_manager.packet_handle_task();
|
||||||
|
}, ipv4_manager.ptr()
|
||||||
|
);
|
||||||
|
ASSERT(ipv4_manager->m_process);
|
||||||
|
ipv4_manager->m_pending_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
|
PageTable::kernel(),
|
||||||
|
KERNEL_OFFSET,
|
||||||
|
~(uintptr_t)0,
|
||||||
|
pending_packet_buffer_size,
|
||||||
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
|
true
|
||||||
|
));
|
||||||
|
ipv4_manager->m_arp_table = TRY(ARPTable::create());
|
||||||
|
return ipv4_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPv4Layer::IPv4Layer()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
IPv4Layer::~IPv4Layer()
|
||||||
|
{
|
||||||
|
if (m_process)
|
||||||
|
m_process->exit(0, SIGKILL);
|
||||||
|
m_process = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv4Layer::add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const
|
||||||
|
{
|
||||||
|
auto& header = packet.as<IPv4Header>();
|
||||||
|
header.version_IHL = 0x45;
|
||||||
|
header.DSCP_ECN = 0x00;
|
||||||
|
header.total_length = packet.size();
|
||||||
|
header.identification = 1;
|
||||||
|
header.flags_frament = 0x00;
|
||||||
|
header.time_to_live = 0x40;
|
||||||
|
header.protocol = protocol;
|
||||||
|
header.src_address = src_ipv4;
|
||||||
|
header.dst_address = dst_ipv4;
|
||||||
|
header.checksum = header.calculate_checksum();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv4Layer::unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
if (m_bound_sockets.contains(port))
|
||||||
|
{
|
||||||
|
ASSERT(m_bound_sockets[port].valid());
|
||||||
|
ASSERT(m_bound_sockets[port].lock() == socket);
|
||||||
|
m_bound_sockets.remove(port);
|
||||||
|
}
|
||||||
|
NetworkManager::get().TmpFileSystem::remove_from_cache(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> IPv4Layer::bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
|
||||||
|
{
|
||||||
|
if (NetworkManager::get().interfaces().empty())
|
||||||
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
|
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
|
if (port == NetworkSocket::PORT_NONE)
|
||||||
|
{
|
||||||
|
for (uint32_t temp = 0xC000; temp < 0xFFFF; temp++)
|
||||||
|
{
|
||||||
|
if (!m_bound_sockets.contains(temp))
|
||||||
|
{
|
||||||
|
port = temp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (port == NetworkSocket::PORT_NONE)
|
||||||
|
{
|
||||||
|
dwarnln("No ports available");
|
||||||
|
return BAN::Error::from_errno(EAGAIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_bound_sockets.contains(port))
|
||||||
|
return BAN::Error::from_errno(EADDRINUSE);
|
||||||
|
TRY(m_bound_sockets.insert(port, socket));
|
||||||
|
|
||||||
|
// FIXME: actually determine proper interface
|
||||||
|
auto interface = NetworkManager::get().interfaces().front();
|
||||||
|
socket->bind_interface_and_port(interface.ptr(), port);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<size_t> IPv4Layer::sendto(NetworkSocket& socket, const sys_sendto_t* arguments)
|
||||||
|
{
|
||||||
|
if (arguments->dest_addr->sa_family != AF_INET)
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(arguments->dest_addr);
|
||||||
|
|
||||||
|
auto dst_port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
||||||
|
auto dst_ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||||
|
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(socket.interface(), dst_ipv4));
|
||||||
|
|
||||||
|
BAN::Vector<uint8_t> packet_buffer;
|
||||||
|
TRY(packet_buffer.resize(arguments->length + sizeof(IPv4Header) + socket.protocol_header_size()));
|
||||||
|
auto packet = BAN::ByteSpan { packet_buffer.span() };
|
||||||
|
|
||||||
|
memcpy(
|
||||||
|
packet.slice(sizeof(IPv4Header)).slice(socket.protocol_header_size()).data(),
|
||||||
|
arguments->message,
|
||||||
|
arguments->length
|
||||||
|
);
|
||||||
|
socket.add_protocol_header(
|
||||||
|
packet.slice(sizeof(IPv4Header)),
|
||||||
|
dst_port
|
||||||
|
);
|
||||||
|
add_ipv4_header(
|
||||||
|
packet,
|
||||||
|
socket.interface().get_ipv4_address(),
|
||||||
|
dst_ipv4,
|
||||||
|
socket.protocol()
|
||||||
|
);
|
||||||
|
|
||||||
|
TRY(socket.interface().send_bytes(dst_mac, EtherType::IPv4, packet));
|
||||||
|
|
||||||
|
return arguments->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t calculate_internet_checksum(BAN::ConstByteSpan packet)
|
||||||
|
{
|
||||||
|
uint32_t checksum = 0;
|
||||||
|
for (size_t i = 0; i < packet.size() / sizeof(uint16_t); i++)
|
||||||
|
checksum += BAN::host_to_network_endian(reinterpret_cast<const uint16_t*>(packet.data())[i]);
|
||||||
|
while (checksum >> 16)
|
||||||
|
checksum = (checksum >> 16) | (checksum & 0xFFFF);
|
||||||
|
return ~(uint16_t)checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> IPv4Layer::handle_ipv4_packet(NetworkInterface& interface, BAN::ByteSpan packet)
|
||||||
|
{
|
||||||
|
auto& ipv4_header = packet.as<const IPv4Header>();
|
||||||
|
auto ipv4_data = packet.slice(sizeof(IPv4Header));
|
||||||
|
|
||||||
|
ASSERT(ipv4_header.is_valid_checksum());
|
||||||
|
|
||||||
|
auto src_ipv4 = ipv4_header.src_address;
|
||||||
|
switch (ipv4_header.protocol)
|
||||||
|
{
|
||||||
|
case NetworkProtocol::ICMP:
|
||||||
|
{
|
||||||
|
auto& icmp_header = ipv4_data.as<const ICMPHeader>();
|
||||||
|
switch (icmp_header.type)
|
||||||
|
{
|
||||||
|
case ICMPType::EchoRequest:
|
||||||
|
{
|
||||||
|
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(interface, src_ipv4));
|
||||||
|
|
||||||
|
auto& reply_icmp_header = ipv4_data.as<ICMPHeader>();
|
||||||
|
reply_icmp_header.type = ICMPType::EchoReply;
|
||||||
|
reply_icmp_header.checksum = 0;
|
||||||
|
reply_icmp_header.checksum = calculate_internet_checksum(ipv4_data);
|
||||||
|
|
||||||
|
add_ipv4_header(packet, interface.get_ipv4_address(), src_ipv4, NetworkProtocol::ICMP);
|
||||||
|
|
||||||
|
TRY(interface.send_bytes(dst_mac, EtherType::IPv4, packet));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dprintln("Unhandleded ICMP packet (type {2H})", icmp_header.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NetworkProtocol::UDP:
|
||||||
|
{
|
||||||
|
auto& udp_header = ipv4_data.as<const UDPHeader>();
|
||||||
|
uint16_t src_port = udp_header.src_port;
|
||||||
|
uint16_t dst_port = udp_header.dst_port;
|
||||||
|
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
|
||||||
|
if (!m_bound_sockets.contains(dst_port) || !m_bound_sockets[dst_port].valid())
|
||||||
|
{
|
||||||
|
dprintln_if(DEBUG_IPV4, "no one is listening on port {}", dst_port);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto udp_data = ipv4_data.slice(sizeof(UDPHeader));
|
||||||
|
m_bound_sockets[dst_port].lock()->add_packet(udp_data, src_ipv4, src_port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
dprintln_if(DEBUG_IPV4, "Unknown network protocol 0x{2H}", ipv4_header.protocol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv4Layer::packet_handle_task()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
BAN::Optional<PendingIPv4Packet> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* buffer_start = reinterpret_cast<uint8_t*>(m_pending_packet_buffer->vaddr());
|
||||||
|
const size_t ipv4_packet_size = reinterpret_cast<const IPv4Header*>(buffer_start)->total_length;
|
||||||
|
|
||||||
|
if (auto ret = handle_ipv4_packet(pending->interface, BAN::ByteSpan(buffer_start, ipv4_packet_size)); ret.is_error())
|
||||||
|
dwarnln("{}", ret.error());
|
||||||
|
|
||||||
|
CriticalScope _;
|
||||||
|
m_pending_total_size -= ipv4_packet_size;
|
||||||
|
if (m_pending_total_size)
|
||||||
|
memmove(buffer_start, buffer_start + ipv4_packet_size, m_pending_total_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPv4Layer::add_ipv4_packet(NetworkInterface& interface, BAN::ConstByteSpan buffer)
|
||||||
|
{
|
||||||
|
if (m_pending_packets.full())
|
||||||
|
{
|
||||||
|
dwarnln("IPv4 packet queue full");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pending_total_size + buffer.size() > m_pending_packet_buffer->size())
|
||||||
|
{
|
||||||
|
dwarnln("IPv4 packet queue full");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& ipv4_header = buffer.as<const IPv4Header>();
|
||||||
|
if (!ipv4_header.is_valid_checksum())
|
||||||
|
{
|
||||||
|
dwarnln("Invalid IPv4 packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ipv4_header.total_length > buffer.size())
|
||||||
|
{
|
||||||
|
dwarnln("Too short IPv4 packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* buffer_start = reinterpret_cast<uint8_t*>(m_pending_packet_buffer->vaddr());
|
||||||
|
memcpy(buffer_start + m_pending_total_size, buffer.data(), ipv4_header.total_length);
|
||||||
|
m_pending_total_size += ipv4_header.total_length;
|
||||||
|
|
||||||
|
m_pending_packets.push({ .interface = interface });
|
||||||
|
m_pending_semaphore.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -32,19 +32,4 @@ namespace Kernel
|
||||||
m_name[3] = minor(m_rdev) + '0';
|
m_name[3] = minor(m_rdev) + '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NetworkInterface::interface_header_size() const
|
|
||||||
{
|
|
||||||
ASSERT(m_type == Type::Ethernet);
|
|
||||||
return sizeof(EthernetHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkInterface::add_interface_header(BAN::ByteSpan packet, BAN::MACAddress destination)
|
|
||||||
{
|
|
||||||
ASSERT(m_type == Type::Ethernet);
|
|
||||||
auto& header = packet.as<EthernetHeader>();
|
|
||||||
header.dst_mac = destination;
|
|
||||||
header.src_mac = get_mac_address();
|
|
||||||
header.ether_type = 0x0800;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#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/IPv4.h>
|
#include <kernel/Networking/ICMP.h>
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/Networking/UDPSocket.h>
|
#include <kernel/Networking/UDPSocket.h>
|
||||||
|
|
||||||
|
#define DEBUG_ETHERTYPE 0
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -19,8 +21,8 @@ namespace Kernel
|
||||||
if (manager_ptr == nullptr)
|
if (manager_ptr == nullptr)
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
auto manager = BAN::UniqPtr<NetworkManager>::adopt(manager_ptr);
|
auto manager = BAN::UniqPtr<NetworkManager>::adopt(manager_ptr);
|
||||||
manager->m_arp_table = TRY(ARPTable::create());
|
|
||||||
TRY(manager->TmpFileSystem::initialize(0777, 0, 0));
|
TRY(manager->TmpFileSystem::initialize(0777, 0, 0));
|
||||||
|
manager->m_ipv4_layer = TRY(IPv4Layer::create());
|
||||||
s_instance = BAN::move(manager);
|
s_instance = BAN::move(manager);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -68,45 +70,41 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> NetworkManager::create_socket(SocketType type, mode_t mode, uid_t uid, gid_t gid)
|
BAN::ErrorOr<BAN::RefPtr<NetworkSocket>> NetworkManager::create_socket(SocketDomain domain, SocketType type, mode_t mode, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
switch (domain)
|
||||||
|
{
|
||||||
|
case SocketDomain::INET:
|
||||||
{
|
{
|
||||||
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
|
|
||||||
|
|
||||||
if (type != SocketType::DGRAM)
|
if (type != SocketType::DGRAM)
|
||||||
return BAN::Error::from_errno(EPROTOTYPE);
|
return BAN::Error::from_errno(EPROTOTYPE);
|
||||||
|
break;
|
||||||
auto udp_socket = TRY(UDPSocket::create(mode | Inode::Mode::IFSOCK, uid, gid));
|
}
|
||||||
return BAN::RefPtr<NetworkSocket>(udp_socket);
|
default:
|
||||||
|
return BAN::Error::from_errno(EAFNOSUPPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkManager::unbind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
|
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
|
||||||
|
mode |= Inode::Mode::IFSOCK;
|
||||||
|
|
||||||
|
auto inode_info = create_inode_info(mode, uid, gid);
|
||||||
|
ino_t ino = TRY(allocate_inode(inode_info));
|
||||||
|
|
||||||
|
BAN::RefPtr<NetworkSocket> socket;
|
||||||
|
switch (domain)
|
||||||
{
|
{
|
||||||
if (m_bound_sockets.contains(port))
|
case SocketDomain::INET:
|
||||||
{
|
{
|
||||||
ASSERT(m_bound_sockets[port].valid());
|
if (type == SocketType::DGRAM)
|
||||||
ASSERT(m_bound_sockets[port].lock() == socket);
|
socket = TRY(UDPSocket::create(*m_ipv4_layer, ino, inode_info));
|
||||||
m_bound_sockets.remove(port);
|
break;
|
||||||
}
|
}
|
||||||
NetworkManager::get().remove_from_cache(socket);
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> NetworkManager::bind_socket(uint16_t port, BAN::RefPtr<NetworkSocket> socket)
|
ASSERT(socket);
|
||||||
{
|
return socket;
|
||||||
if (m_interfaces.empty())
|
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
|
||||||
|
|
||||||
if (port != NetworkSocket::PORT_NONE)
|
|
||||||
{
|
|
||||||
if (m_bound_sockets.contains(port))
|
|
||||||
return BAN::Error::from_errno(EADDRINUSE);
|
|
||||||
TRY(m_bound_sockets.insert(port, socket));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: actually determine proper interface
|
|
||||||
auto interface = m_interfaces.front();
|
|
||||||
socket->bind_interface_and_port(interface.ptr(), port);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
void NetworkManager::on_receive(NetworkInterface& interface, BAN::ConstByteSpan packet)
|
||||||
|
@ -117,41 +115,16 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
case EtherType::ARP:
|
case EtherType::ARP:
|
||||||
{
|
{
|
||||||
m_arp_table->add_arp_packet(interface, packet.slice(sizeof(EthernetHeader)));
|
m_ipv4_layer->arp_table().add_arp_packet(interface, packet.slice(sizeof(EthernetHeader)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EtherType::IPv4:
|
case EtherType::IPv4:
|
||||||
{
|
{
|
||||||
auto ipv4 = packet.slice(sizeof(EthernetHeader));
|
m_ipv4_layer->add_ipv4_packet(interface, 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;
|
|
||||||
|
|
||||||
if (!m_bound_sockets.contains(dst_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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
dprintln("Unknown network protocol 0x{2H}", ipv4_header.protocol);
|
dprintln_if(DEBUG_ETHERTYPE, "Unknown EtherType 0x{4H}", (uint16_t)ethernet_header.ether_type);
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
dprintln("Unknown EtherType 0x{4H}", (uint16_t)ethernet_header.ether_type);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <kernel/Networking/IPv4.h>
|
|
||||||
#include <kernel/Networking/NetworkManager.h>
|
#include <kernel/Networking/NetworkManager.h>
|
||||||
#include <kernel/Networking/NetworkSocket.h>
|
#include <kernel/Networking/NetworkSocket.h>
|
||||||
|
|
||||||
|
@ -7,13 +6,9 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
NetworkSocket::NetworkSocket(mode_t mode, uid_t uid, gid_t gid)
|
NetworkSocket::NetworkSocket(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
|
||||||
// FIXME: what the fuck is this
|
: TmpInode(NetworkManager::get(), ino, inode_info)
|
||||||
: TmpInode(
|
, m_network_layer(network_layer)
|
||||||
NetworkManager::get(),
|
|
||||||
MUST(NetworkManager::get().allocate_inode(create_inode_info(mode, uid, gid))),
|
|
||||||
create_inode_info(mode, uid, gid)
|
|
||||||
)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
NetworkSocket::~NetworkSocket()
|
NetworkSocket::~NetworkSocket()
|
||||||
|
@ -23,7 +18,7 @@ namespace Kernel
|
||||||
void NetworkSocket::on_close_impl()
|
void NetworkSocket::on_close_impl()
|
||||||
{
|
{
|
||||||
if (m_interface)
|
if (m_interface)
|
||||||
NetworkManager::get().unbind_socket(m_port, this);
|
m_network_layer.unbind_socket(m_port, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSocket::bind_interface_and_port(NetworkInterface* interface, uint16_t port)
|
void NetworkSocket::bind_interface_and_port(NetworkInterface* interface, uint16_t port)
|
||||||
|
@ -36,17 +31,15 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<void> NetworkSocket::bind_impl(const sockaddr* address, socklen_t address_len)
|
BAN::ErrorOr<void> NetworkSocket::bind_impl(const sockaddr* address, socklen_t address_len)
|
||||||
{
|
{
|
||||||
if (address_len != sizeof(sockaddr_in))
|
if (m_interface || address_len != sizeof(sockaddr_in))
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
auto* addr_in = reinterpret_cast<const sockaddr_in*>(address);
|
auto* addr_in = reinterpret_cast<const sockaddr_in*>(address);
|
||||||
uint16_t dst_port = BAN::host_to_network_endian(addr_in->sin_port);
|
uint16_t dst_port = BAN::host_to_network_endian(addr_in->sin_port);
|
||||||
return NetworkManager::get().bind_socket(dst_port, this);
|
return m_network_layer.bind_socket(dst_port, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<ssize_t> NetworkSocket::sendto_impl(const sys_sendto_t* arguments)
|
BAN::ErrorOr<ssize_t> NetworkSocket::sendto_impl(const sys_sendto_t* arguments)
|
||||||
{
|
{
|
||||||
if (arguments->dest_len != sizeof(sockaddr_in))
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
if (arguments->flags)
|
if (arguments->flags)
|
||||||
{
|
{
|
||||||
dprintln("flags not supported");
|
dprintln("flags not supported");
|
||||||
|
@ -54,42 +47,9 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_interface)
|
if (!m_interface)
|
||||||
TRY(NetworkManager::get().bind_socket(PORT_NONE, this));
|
TRY(m_network_layer.bind_socket(PORT_NONE, this));
|
||||||
|
|
||||||
auto* destination = reinterpret_cast<const sockaddr_in*>(arguments->dest_addr);
|
return TRY(m_network_layer.sendto(*this, arguments));
|
||||||
auto message = BAN::ConstByteSpan((const uint8_t*)arguments->message, arguments->length);
|
|
||||||
|
|
||||||
uint16_t dst_port = BAN::host_to_network_endian(destination->sin_port);
|
|
||||||
if (dst_port == PORT_NONE)
|
|
||||||
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(*m_interface, dst_addr));
|
|
||||||
|
|
||||||
const size_t interface_header_offset = 0;
|
|
||||||
const size_t interface_header_size = m_interface->interface_header_size();
|
|
||||||
|
|
||||||
const size_t ipv4_header_offset = interface_header_offset + interface_header_size;
|
|
||||||
const size_t ipv4_header_size = sizeof(IPv4Header);
|
|
||||||
|
|
||||||
const size_t protocol_header_offset = ipv4_header_offset + ipv4_header_size;
|
|
||||||
const size_t protocol_header_size = this->protocol_header_size();
|
|
||||||
|
|
||||||
const size_t payload_offset = protocol_header_offset + protocol_header_size;
|
|
||||||
const size_t payload_size = message.size();
|
|
||||||
|
|
||||||
BAN::Vector<uint8_t> full_packet;
|
|
||||||
TRY(full_packet.resize(payload_offset + payload_size));
|
|
||||||
|
|
||||||
BAN::ByteSpan packet_bytespan { full_packet.span() };
|
|
||||||
|
|
||||||
memcpy(full_packet.data() + payload_offset, message.data(), payload_size);
|
|
||||||
add_protocol_header(packet_bytespan.slice(protocol_header_offset), m_port, dst_port);
|
|
||||||
add_ipv4_header(packet_bytespan.slice(ipv4_header_offset), m_interface->get_ipv4_address(), dst_addr, protocol());
|
|
||||||
m_interface->add_interface_header(packet_bytespan.slice(interface_header_offset), dst_mac);
|
|
||||||
TRY(m_interface->send_raw_bytes(packet_bytespan));
|
|
||||||
|
|
||||||
return arguments->length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<ssize_t> NetworkSocket::recvfrom_impl(sys_recvfrom_t* arguments)
|
BAN::ErrorOr<ssize_t> NetworkSocket::recvfrom_impl(sys_recvfrom_t* arguments)
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::RefPtr<UDPSocket>> UDPSocket::create(mode_t mode, uid_t uid, gid_t gid)
|
BAN::ErrorOr<BAN::RefPtr<UDPSocket>> UDPSocket::create(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
|
||||||
{
|
{
|
||||||
auto socket = TRY(BAN::RefPtr<UDPSocket>::create(mode, uid, gid));
|
auto socket = TRY(BAN::RefPtr<UDPSocket>::create(network_layer, ino, inode_info));
|
||||||
socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
socket->m_packet_buffer = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
PageTable::kernel(),
|
PageTable::kernel(),
|
||||||
KERNEL_OFFSET,
|
KERNEL_OFFSET,
|
||||||
|
@ -19,14 +19,14 @@ namespace Kernel
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPSocket::UDPSocket(mode_t mode, uid_t uid, gid_t gid)
|
UDPSocket::UDPSocket(NetworkLayer& network_layer, ino_t ino, const TmpInodeInfo& inode_info)
|
||||||
: NetworkSocket(mode, uid, gid)
|
: NetworkSocket(network_layer, ino, inode_info)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t src_port, uint16_t dst_port)
|
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port)
|
||||||
{
|
{
|
||||||
auto& header = packet.as<UDPHeader>();
|
auto& header = packet.as<UDPHeader>();
|
||||||
header.src_port = src_port;
|
header.src_port = m_port;
|
||||||
header.dst_port = dst_port;
|
header.dst_port = dst_port;
|
||||||
header.length = packet.size();
|
header.length = packet.size();
|
||||||
header.checksum = 0;
|
header.checksum = 0;
|
||||||
|
|
|
@ -80,13 +80,25 @@ namespace Kernel
|
||||||
|
|
||||||
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
|
BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
using SocketType = NetworkManager::SocketType;
|
|
||||||
|
|
||||||
if (domain != AF_INET)
|
|
||||||
return BAN::Error::from_errno(EAFNOSUPPORT);
|
|
||||||
if (protocol != 0)
|
if (protocol != 0)
|
||||||
return BAN::Error::from_errno(EPROTONOSUPPORT);
|
return BAN::Error::from_errno(EPROTONOSUPPORT);
|
||||||
|
|
||||||
|
SocketDomain sock_domain;
|
||||||
|
switch (domain)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
sock_domain = SocketDomain::INET;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
sock_domain = SocketDomain::INET6;
|
||||||
|
break;
|
||||||
|
case AF_UNIX:
|
||||||
|
sock_domain = SocketDomain::UNIX;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return BAN::Error::from_errno(EPROTOTYPE);
|
||||||
|
}
|
||||||
|
|
||||||
SocketType sock_type;
|
SocketType sock_type;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +115,7 @@ namespace Kernel
|
||||||
return BAN::Error::from_errno(EPROTOTYPE);
|
return BAN::Error::from_errno(EPROTOTYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto socket = TRY(NetworkManager::get().create_socket(sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
|
auto socket = TRY(NetworkManager::get().create_socket(sock_domain, sock_type, 0777, m_credentials.euid(), m_credentials.egid()));
|
||||||
|
|
||||||
int fd = TRY(get_free_fd());
|
int fd = TRY(get_free_fd());
|
||||||
m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(socket, "no-path"sv, 0, O_RDWR));
|
m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(socket, "no-path"sv, 0, O_RDWR));
|
||||||
|
|
Loading…
Reference in New Issue