diff --git a/core/libs/prx/libc/src/Interfaces.cpp b/core/libs/prx/libc/src/Interfaces.cpp index 7e8aadef3..3391a0705 100644 --- a/core/libs/prx/libc/src/Interfaces.cpp +++ b/core/libs/prx/libc/src/Interfaces.cpp @@ -89,6 +89,13 @@ std::size_t Aligned(std::size_t size) { return (size + 7) & ~static_cast(7); } +std::vector BroadcastAddress(const std::vector& address, const std::vector& netmask) { + std::vector broadcast = address; + for (std::size_t index = 4; index < 8; ++index) + broadcast[index] = static_cast(address[index] | static_cast(~netmask[index])); + return broadcast; +} + #ifdef _WIN32 std::vector PrefixMask(int family, unsigned prefix) { const unsigned bits = family == AF_INET ? 32 : 128; @@ -98,13 +105,6 @@ std::vector PrefixMask(int family, unsigned prefix) { return family == AF_INET ? GuestIpv4(mask) : GuestIpv6(mask, 0); } -std::vector BroadcastAddress(const std::vector& address, const std::vector& netmask) { - std::vector broadcast = address; - for (std::size_t index = 4; index < 8; ++index) - broadcast[index] = static_cast(address[index] | static_cast(~netmask[index])); - return broadcast; -} - std::uint32_t InterfaceFlags(const IP_ADAPTER_ADDRESSES* adapter) { std::uint32_t flags = 0; if (adapter->OperStatus == IfOperStatusUp) flags |= guestUp | guestRunning; @@ -179,8 +179,14 @@ int HostEntries(std::vector& entries) { if (!item->ifa_addr || (item->ifa_addr->sa_family != AF_INET && item->ifa_addr->sa_family != AF_INET6)) continue; if (!item->ifa_netmask) throw std::runtime_error(std::string("getifaddrs: host address without a netmask on ") + item->ifa_name); Entry entry{CheckedName(item->ifa_name), InterfaceFlags(item->ifa_flags), GuestAddress(item->ifa_addr), GuestAddress(item->ifa_netmask), {}}; - const sockaddr* destination = item->ifa_flags & IFF_POINTOPOINT ? item->ifa_dstaddr : item->ifa_flags & IFF_BROADCAST ? item->ifa_broadaddr : nullptr; - if (destination && destination->sa_family == item->ifa_addr->sa_family) entry.destination = GuestAddress(destination); + const int family = item->ifa_addr->sa_family; + if (item->ifa_flags & IFF_POINTOPOINT) { + if (item->ifa_dstaddr && item->ifa_dstaddr->sa_family == family) entry.destination = GuestAddress(item->ifa_dstaddr); + else entry.flags &= ~guestPointToPoint; + } else if (family == AF_INET && (item->ifa_flags & IFF_BROADCAST)) { + entry.destination = item->ifa_broadaddr && item->ifa_broadaddr->sa_family == AF_INET + ? GuestAddress(item->ifa_broadaddr) : BroadcastAddress(entry.address, entry.netmask); + } entries.push_back(std::move(entry)); } } catch (...) { diff --git a/core/libs/tests/GuestInterfaces.cpp b/core/libs/tests/GuestInterfaces.cpp index 634b1b728..eeb24342a 100644 --- a/core/libs/tests/GuestInterfaces.cpp +++ b/core/libs/tests/GuestInterfaces.cpp @@ -131,6 +131,12 @@ int main() { Require(reinterpret_cast(netmask) % 8 == 0); Require((address[0] == 16 && address[1] == 2) || (address[0] == 28 && address[1] == 28)); Require(netmask[0] == address[0] && netmask[1] == address[1]); + Require(address[2] == 0 && address[3] == 0 && netmask[2] == 0 && netmask[3] == 0); + if (address[1] == 2) { + for (std::size_t index = 8; index < 16; ++index) Require(address[index] == 0 && netmask[index] == 0); + } else { + for (std::size_t index = 4; index < 8; ++index) Require(address[index] == 0 && netmask[index] == 0); + } if (item->destination) { const auto* destination = static_cast(item->destination); Require(reinterpret_cast(destination) % 8 == 0); diff --git a/docs/dev/TechnicalDebt.md b/docs/dev/TechnicalDebt.md index ba94c676f..04c942ac6 100644 --- a/docs/dev/TechnicalDebt.md +++ b/docs/dev/TechnicalDebt.md @@ -438,4 +438,4 @@ Throughout the project, every function at every stage either **does exactly what - [sigaction](../../core/libs/prx/libkernel/System/src/Signals.cpp) (libkernel) records the handler, flags and mask of every signal from 1 to 128 and reports them back, following FreeBSD's `sigaction` (`EINVAL` for other signals, and for a handler on `SIGKILL` or `SIGSTOP`); `signal` records its handler with `SA_RESTART`, as FreeBSD's libc does. Only handlers without `SA_SIGINFO` on the signals `signal` already delivers (`SIGINT`, `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGTERM`) run, the same way `signal` handlers do; their mask and flags are not applied. `SA_SIGINFO` handlers and other signals (`SIGBUS`, `SIGHUP`, ...) are recorded but never called, since that needs FreeBSD's `siginfo_t` and `ucontext_t`; `raise` of an `SA_SIGINFO` handler on a signal `signal` delivers throws instead of terminating, and `raise` of the other signals still returns `EINVAL` - [AJM](../../core/libs/prx/libSceAjm.native/src/Ajm.cpp), [APR](../../core/libs/prx/libkernel/Apr/src/Apr.cpp) and [NGS2](../../core/libs/prx/libSceNgs2.native/src/System.cpp) state is allocated with `new` and never freed on purpose: title threads still call into these libraries while `std::exit` runs static destructors, so ordinary statics would be destroyed under them. Keep them leaked; `guest_ajm_teardown` covers the AJM case on Unix. - [Null vertex buffer V#](../../core/libs/prx/libSceAgcDriver/Graphics/include/VertexInput.hpp) (libSceAgcDriver) - a V# whose four dwords are all zero is bound to a zeroed vertex buffer of the attribute's size with stride 0, so every component of its attribute reads 0. This follows the V# fields in the [AMD RDNA2 ISA](https://gpuopen.com/download/rdna2-shader-instruction-set-architecture.pdf) (`NUM_RECORDS` 0, `DST_SEL` 0 selects 0), not measured on hardware. -- [getifaddrs](../../core/libs/prx/libc/src/Interfaces.cpp) (libc) lists the host's IPv4 and IPv6 addresses in FreeBSD's `ifaddrs` and sockaddr layouts. FreeBSD's per-interface AF_LINK entries (MAC, index, MTU) and their `if_data` are not produced, so interfaces without an address are omitted. Names are the host's (Linux `lo`, `eth0`; Windows NDIS names such as `ethernet_32769`, or `if` when one does not fit 15 bytes), not the console's. On Windows the flags are derived from the adapter: PPP and tunnel adapters get neither `IFF_BROADCAST` nor `IFF_POINTOPOINT` because their peer address is not reported, and an address whose prefix length the host reports as unspecified gets a host mask. +- [getifaddrs](../../core/libs/prx/libc/src/Interfaces.cpp) (libc) lists the host's IPv4 and IPv6 addresses in FreeBSD's `ifaddrs` and sockaddr layouts. FreeBSD's per-interface AF_LINK entries (MAC, index, MTU) and their `if_data` are not produced, so interfaces without an address are omitted. Names are the host's (Linux `lo`, `eth0`; Windows NDIS names such as `ethernet_32769`, or `if` when one does not fit 15 bytes), not the console's. A Linux point-to-point address without a peer loses `IFF_POINTOPOINT`, and an IPv4 broadcast address the host omits is computed from the netmask. On Windows the flags are only `IFF_UP`, `IFF_RUNNING`, `IFF_LOOPBACK`, `IFF_BROADCAST` and `IFF_MULTICAST`, derived from the adapter: PPP and tunnel adapters get neither `IFF_BROADCAST` nor `IFF_POINTOPOINT` because their peer address is not reported, and an address whose prefix length the host reports as unspecified gets a host mask.