/* * Net.hpp * Networking syscalls: SYS_PING, SYS_SOCKET, SYS_CONNECT, SYS_BIND, * SYS_LISTEN, SYS_ACCEPT, SYS_SEND, SYS_RECV, SYS_CLOSESOCK, * SYS_SENDTO, SYS_RECVFROM, SYS_GETNETCFG, SYS_SETNETCFG, SYS_RESOLVE * Copyright (c) 2026 Daniel Hammer */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "Syscall.hpp" namespace montauk::abi { static uint16_t g_pingSeq = 0; static constexpr uint16_t PING_ID = 0x2E01; // "ZE" static int32_t Sys_Ping(uint32_t ipAddr, uint32_t timeoutMs) { uint16_t seq = g_pingSeq++; Net::Icmp::ResetReply(); Net::Icmp::SendEchoRequest(ipAddr, PING_ID, seq); uint64_t start = Timekeeping::GetMilliseconds(); while (!Net::Icmp::HasReply(PING_ID, seq)) { if (Timekeeping::GetMilliseconds() - start >= timeoutMs) { return -1; } Sched::Schedule(); } return (int32_t)(Timekeeping::GetMilliseconds() - start); } // ---- Socket syscalls ---- static int Sys_Socket(int type) { return Net::Socket::Create(type, Sched::GetCurrentPid()); } static int Sys_Connect(int fd, uint32_t ip, uint16_t port) { return Net::Socket::Connect(fd, ip, port, Sched::GetCurrentPid()); } static int Sys_Bind(int fd, uint16_t port) { return Net::Socket::Bind(fd, port, Sched::GetCurrentPid()); } static int Sys_Listen(int fd) { return Net::Socket::Listen(fd, Sched::GetCurrentPid()); } static int Sys_Accept(int fd) { return Net::Socket::Accept(fd, Sched::GetCurrentPid()); } static int Sys_Send(int fd, const uint8_t* data, uint32_t len) { return Net::Socket::Send(fd, data, len, Sched::GetCurrentPid()); } static int Sys_Recv(int fd, uint8_t* buf, uint32_t maxLen) { return Net::Socket::Recv(fd, buf, maxLen, Sched::GetCurrentPid()); } static void Sys_CloseSock(int fd) { Net::Socket::Close(fd, Sched::GetCurrentPid()); } static int Sys_SendTo(int fd, const uint8_t* data, uint32_t len, uint32_t destIp, uint16_t destPort) { return Net::Socket::SendTo(fd, data, len, destIp, destPort, Sched::GetCurrentPid()); } static int Sys_RecvFrom(int fd, uint8_t* buf, uint32_t maxLen, uint32_t* srcIp, uint16_t* srcPort) { // A preceding UDP send may be queued while ARP resolves the next hop. // Drive the pending IPv4 queue on each non-blocking receive so a lost // initial ARP request is retried without unrelated network traffic. Net::Ipv4::FlushPending(); return Net::Socket::RecvFrom(fd, buf, maxLen, srcIp, srcPort, Sched::GetCurrentPid()); } static void Sys_GetNetCfg(NetCfg* out) { if (out == nullptr) return; out->ipAddress = Net::GetIpAddress(); out->subnetMask = Net::GetSubnetMask(); out->gateway = Net::GetGateway(); // Whichever interface is carrying traffic; on a Wi-Fi link this is the // adapter's MAC, not an idle Ethernet port's. const uint8_t* mac = ::Net::NetIf::ActiveMac(); if (mac) { for (int i = 0; i < 6; i++) out->macAddress[i] = mac[i]; } else { for (int i = 0; i < 6; i++) out->macAddress[i] = 0; } out->_pad[0] = 0; out->_pad[1] = 0; out->dnsServer = Net::GetDnsServer(); } static void CopyNetStatusDriver(char* dst, const char* src) { static constexpr uint64_t DriverNameBytes = 32; if (!dst) return; uint64_t i = 0; for (; i < DriverNameBytes - 1 && src && src[i]; i++) { dst[i] = src[i]; } dst[i] = '\0'; } // Reports whichever interface is currently carrying traffic, so a machine // that joined a Wi-Fi network sees the wireless counters here rather than // an idle Ethernet port. static void Sys_NetStatus(NetStatus* out) { if (out == nullptr) return; out->initialized = 0; out->linkUp = 0; out->polling = 0; out->_pad0 = 0; out->rxPackets = 0; out->txPackets = 0; CopyNetStatusDriver(out->driver, "No adapter"); const auto* iface = ::Net::NetIf::Active(); if (iface == nullptr) return; out->initialized = 1; out->linkUp = iface->IsLinkUp() ? 1 : 0; if (iface->Type == ::Net::NetIf::Kind::Wireless) { WifiInfo wi; if (Drivers::Net::Wifi::GetInfo(&wi) == 0) { out->rxPackets = wi.rxPackets; out->txPackets = wi.txPackets; } CopyNetStatusDriver(out->driver, "Intel Wi-Fi (wlan0)"); } else if (Drivers::Net::E1000::IsInitialized()) { out->rxPackets = Drivers::Net::E1000::GetRxPacketCount(); out->txPackets = Drivers::Net::E1000::GetTxPacketCount(); CopyNetStatusDriver(out->driver, "Intel 82540EM"); } else if (Drivers::Net::E1000E::IsInitialized()) { out->polling = Drivers::Net::E1000E::RequiresPolling() ? 1 : 0; out->rxPackets = Drivers::Net::E1000E::GetRxPacketCount(); out->txPackets = Drivers::Net::E1000E::GetTxPacketCount(); CopyNetStatusDriver(out->driver, "Intel e1000e"); } } // List the registered link-layer interfaces. The panel needs this to keep // wired and wireless status apart: the IP configuration is global, so the // only way to say which interface owns it is `active`. static int Sys_NetIfs(NetIfInfo* out, int maxCount) { if (out == nullptr || maxCount <= 0) return -1; const auto* active = ::Net::NetIf::Active(); int count = ::Net::NetIf::Count(); int n = 0; for (int i = 0; i < count && n < maxCount; i++) { const auto* iface = ::Net::NetIf::At(i); if (iface == nullptr) continue; NetIfInfo& info = out[n]; for (uint64_t k = 0; k < sizeof(info.name); k++) info.name[k] = '\0'; for (uint64_t k = 0; k + 1 < sizeof(info.name) && iface->Name && iface->Name[k]; k++) info.name[k] = iface->Name[k]; const uint8_t* mac = iface->GetMac ? iface->GetMac() : nullptr; for (int k = 0; k < 6; k++) info.mac[k] = mac ? mac[k] : 0; info.kind = iface->Type == ::Net::NetIf::Kind::Wireless ? NETIF_KIND_WIRELESS : NETIF_KIND_ETHERNET; info.linkUp = (iface->IsLinkUp && iface->IsLinkUp()) ? 1 : 0; info.active = iface == active ? 1 : 0; info._pad[0] = info._pad[1] = info._pad[2] = 0; n++; } return n; } static int Sys_SetNetCfg(const NetCfg* in) { if (in == nullptr) return -1; Net::SetIpAddress(in->ipAddress); Net::SetSubnetMask(in->subnetMask); Net::SetGateway(in->gateway); Net::SetDnsServer(in->dnsServer); return 0; } // ---- DNS resolve ---- static int64_t Sys_Resolve(const char* hostname) { uint32_t ip = Net::Dns::Resolve(hostname); return (int64_t)ip; } };