rooklz read sceNetConfigGetDefaultRoute (NID lFJb+BlPK1c, wrapper at
0x153f0) in libSceNet.sprx. Before sceNetInit it returns 0x804101C8
with errno 200. Without a default route it returns 0x8041130C and
leaves the output alone. With one it stores the route and returns 1,
not 0. The wrapper never checks the output pointer.
The not-initialized answer reads the library's sceNetInit/sceNetTerm
flag through fail(), as the other exports do. The route is still the
host gateway. A null output with a route throws std::invalid_argument,
where the module faults.
Co-authored-by: rooklz <[email protected]>
rooklz read sceNetInetNtopWithScopeId (FUN_00006be0) and
sceNetInetPtonWithScopeId (FUN_000072d0) in libSceNet.sprx. The zone
after '%' is one of the ten interface names, never a number, and ntop
prints the name of the interface whose index is the scope. A null
address or text and a short buffer set ENOSPC, and another family sets
EAFNOSUPPORT. Pton reads a zone only when the scope output is not null,
and answers another family with EAFNOSUPPORT and a null text with
EINVAL.
The host has none of these interfaces. Names and indexes go through the
interface table and host-index mapping of rooklz's "feat(net): resolve
interface ids to host indexes", taken with the same text so the two
changes merge without conflict there. A null destination throws
std::invalid_argument, where the module faults.
Co-authored-by: rooklz <[email protected]>
sceNetResolverStartNtoa refuses a timeout from 1 to 999999 with EINVAL
before the resolver is looked up, and takes 0 as 1000000, as a run of
firmware 13.42's module shows.
On Windows, std::tmpfile() returns NULL with errno 22 when %TEMP%
contains a character outside the ANSI code page. Thirteen more test
files still called it: the AGC async log, frame dump, PM4 replay and
recorder tests, eight AGC execution tests and the SceNet test. They
now use TemporaryFile::Open(), as #13104 did for the libc tests.
Part of #13083
Co-Authored-By: Claude Opus 5.5 <[email protected]>
GuestSceNet checked only a host-refused protocol. CheckSocketArgumentErrors
adds the errors FreeBSD's socreate gives before any protocol lookup:
an unknown family (AF_UNSPEC, 99) fails with EAFNOSUPPORT even with an
unknown type, and an unknown type (0, SOCK_RDM, 99) with protocol 6 on
IPv4 and IPv6 fails with EPROTONOSUPPORT, in the 0x80410100 | errno form.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceNetGetStatisticsInfo threw NotImplemented_nid_no_patch. It now fills
the six 32-bit fields of the statistics block (kernel memory free and
minimum free, packet count, QoS packet count, library memory free and
minimum free) and fails with NET_EFAULT, setting errno, for a null
pointer. The layout and the "plenty free, nothing queued" answer follow
shadPS4's net.cpp and net_types.h; the host has no counter for the
console's network memory, so the values are not measured. The debt file
records this, and the test checks the null pointer, the field
invariants and that the flags argument is ignored.
sceNetShowIfconfigWithMemory, sceNetShowPolicyWithMemory and
sceNetShowRoute6WithMemory threw NotImplemented_nid_no_patch. They now
behave like the existing sceNetShowRouteWithMemory: an unknown memory
pool id fails with NET_EBADF (errno set), a live pool returns success
without printing. The behaviour follows shadPS4's net.cpp, which does
the same for these three. The new silent stubs are listed in the
libSceNet technical debt file, and the tests cover the invalid id, live
pool and destroyed pool cases.
Since #9137 both throw after sceNetInit. A PS5 on firmware 13.40
returns 0 from each and prints plain-text tables to stdout. They now
print the console's layout with what the emulator knows: ifconfig an
eth0 block from the host interface sceNetCtlGetInfo reports (the same
MAC, address, netmask and MTU), the console's lo0 block and the DNS
servers; netstat the header and one entry per socket and epoll of the
title, with the self and non-blocking flags, addresses, buffer sizes and
the names given to sceNetSocket and sceNetEpollCreate, which are now
kept. The debt entry lists what the console prints that is left out.
guest_sce_net captures both outputs: the lo0 block and DNS section, a
named unbound UDP socket, a non-blocking listening TCP socket bound to
127.0.0.1, an epoll, a 40-character name cut to 31, and the entries gone
after close.
The named zone "fe80::1%lo0", the two AF_INET scope conversions and
sceNetConfigGetDefaultRoute with a valid output and no host gateway are
valid but unimplemented forms; tests no longer pin them as throws. The
malformed and null-pointer checks, the numeric IPv6 round trips and the
success controls stay.
Copy the iovec table only when there is one, and receive a datagram
with no iovecs in guest_sce_net: it returns 0 with MSG_TRUNC and the
sender's address.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sceNetRecvmsg guarded the destinations of the iovec table it saw at
entry, then read the live table again to scatter the received bytes.
When an earlier destination overlapped a later iovec, the received
bytes replaced that iovec and the rest of the data went to an address
that was never guarded, which crashed the host when that address was
not writable. Copy the header and the iovec table once, as FreeBSD
11.4's sys_recvmsg does with copyin and copyiniov, use that copy for
the guards, the scatter and the address, and write the header back
from it as sys_recvmsg's copyout does.
Fixes#11610
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Firmware 13.42's module looks the name up with sceNetGetIfName, which
has none past 9, then issues SIOCGIFFLAGS on the empty name. That ioctl
fails, and the call returns -1 with the flags untouched. Return the
same instead of throwing. Interfaces 1 to 9 still throw, and the test
no longer asserts that for 1 and 4, which the console answers from the
kernel.
Asked for in oneandonlydean's review, from BunnyFl's read of the
module.
Human Fall Flat (PPSA02429) opens its sockets with libkernel's socket()
and reads options of them with sceNetGetsockopt. libSceNet only looked
in its own socket table, so each call failed with SCE_NET_ERROR_EBADF.
On the console both calls work on the same kernel sockets, the position
sceNetSetsockopt already takes for MXGP 26 (PPSA30839).
A descriptor libSceNet does not own but libkernel has open as a socket
now goes to libkernel's getsockopt(), which answers the options it
models. Anything else still fails with EBADF. The fallback runs after
g_mutex is released.
guest_sce_net reads SO_SNDBUF and TCP_NODELAY of a libkernel TCP socket
through sceNetGetsockopt, checks that an unknown level fails with
EINVAL, and that the call fails with EBADF once the socket is closed.
Human Fall Flat (PPSA02429) opens its sockets with libkernel's socket()
and registers them with sceNetEpollControl. libSceNet only looked in its
own socket table, so every ADD and DEL failed with SCE_NET_ERROR_EBADF.
The game retries without pause: on box 2 it made more than 1.6 million
failing calls on 14 descriptors in its first seconds, all of them
libkernel sockets.
sceNetEpollControl now accepts a descriptor libkernel has open as a
socket, as sceNetSocketClose and sceNetSetsockopt already do for MXGP 26
(PPSA30839). sceNetEpollWait looks up the host socket of such a
registration through libkernel after g_mutex is released, because that
lookup asks libSceNet's own table for descriptors libkernel does not
own, and keeps the owner alive across the host poll. libkernel's close()
retires the registrations of the closed socket; a wait drops a
registration whose socket is gone.
guest_sce_net registers a libkernel UDP socket, waits for it to become
readable and then writable, deletes it twice, closes registered sockets
through close() and sceKernelClose and waits again, and checks that a
descriptor that was never open still fails with EBADF.
sceNetEpollCreate fails with EINVAL for a null name or non-zero flags,
sceNetResolverCreate and sceNetGetMacAddress for non-zero flags, and
sceNetResolverStartNtoa, before any other check, for a negative timeout
or retry count or a flag bit outside 0x10001, as prosper reads the
libSceNet module. The two accepted resolver flag bits are still ignored,
which the debt file now records.
Apply the firmware 13.42 module-probe report in PR #9506: all four DNS calls check initialization first; getters return EINVAL for null outputs or nonzero flags; setters reject flags before reading guest memory. Keep the checked input copy and document EFAULT as host safety, not firmware behavior. Use the current public Net.hpp declarations in the regression.
Rebased onto upstream e7e3e9c198. Ubuntu 24.04, GCC 13.3, Release: actual libc/libkernel/libSceNet libraries and both focused test executables built. guest_sce_net passes. A separate harness linked against those unmodified libraries passes initialization, errno, invalid flags, unreadable-input flag precedence, null clearing and unchanged-output checks. The full guest_net_dns_info test is blocked here: process_vm_readv is denied with EPERM by the execution environment. No full DNS regression pass is claimed. Public-header audit, conventions, test registration and whitespace checks pass.
The resolver still uses host DNS; IPv6 host-server discovery and firmware server-count behavior remain debt. Firmware evidence: https://github.com/boykopovar/AnyPS5/pull/9506#issuecomment-6390574180
AI-assisted: yes
Main's #10706 removes the local declarations at the top of libSceNet's
Export.cpp, where this branch had added __inet_pton and __inet_ntop.
libkernel's Api.hpp, which Export.cpp includes, now declares both, so the
merge takes main's side there.
BunnyFl measured both calls in firmware 13.42 libSceNet.sprx, run in an
emulator on the module itself. sceNetInitParam returns 0x80410116 for a
null parameter. The first non-null call copies the first 32 bytes of the
parameter and returns 0, and every later call returns 0x80410110, with a
null parameter and after sceNetTerm too, because the flag is never
cleared. sceNetConfigGetIfFlags returns 0x8041130E for a null flags
pointer before anything else. Both replace throws that stood in for the
unknown answers.
The first successful sceNetInitParam still marks the library initialized,
as sceNetInit does here, because the other calls check it. The module
reads only bit 0 of the stored copy's first word, to raise the pool limit
of sceNetPoolCreate from 32 to 128; that limit is recorded as not
modelled, as sceNetPoolCreate here has none.
Main extends the libkernel debt entry on libSceNet sockets with poll and
fcntl, where this branch adds getsockopt to the same entry; the merge keeps
both.
Main extends the libkernel debt entry on libSceNet sockets with poll and
fcntl, where this branch adds getsockopt to the same entry; the merge keeps
both.