Kernel: Rework socket binding to an address
Sockets are no longer bound to an interface, but an ipv4 address. This allows servers at 0.0.0.0 talk to multiple different interfaces
This commit is contained in:
parent
efdbd1576f
commit
f06e5d33e7
|
|
@ -45,7 +45,7 @@ namespace Kernel
|
|||
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
|
||||
|
||||
virtual void unbind_socket(uint16_t port) override;
|
||||
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) override;
|
||||
virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) override;
|
||||
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override;
|
||||
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override;
|
||||
|
||||
|
|
@ -59,6 +59,8 @@ namespace Kernel
|
|||
|
||||
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const;
|
||||
|
||||
BAN::ErrorOr<in_port_t> find_free_port();
|
||||
|
||||
void packet_handle_task();
|
||||
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Kernel
|
|||
virtual ~NetworkLayer() {}
|
||||
|
||||
virtual void unbind_socket(uint16_t port) = 0;
|
||||
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) = 0;
|
||||
virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) = 0;
|
||||
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0;
|
||||
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <kernel/Networking/NetworkInterface.h>
|
||||
#include <kernel/Networking/NetworkLayer.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
|
|
@ -24,10 +26,10 @@ namespace Kernel
|
|||
static constexpr uint16_t PORT_NONE = 0;
|
||||
|
||||
public:
|
||||
void bind_interface_and_port(NetworkInterface*, uint16_t port);
|
||||
void bind_address_and_port(const sockaddr*, socklen_t);
|
||||
~NetworkSocket();
|
||||
|
||||
NetworkInterface& interface() { ASSERT(m_interface); return *m_interface; }
|
||||
BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> interface(const sockaddr* target, socklen_t target_len);
|
||||
|
||||
virtual size_t protocol_header_size() const = 0;
|
||||
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) = 0;
|
||||
|
|
@ -35,7 +37,19 @@ namespace Kernel
|
|||
|
||||
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0;
|
||||
|
||||
bool is_bound() const { return m_interface != nullptr; }
|
||||
bool is_bound() const { return m_address_len >= static_cast<socklen_t>(sizeof(sa_family_t)) && m_address.ss_family != AF_UNSPEC; }
|
||||
in_port_t bound_port() const
|
||||
{
|
||||
ASSERT(is_bound());
|
||||
ASSERT(m_address.ss_family == AF_INET && m_address_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
|
||||
return BAN::network_endian_to_host(reinterpret_cast<const sockaddr_in*>(&m_address)->sin_port);
|
||||
}
|
||||
|
||||
const sockaddr* address() const { return reinterpret_cast<const sockaddr*>(&m_address); }
|
||||
socklen_t address_len() const { return m_address_len; }
|
||||
|
||||
private:
|
||||
bool can_interface_send_to(const NetworkInterface&, const sockaddr*, socklen_t) const;
|
||||
|
||||
protected:
|
||||
NetworkSocket(NetworkLayer&, const Socket::Info&);
|
||||
|
|
@ -45,9 +59,9 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
|
||||
|
||||
protected:
|
||||
NetworkLayer& m_network_layer;
|
||||
NetworkInterface* m_interface = nullptr;
|
||||
uint16_t m_port { PORT_NONE };
|
||||
NetworkLayer& m_network_layer;
|
||||
sockaddr_storage m_address { .ss_family = AF_UNSPEC, .ss_storage = {} };
|
||||
socklen_t m_address_len { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,35 +75,58 @@ namespace Kernel
|
|||
m_bound_sockets.remove(it);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_unused(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
||||
BAN::ErrorOr<in_port_t> IPv4Layer::find_free_port()
|
||||
{
|
||||
if (!address || address_len < (socklen_t)sizeof(sockaddr_in))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (address->sa_family != AF_INET)
|
||||
return BAN::Error::from_errno(EAFNOSUPPORT);
|
||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
||||
|
||||
SpinLockGuard _(m_bound_socket_lock);
|
||||
|
||||
uint16_t port = NetworkSocket::PORT_NONE;
|
||||
for (uint32_t i = 0; i < 100 && port == NetworkSocket::PORT_NONE; i++)
|
||||
if (uint32_t temp = 0xC000 | (Random::get_u32() & 0x3FFF); !m_bound_sockets.contains(temp))
|
||||
port = temp;
|
||||
for (uint32_t temp = 0xC000; temp < 0xFFFF && port == NetworkSocket::PORT_NONE; temp++)
|
||||
if (!m_bound_sockets.contains(temp))
|
||||
port = temp;
|
||||
if (port == NetworkSocket::PORT_NONE)
|
||||
{
|
||||
dwarnln("No ports available");
|
||||
return BAN::Error::from_errno(EAGAIN);
|
||||
}
|
||||
dprintln_if(DEBUG_IPV4, "using port {}", port);
|
||||
for (uint32_t i = 0; i < 100; i++)
|
||||
if (uint32_t port = 0xC000 | (Random::get_u32() & 0x3FFF); !m_bound_sockets.contains(port))
|
||||
return port;
|
||||
|
||||
struct sockaddr_in target;
|
||||
target.sin_family = AF_INET;
|
||||
target.sin_port = BAN::host_to_network_endian(port);
|
||||
target.sin_addr.s_addr = sockaddr_in.sin_addr.s_addr;
|
||||
return bind_socket_to_address(socket, (sockaddr*)&target, sizeof(sockaddr_in));
|
||||
for (uint32_t port = 0xC000; port < 0xFFFF; port++)
|
||||
if (!m_bound_sockets.contains(port))
|
||||
return port;
|
||||
|
||||
dwarnln("No ports available");
|
||||
return BAN::Error::from_errno(EAGAIN);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_with_target(BAN::RefPtr<NetworkSocket> socket, const sockaddr* target, socklen_t target_len)
|
||||
{
|
||||
if (!target || target_len < (socklen_t)sizeof(sockaddr_in))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (target->sa_family != AF_INET)
|
||||
return BAN::Error::from_errno(EAFNOSUPPORT);
|
||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(target);
|
||||
|
||||
auto interface =
|
||||
TRY([&sockaddr_in]() -> BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> {
|
||||
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||
|
||||
// try to find an interface in the same subnet
|
||||
const auto& all_interfaces = NetworkManager::get().interfaces();
|
||||
for (const auto& interface : all_interfaces)
|
||||
{
|
||||
const auto netmask = interface->get_netmask();
|
||||
if (ipv4.mask(netmask) == interface->get_ipv4_address().mask(netmask))
|
||||
return interface;
|
||||
}
|
||||
|
||||
// fallback to non-loopback interface
|
||||
// FIXME: make sure target is reachable
|
||||
for (const auto& interface : all_interfaces)
|
||||
if (interface->type() != NetworkInterface::Type::Loopback)
|
||||
return interface;
|
||||
|
||||
return BAN::Error::from_errno(EHOSTUNREACH);
|
||||
}());
|
||||
|
||||
// FIXME: race condition with port allocation/binding
|
||||
struct sockaddr_in bind_address;
|
||||
bind_address.sin_family = AF_INET;
|
||||
bind_address.sin_port = BAN::host_to_network_endian(TRY(find_free_port()));
|
||||
bind_address.sin_addr.s_addr = interface->get_ipv4_address().raw;
|
||||
return bind_socket_to_address(socket, (sockaddr*)&bind_address, sizeof(bind_address));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> IPv4Layer::bind_socket_to_address(BAN::RefPtr<NetworkSocket> socket, const sockaddr* address, socklen_t address_len)
|
||||
|
|
@ -114,33 +137,47 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EAFNOSUPPORT);
|
||||
|
||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
||||
const uint16_t port = BAN::host_to_network_endian(sockaddr_in.sin_port);
|
||||
if (port == NetworkSocket::PORT_NONE)
|
||||
return bind_socket_to_unused(socket, address, address_len);
|
||||
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||
|
||||
BAN::RefPtr<NetworkInterface> bind_interface;
|
||||
for (auto interface : NetworkManager::get().interfaces())
|
||||
{
|
||||
if (interface->type() != NetworkInterface::Type::Loopback)
|
||||
bind_interface = interface;
|
||||
const auto netmask = interface->get_netmask();
|
||||
if (ipv4.mask(netmask) != interface->get_ipv4_address().mask(netmask))
|
||||
continue;
|
||||
bind_interface = interface;
|
||||
break;
|
||||
}
|
||||
TRY([&sockaddr_in]() -> BAN::ErrorOr<void> {
|
||||
const auto ipv4 = BAN::IPv4Address { sockaddr_in.sin_addr.s_addr };
|
||||
|
||||
if (ipv4 == 0)
|
||||
return {};
|
||||
|
||||
const auto& all_interfaces = NetworkManager::get().interfaces();
|
||||
for (const auto& interface : all_interfaces)
|
||||
{
|
||||
switch (interface->type())
|
||||
{
|
||||
case NetworkInterface::Type::Ethernet:
|
||||
if (ipv4 == interface->get_ipv4_address())
|
||||
return {};
|
||||
break;
|
||||
case NetworkInterface::Type::Loopback:
|
||||
const auto netmask = interface->get_netmask();
|
||||
if (ipv4.mask(netmask) == interface->get_ipv4_address().mask(netmask))
|
||||
return {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bind_interface)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
}());
|
||||
|
||||
struct sockaddr_in bind_address;
|
||||
memcpy(&bind_address, address, sizeof(sockaddr_in));
|
||||
|
||||
SpinLockGuard _(m_bound_socket_lock);
|
||||
|
||||
if (bind_address.sin_port == 0)
|
||||
bind_address.sin_port = TRY(find_free_port());
|
||||
const uint16_t port = BAN::host_to_network_endian(bind_address.sin_port);
|
||||
|
||||
if (m_bound_sockets.contains(port))
|
||||
return BAN::Error::from_errno(EADDRINUSE);
|
||||
TRY(m_bound_sockets.insert(port, TRY(socket->get_weak_ptr())));
|
||||
|
||||
socket->bind_interface_and_port(bind_interface.ptr(), port);
|
||||
socket->bind_address_and_port(reinterpret_cast<struct sockaddr*>(&bind_address), sizeof(bind_address));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
@ -173,18 +210,36 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(EINVAL);
|
||||
if (address == nullptr || address_len != sizeof(sockaddr_in))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
||||
|
||||
auto interface = TRY(socket.interface(address, address_len));
|
||||
|
||||
auto& sockaddr_in = *reinterpret_cast<const struct sockaddr_in*>(address);
|
||||
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));
|
||||
auto dst_mac = TRY(m_arp_table->get_mac_from_ipv4(*interface, dst_ipv4));
|
||||
|
||||
if (interface->type() == NetworkInterface::Type::Loopback)
|
||||
{
|
||||
BAN::RefPtr<NetworkSocket> receiver;
|
||||
|
||||
{
|
||||
SpinLockGuard _(m_bound_socket_lock);
|
||||
auto receiver_it = m_bound_sockets.find(dst_port);
|
||||
if (receiver_it != m_bound_sockets.end())
|
||||
receiver = receiver_it->value.lock();
|
||||
}
|
||||
|
||||
if (!receiver)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
TRY(socket.interface(receiver->address(), receiver->address_len()));
|
||||
}
|
||||
|
||||
BAN::Vector<uint8_t> packet_buffer;
|
||||
TRY(packet_buffer.resize(buffer.size() + sizeof(IPv4Header) + socket.protocol_header_size()));
|
||||
auto packet = BAN::ByteSpan { packet_buffer.span() };
|
||||
|
||||
auto pseudo_header = PseudoHeader {
|
||||
.src_ipv4 = socket.interface().get_ipv4_address(),
|
||||
.src_ipv4 = interface->get_ipv4_address(),
|
||||
.dst_ipv4 = dst_ipv4,
|
||||
.protocol = socket.protocol()
|
||||
};
|
||||
|
|
@ -201,12 +256,12 @@ namespace Kernel
|
|||
);
|
||||
add_ipv4_header(
|
||||
packet,
|
||||
socket.interface().get_ipv4_address(),
|
||||
interface->get_ipv4_address(),
|
||||
dst_ipv4,
|
||||
socket.protocol()
|
||||
);
|
||||
|
||||
TRY(socket.interface().send_bytes(dst_mac, EtherType::IPv4, packet));
|
||||
TRY(interface->send_bytes(dst_mac, EtherType::IPv4, packet));
|
||||
|
||||
return buffer.size();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,97 @@ namespace Kernel
|
|||
{
|
||||
}
|
||||
|
||||
void NetworkSocket::bind_interface_and_port(NetworkInterface* interface, uint16_t port)
|
||||
bool NetworkSocket::can_interface_send_to(const NetworkInterface& interface, const sockaddr* target, socklen_t target_len) const
|
||||
{
|
||||
ASSERT(!m_interface);
|
||||
ASSERT(interface);
|
||||
m_interface = interface;
|
||||
m_port = port;
|
||||
ASSERT(target);
|
||||
ASSERT(target_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
|
||||
ASSERT(target->sa_family == AF_INET);
|
||||
|
||||
const auto target_ipv4 = BAN::IPv4Address {
|
||||
reinterpret_cast<const sockaddr_in*>(target)->sin_addr.s_addr
|
||||
};
|
||||
|
||||
switch (interface.type())
|
||||
{
|
||||
case NetworkInterface::Type::Ethernet:
|
||||
// FIXME: this is not really correct :D
|
||||
return target_ipv4.octets[0] != IN_LOOPBACKNET;
|
||||
case NetworkInterface::Type::Loopback:
|
||||
return target_ipv4.octets[0] == IN_LOOPBACKNET;
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> NetworkSocket::interface(const sockaddr* target, socklen_t target_len)
|
||||
{
|
||||
ASSERT(m_network_layer.domain() == NetworkSocket::Domain::INET);
|
||||
ASSERT(is_bound());
|
||||
|
||||
if (target != nullptr)
|
||||
{
|
||||
ASSERT(target_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
|
||||
ASSERT(target->sa_family == AF_INET);
|
||||
}
|
||||
|
||||
const auto& all_interfaces = NetworkManager::get().interfaces();
|
||||
|
||||
const auto bound_ipv4 = BAN::IPv4Address {
|
||||
reinterpret_cast<const sockaddr_in*>(&m_address)->sin_addr.s_addr
|
||||
};
|
||||
|
||||
// find the bound interface
|
||||
if (bound_ipv4 != 0)
|
||||
{
|
||||
for (const auto& interface : all_interfaces)
|
||||
{
|
||||
const auto netmask = interface->get_netmask();
|
||||
if (bound_ipv4.mask(netmask) != interface->get_ipv4_address().mask(netmask))
|
||||
continue;
|
||||
if (target && !can_interface_send_to(*interface, target, target_len))
|
||||
continue;
|
||||
return interface;
|
||||
}
|
||||
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
}
|
||||
|
||||
// try to find an interface in the same subnet as target
|
||||
if (target != nullptr)
|
||||
{
|
||||
const auto target_ipv4 = BAN::IPv4Address {
|
||||
reinterpret_cast<const sockaddr_in*>(target)->sin_addr.s_addr
|
||||
};
|
||||
|
||||
for (const auto& interface : all_interfaces)
|
||||
{
|
||||
const auto netmask = interface->get_netmask();
|
||||
if (target_ipv4.mask(netmask) == interface->get_ipv4_address().mask(netmask))
|
||||
return interface;
|
||||
}
|
||||
}
|
||||
|
||||
// return any interface (prefer non-loopback)
|
||||
for (const auto& interface : all_interfaces)
|
||||
if (interface->type() != NetworkInterface::Type::Loopback)
|
||||
if (!target || can_interface_send_to(*interface, target, target_len))
|
||||
return interface;
|
||||
for (const auto& interface : all_interfaces)
|
||||
if (interface->type() == NetworkInterface::Type::Loopback)
|
||||
if (!target || can_interface_send_to(*interface, target, target_len))
|
||||
return interface;
|
||||
|
||||
return BAN::Error::from_errno(EHOSTUNREACH);
|
||||
}
|
||||
|
||||
void NetworkSocket::bind_address_and_port(const sockaddr* addr, socklen_t addr_len)
|
||||
{
|
||||
ASSERT(!is_bound());
|
||||
ASSERT(addr->sa_family != AF_UNSPEC);
|
||||
ASSERT(addr_len <= static_cast<socklen_t>(sizeof(sockaddr_storage)));
|
||||
|
||||
memcpy(&m_address, addr, addr_len);
|
||||
m_address_len = addr_len;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(int request, void* arg)
|
||||
|
|
@ -30,12 +115,8 @@ namespace Kernel
|
|||
dprintln("No argument provided");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
if (m_interface == nullptr)
|
||||
{
|
||||
dprintln("No interface bound");
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
}
|
||||
|
||||
auto interface = TRY(this->interface(nullptr, 0));
|
||||
auto* ifreq = reinterpret_cast<struct ifreq*>(arg);
|
||||
|
||||
switch (request)
|
||||
|
|
@ -44,7 +125,7 @@ namespace Kernel
|
|||
{
|
||||
auto& ifru_addr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
|
||||
ifru_addr.sin_family = AF_INET;
|
||||
ifru_addr.sin_addr.s_addr = m_interface->get_ipv4_address().raw;
|
||||
ifru_addr.sin_addr.s_addr = interface->get_ipv4_address().raw;
|
||||
return 0;
|
||||
}
|
||||
case SIOCSIFADDR:
|
||||
|
|
@ -52,15 +133,15 @@ namespace Kernel
|
|||
auto& ifru_addr = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
|
||||
if (ifru_addr.sin_family != AF_INET)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
m_interface->set_ipv4_address(BAN::IPv4Address { ifru_addr.sin_addr.s_addr });
|
||||
dprintln("IPv4 address set to {}", m_interface->get_ipv4_address());
|
||||
interface->set_ipv4_address(BAN::IPv4Address { ifru_addr.sin_addr.s_addr });
|
||||
dprintln("IPv4 address set to {}", interface->get_ipv4_address());
|
||||
return 0;
|
||||
}
|
||||
case SIOCGIFNETMASK:
|
||||
{
|
||||
auto& ifru_netmask = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_netmask);
|
||||
ifru_netmask.sin_family = AF_INET;
|
||||
ifru_netmask.sin_addr.s_addr = m_interface->get_netmask().raw;
|
||||
ifru_netmask.sin_addr.s_addr = interface->get_netmask().raw;
|
||||
return 0;
|
||||
}
|
||||
case SIOCSIFNETMASK:
|
||||
|
|
@ -68,15 +149,15 @@ namespace Kernel
|
|||
auto& ifru_netmask = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_netmask);
|
||||
if (ifru_netmask.sin_family != AF_INET)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
m_interface->set_netmask(BAN::IPv4Address { ifru_netmask.sin_addr.s_addr });
|
||||
dprintln("Netmask set to {}", m_interface->get_netmask());
|
||||
interface->set_netmask(BAN::IPv4Address { ifru_netmask.sin_addr.s_addr });
|
||||
dprintln("Netmask set to {}", interface->get_netmask());
|
||||
return 0;
|
||||
}
|
||||
case SIOCGIFGWADDR:
|
||||
{
|
||||
auto& ifru_gwaddr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_gwaddr);
|
||||
ifru_gwaddr.sin_family = AF_INET;
|
||||
ifru_gwaddr.sin_addr.s_addr = m_interface->get_gateway().raw;
|
||||
ifru_gwaddr.sin_addr.s_addr = interface->get_gateway().raw;
|
||||
return 0;
|
||||
}
|
||||
case SIOCSIFGWADDR:
|
||||
|
|
@ -84,13 +165,13 @@ namespace Kernel
|
|||
auto& ifru_gwaddr = *reinterpret_cast<const sockaddr_in*>(&ifreq->ifr_ifru.ifru_gwaddr);
|
||||
if (ifru_gwaddr.sin_family != AF_INET)
|
||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||
m_interface->set_gateway(BAN::IPv4Address { ifru_gwaddr.sin_addr.s_addr });
|
||||
dprintln("Gateway set to {}", m_interface->get_gateway());
|
||||
interface->set_gateway(BAN::IPv4Address { ifru_gwaddr.sin_addr.s_addr });
|
||||
dprintln("Gateway set to {}", interface->get_gateway());
|
||||
return 0;
|
||||
}
|
||||
case SIOCGIFHWADDR:
|
||||
{
|
||||
auto mac_address = m_interface->get_mac_address();
|
||||
auto mac_address = interface->get_mac_address();
|
||||
ifreq->ifr_ifru.ifru_hwaddr.sa_family = AF_INET;
|
||||
memcpy(ifreq->ifr_ifru.ifru_hwaddr.sa_data, &mac_address, sizeof(mac_address));
|
||||
return 0;
|
||||
|
|
@ -98,9 +179,9 @@ namespace Kernel
|
|||
case SIOCGIFNAME:
|
||||
{
|
||||
auto& ifrn_name = ifreq->ifr_ifrn.ifrn_name;
|
||||
ASSERT(m_interface->name().size() < sizeof(ifrn_name));
|
||||
memcpy(ifrn_name, m_interface->name().data(), m_interface->name().size());
|
||||
ifrn_name[m_interface->name().size()] = '\0';
|
||||
ASSERT(interface->name().size() < sizeof(ifrn_name));
|
||||
memcpy(ifrn_name, interface->name().data(), interface->name().size());
|
||||
ifrn_name[interface->name().size()] = '\0';
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ namespace Kernel
|
|||
}
|
||||
|
||||
return_inode->m_mutex.lock();
|
||||
return_inode->m_port = m_port;
|
||||
return_inode->m_interface = m_interface;
|
||||
memcpy(&return_inode->m_address, &connection.target.address, connection.target.address_len);
|
||||
return_inode->m_address_len = connection.target.address_len;
|
||||
return_inode->m_listen_parent = this;
|
||||
return_inode->m_connection_info.emplace(connection.target);
|
||||
return_inode->m_recv_window.start_seq = connection.target_start_seq;
|
||||
|
|
@ -152,13 +152,18 @@ namespace Kernel
|
|||
};
|
||||
|
||||
if (!is_bound())
|
||||
TRY(m_network_layer.bind_socket_to_unused(this, address, address_len));
|
||||
TRY(m_network_layer.bind_socket_with_target(this, address, address_len));
|
||||
|
||||
m_connection_info.emplace(sockaddr_storage {}, address_len, true);
|
||||
memcpy(&m_connection_info->address, address, address_len);
|
||||
|
||||
m_next_flags = SYN;
|
||||
TRY(m_network_layer.sendto(*this, {}, address, address_len));
|
||||
if (m_network_layer.sendto(*this, {}, address, address_len).is_error())
|
||||
{
|
||||
set_connection_as_closed();
|
||||
return BAN::Error::from_errno(ECONNREFUSED);
|
||||
}
|
||||
|
||||
m_next_flags = 0;
|
||||
m_state = State::SynSent;
|
||||
|
||||
|
|
@ -410,8 +415,8 @@ namespace Kernel
|
|||
memset(&header, 0, sizeof(TCPHeader));
|
||||
memset(header.options, TCPOption::End, m_tcp_options_bytes);
|
||||
|
||||
header.src_port = bound_port();
|
||||
header.dst_port = dst_port;
|
||||
header.src_port = m_port;
|
||||
header.seq_number = m_send_window.current_seq + m_send_window.has_ghost_byte;
|
||||
header.ack_number = m_recv_window.start_seq + m_recv_window.data_size + m_recv_window.has_ghost_byte;
|
||||
header.data_offset = (sizeof(TCPHeader) + m_tcp_options_bytes) / sizeof(uint32_t);
|
||||
|
|
@ -423,7 +428,15 @@ namespace Kernel
|
|||
|
||||
if (m_state == State::Closed || m_state == State::SynReceived)
|
||||
{
|
||||
add_tcp_header_option<0, TCPOption::MaximumSeqmentSize>(header, m_interface->payload_mtu() - m_network_layer.header_size());
|
||||
const sockaddr_in target {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = dst_port,
|
||||
.sin_addr = { .s_addr = pseudo_header.dst_ipv4.raw },
|
||||
.sin_zero = {},
|
||||
};
|
||||
auto interface = MUST(this->interface(reinterpret_cast<const sockaddr*>(&target), sizeof(target)));
|
||||
|
||||
add_tcp_header_option<0, TCPOption::MaximumSeqmentSize>(header, interface->payload_mtu() - m_network_layer.header_size());
|
||||
|
||||
if (m_connection_info->has_window_scale)
|
||||
add_tcp_header_option<4, TCPOption::WindowScale>(header, m_recv_window.scale_shift);
|
||||
|
|
@ -451,11 +464,16 @@ namespace Kernel
|
|||
|
||||
if (sender->sa_family == AF_INET)
|
||||
{
|
||||
auto interface_or_error = interface(sender, sender_len);
|
||||
if (interface_or_error.is_error())
|
||||
return;
|
||||
auto interface = interface_or_error.release_value();
|
||||
|
||||
auto& addr_in = *reinterpret_cast<const sockaddr_in*>(sender);
|
||||
checksum = calculate_internet_checksum(buffer,
|
||||
PseudoHeader {
|
||||
.src_ipv4 = BAN::IPv4Address(addr_in.sin_addr.s_addr),
|
||||
.dst_ipv4 = m_interface->get_ipv4_address(),
|
||||
.dst_ipv4 = interface->get_ipv4_address(),
|
||||
.protocol = NetworkProtocol::TCP,
|
||||
.extra = buffer.size()
|
||||
}
|
||||
|
|
@ -663,11 +681,11 @@ namespace Kernel
|
|||
// NOTE: Only listen socket can unbind the socket as
|
||||
// listen socket is always alive to redirect packets
|
||||
if (!m_listen_parent)
|
||||
m_network_layer.unbind_socket(m_port);
|
||||
m_network_layer.unbind_socket(bound_port());
|
||||
else
|
||||
m_listen_parent->remove_listen_child(this);
|
||||
m_interface = nullptr;
|
||||
m_port = PORT_NONE;
|
||||
m_address.ss_family = AF_UNSPEC;
|
||||
m_address_len = 0;
|
||||
dprintln_if(DEBUG_TCP, "Socket unbound");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,15 +30,15 @@ namespace Kernel
|
|||
UDPSocket::~UDPSocket()
|
||||
{
|
||||
if (is_bound())
|
||||
m_network_layer.unbind_socket(m_port);
|
||||
m_port = PORT_NONE;
|
||||
m_interface = nullptr;
|
||||
m_network_layer.unbind_socket(bound_port());
|
||||
m_address.ss_family = AF_UNSPEC;
|
||||
m_address_len = 0;
|
||||
}
|
||||
|
||||
void UDPSocket::add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader)
|
||||
{
|
||||
auto& header = packet.as<UDPHeader>();
|
||||
header.src_port = m_port;
|
||||
header.src_port = bound_port();
|
||||
header.dst_port = dst_port;
|
||||
header.length = packet.size();
|
||||
header.checksum = 0;
|
||||
|
|
@ -115,7 +115,6 @@ namespace Kernel
|
|||
dprintln("No interface bound");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
ASSERT(m_port != PORT_NONE);
|
||||
|
||||
SpinLockGuard guard(m_packet_lock);
|
||||
|
||||
|
|
@ -176,7 +175,7 @@ namespace Kernel
|
|||
dwarnln("ignoring sendmsg control message");
|
||||
|
||||
if (!is_bound())
|
||||
TRY(m_network_layer.bind_socket_to_unused(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
|
||||
TRY(m_network_layer.bind_socket_with_target(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
|
||||
|
||||
const size_t total_send_size =
|
||||
[&message]() -> size_t {
|
||||
|
|
|
|||
Loading…
Reference in New Issue