Kernel: Allow network interface ioctls on interfaces

previously it was only on the sockets
This commit is contained in:
2026-05-23 13:02:43 +03:00
parent c72f2f9b31
commit d266d2ca88
3 changed files with 100 additions and 67 deletions

View File

@@ -65,6 +65,9 @@ namespace Kernel
}
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) = 0;
private:
BAN::ErrorOr<long> ioctl_impl(int, void*) override;
private:
const Type m_type;
char m_name[10];

View File

@@ -3,6 +3,8 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Networking/NetworkInterface.h>
#include <netinet/in.h>
#include <net/if.h>
#include <sys/sysmacros.h>
#include <string.h>
@@ -25,7 +27,7 @@ namespace Kernel
}
NetworkInterface::NetworkInterface(Type type)
: CharacterDevice(0400, 0, 0)
: CharacterDevice(0664, 0, 0)
, m_type(type)
{
m_rdev = get_rdev(type);
@@ -43,4 +45,95 @@ namespace Kernel
}
}
BAN::ErrorOr<long> NetworkInterface::ioctl_impl(int request, void* arg)
{
if (arg == nullptr)
{
dprintln("No argument provided");
return BAN::Error::from_errno(EINVAL);
}
auto* ifreq = reinterpret_cast<struct ifreq*>(arg);
switch (request)
{
case SIOCGIFADDR:
{
auto& ifru_addr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
ifru_addr.sin_family = AF_INET;
ifru_addr.sin_addr.s_addr = get_ipv4_address().raw;
return 0;
}
case SIOCSIFADDR:
{
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);
set_ipv4_address(BAN::IPv4Address { ifru_addr.sin_addr.s_addr });
dprintln("IPv4 address set to {}", 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 = get_netmask().raw;
return 0;
}
case SIOCSIFNETMASK:
{
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);
set_netmask(BAN::IPv4Address { ifru_netmask.sin_addr.s_addr });
dprintln("Netmask set to {}", 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 = get_gateway().raw;
return 0;
}
case SIOCSIFGWADDR:
{
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);
set_gateway(BAN::IPv4Address { ifru_gwaddr.sin_addr.s_addr });
dprintln("Gateway set to {}", get_gateway());
return 0;
}
case SIOCGIFHWADDR:
{
auto mac_address = 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;
}
case SIOCGIFNAME:
{
auto& ifrn_name = ifreq->ifr_ifrn.ifrn_name;
ASSERT(name().size() < sizeof(ifrn_name));
memcpy(ifrn_name, name().data(), name().size());
ifrn_name[name().size()] = '\0';
return 0;
}
case SIOCGIFFLAGS:
{
int flags = 0;
if (link_up())
flags |= IFF_UP | IFF_RUNNING;
if (m_type == Type::Loopback)
flags |= IFF_LOOPBACK;
ifreq->ifr_ifru.ifru_flags = flags;
return 0;
}
}
return CharacterDevice::ioctl_impl(request, arg);
}
}

View File

@@ -110,83 +110,20 @@ namespace Kernel
BAN::ErrorOr<long> NetworkSocket::ioctl_impl(int request, void* arg)
{
if (!arg)
{
dprintln("No argument provided");
return BAN::Error::from_errno(EINVAL);
}
auto interface = TRY(this->interface(nullptr, 0));
auto* ifreq = reinterpret_cast<struct ifreq*>(arg);
switch (request)
{
case SIOCGIFADDR:
{
auto& ifru_addr = *reinterpret_cast<sockaddr_in*>(&ifreq->ifr_ifru.ifru_addr);
ifru_addr.sin_family = AF_INET;
ifru_addr.sin_addr.s_addr = interface->get_ipv4_address().raw;
return 0;
}
case SIOCSIFADDR:
{
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);
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 = interface->get_netmask().raw;
return 0;
}
case SIOCSIFNETMASK:
{
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);
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 = interface->get_gateway().raw;
return 0;
}
case SIOCSIFGWADDR:
{
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);
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 = 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;
}
case SIOCGIFNAME:
{
auto& ifrn_name = ifreq->ifr_ifrn.ifrn_name;
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:
return BAN::Error::from_errno(EINVAL);
return TRY(interface(nullptr, 0))->ioctl(request, arg);
}
return Socket::ioctl_impl(request, arg);
}
BAN::ErrorOr<void> NetworkSocket::getsockname_impl(sockaddr* address, socklen_t* address_len)