Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions core/libs/prx/libSceNet/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,9 @@ int APS5_VABI sceNetClearDnsCache(int flags) {
}

int APS5_VABI sceNetGetStatisticsInfo(NetStatisticsInfo* info, std::uint32_t flags) {
NotImplemented_nid_no_patch(__func__);
if (info == nullptr) return fail(NET_EFAULT);
constexpr std::int32_t FREE_BYTES = 16 * 1024 * 1024;
*info = {FREE_BYTES, FREE_BYTES, 0, 0, FREE_BYTES, FREE_BYTES};
return 0;
}

Expand All @@ -2560,7 +2562,8 @@ int APS5_VABI sceNetSetDnsInfo(const NetDnsInfo* info, std::uint32_t flags) {
}

int APS5_VABI sceNetShowIfconfigWithMemory(std::int32_t poolId) {
NotImplemented_nid_no_patch(__func__);
std::lock_guard lk(g_mutex);
if (g_pools.find(poolId) == g_pools.end()) return fail(NET_EBADF);
return 0;
}

Expand All @@ -2569,7 +2572,8 @@ int APS5_VABI sceNetShowPolicy(void) {
}

int APS5_VABI sceNetShowPolicyWithMemory(std::int32_t poolId) {
NotImplemented_nid_no_patch(__func__);
std::lock_guard lk(g_mutex);
if (g_pools.find(poolId) == g_pools.end()) return fail(NET_EBADF);
return 0;
}

Expand Down Expand Up @@ -2619,7 +2623,8 @@ int APS5_VABI sceNetShowRoute6(void) {
}

int APS5_VABI sceNetShowRoute6WithMemory(std::int32_t poolId) {
NotImplemented_nid_no_patch(__func__);
std::lock_guard lk(g_mutex);
if (g_pools.find(poolId) == g_pools.end()) return fail(NET_EBADF);
return 0;
}

Expand Down
9 changes: 8 additions & 1 deletion core/libs/prx/libSceNet/include/Net.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,14 @@ struct NetSockInfo6 {
std::int32_t tx_wait;
std::int32_t reserved[2];
};
struct NetStatisticsInfo;
struct NetStatisticsInfo {
std::int32_t kernel_mem_free_size;
std::int32_t kernel_mem_free_min;
std::int32_t packet_count;
std::int32_t packet_qos_count;
std::int32_t libnet_mem_free_size;
std::int32_t libnet_mem_free_min;
};
struct NetInterfaceStats;
struct NetRouteInfo;
struct NetDebugParameter;
Expand Down
26 changes: 26 additions & 0 deletions core/libs/tests/GuestSceNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,15 @@ static void CheckNetstat() {
Require(sceNetShowRoute6() == 0);
Require(Failed(sceNetShowNetstatWithMemory(-1), 9));
Require(Failed(sceNetShowRouteWithMemory(-1), 9));
Require(Failed(sceNetShowIfconfigWithMemory(-1), 9));
Require(Failed(sceNetShowPolicyWithMemory(-1), 9));
Require(Failed(sceNetShowRoute6WithMemory(-1), 9));
const int pool = sceNetPoolCreate("netstat", 4096, 0);
Require(pool > 0);
Require(sceNetShowRouteWithMemory(pool) == 0);
Require(sceNetShowIfconfigWithMemory(pool) == 0);
Require(sceNetShowPolicyWithMemory(pool) == 0);
Require(sceNetShowRoute6WithMemory(pool) == 0);
const auto empty = CaptureNetstat(pool);
Require(empty.find("bytes=4096 sockets=0") != std::string::npos);
const int socket = sceNetSocket("netstat", 2, 1, 0);
Expand All @@ -279,6 +285,9 @@ static void CheckNetstat() {
Require(sceNetPoolDestroy(pool) == 0);
Require(Failed(sceNetShowNetstatWithMemory(pool), 9));
Require(Failed(sceNetShowRouteWithMemory(pool), 9));
Require(Failed(sceNetShowIfconfigWithMemory(pool), 9));
Require(Failed(sceNetShowPolicyWithMemory(pool), 9));
Require(Failed(sceNetShowRoute6WithMemory(pool), 9));
}

static void CheckPoolStats() {
Expand All @@ -292,6 +301,22 @@ static void CheckPoolStats() {
Require(Failed(sceNetGetMemoryPoolStats(pool, &stats), 9));
}

static void CheckStatisticsInfo() {
Require(Failed(sceNetGetStatisticsInfo(nullptr, 0), 14));
NetStatisticsInfo info;
std::memset(&info, 0xaa, sizeof(info));
Require(sceNetGetStatisticsInfo(&info, 0) == 0);
Require(sizeof(info) == 24);
Require(info.kernel_mem_free_size > 0 && info.kernel_mem_free_min > 0);
Require(info.libnet_mem_free_size > 0 && info.libnet_mem_free_min > 0);
Require(info.kernel_mem_free_min <= info.kernel_mem_free_size);
Require(info.libnet_mem_free_min <= info.libnet_mem_free_size);
Require(info.packet_count == 0 && info.packet_qos_count == 0);
NetStatisticsInfo again;
Require(sceNetGetStatisticsInfo(&again, 0x1234) == 0);
Require(std::memcmp(&again, &info, sizeof(info)) == 0);
}

static void CheckIfName() {
constexpr std::array<const char*, 10> names = {
"lo0", "eth0", "eth1", "dbg0", "wlan0", "wlan1", "gbe0", "bt0", "phone0", "pppoe0"};
Expand Down Expand Up @@ -2160,6 +2185,7 @@ int main() {
CheckEpollWritable();
CheckSocketHostErrors();
CheckPoolStats();
CheckStatisticsInfo();
CheckIfName();
CheckRandom();
CheckByteOrderConversion();
Expand Down
3 changes: 2 additions & 1 deletion docs/dev/debt/libSceNet.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# libSceNet technical debt

- [sceNetShowRouteWithMemory, sceNetShowIfconfigWithMemory, sceNetShowPolicyWithMemory, sceNetShowRoute6WithMemory](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) - validates memory pool ID and returns success without printing anything: the `(poolId)` signature and pool validation follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/net/net.cpp) and `sceNetShowNetstatWithMemory`; shadPS4 stubs the Ifconfig, Policy and Route6 forms the same way, validating the pool and returning success. What the console prints and where is unverified
### Silent stubs

- [sceNetShowRouteWithMemory](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) - validates memory pool ID and returns success without printing anything: the `(poolId)` signature and pool validation follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/net/net.cpp) and `sceNetShowNetstatWithMemory`. What the console prints and where is unverified
- [sceNetShowIfconfig, sceNetShowNetstat](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) print the console's layout (a PS5 on firmware 13.40, measured 2026-10-19) with what the emulator knows. Ifconfig prints `eth0` from the host interface `sceNetCtlGetInfo` reports, without its IPv6 address, `UP6`, link status, traffic counters or times, then `lo0` as the console does and the two IPv4 DNS servers, with `::, ::` for IPv6. It leaves out the wireless interfaces and the pool and statistics sections. Netstat lists only the title's sockets and epolls; the console lists every process's. The self and non-blocking flags, addresses, buffer sizes and names are filled; the R, S, RE and SE flags, the field after the type, queue lengths, rates and drops print as for an idle socket, TCP states are only `LISTEN`, `ESTABLISHED` and `CLOSED`, and the self flag on epolls is inferred. Before initialization both return the not-initialized error.
- [sceNetShowPolicy, sceNetShowNetstatEx, sceNetShowRoute, sceNetShowRoute6](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) - return success without printing anything: the `()` signatures and the success return follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/network/net.cpp), which stubs each the same way. PPSA01530 fails to load without the `sceNetShowIfconfig` export (#3177); PPSA11386 imports `sceNetShowNetstat` but does not call it during start-up. What the console prints and where is unverified
- [sceNetGetStatisticsInfo](../../../core/libs/prx/libSceNet/Export.cpp) (libSceNet) - fills the six 32-bit fields (kernel memory free and minimum free, packet count, QoS packet count, library memory free and minimum free) with 16 MiB free, nothing queued and no flag check, and a null pointer fails with `EFAULT`, as [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/net/net.cpp) does; the layout follows its `net_types.h`. The host has no counters for the console's network memory, so the values are not measured and the call works before `sceNetInit`.

### Unknown function info

Expand Down
Loading