Skip to content

feat(libSceNet): implement sceNetInitParam and the loopback answer of sceNetConfigGetIfFlags - #10881

Merged
oneandonlydean merged 5 commits into
boykopovar:mainfrom
EagleBearerYS:feat/scenet-config-and-ether-calls
Oct 26, 2026
Merged

oneandonlydean merged 5 commits into
boykopovar:mainfrom
EagleBearerYS:feat/scenet-config-and-ether-calls

Conversation

@EagleBearerYS

@EagleBearerYS EagleBearerYS commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

Two libSceNet calls stop throwing:

  • sceNetInitParam follows libSceNet's own code on firmware 13.42, as BunnyFl measured it (comment): a null parameter returns 0x80410116 (errno 22); the first non-null call stores the parameter's first 32 bytes and returns 0; every later call returns 0x80410110 (errno 16), a null parameter and a call after sceNetTerm included. The first success also marks the library initialized, which main's other calls check. The one field the module reads, bit 0 of the first word, raises sceNetPoolCreate's limit from 32 to 128 pools; main's sceNetPoolCreate has no limit, so the bit is stored but not modelled.
  • sceNetConfigGetIfFlags answers interface 0 (lo0 in the sceNetGetIfName numbering) with IFF_UP | IFF_LOOPBACK | IFF_RUNNING | IFF_MULTICAST (0x8049). That is what FreeBSD 11 reports for a configured loopback: lo_clone_create and loioctl in sys/net/if_loop.c, with if_flags | if_drv_flags as SIOCGIFFLAGS builds it in sys/net/if.c. A null flags pointer returns 0x8041130E before anything else, as measured on 13.42 (comment). Interfaces 1 to 9 throw, because their flags come from the kernel and the library models no other interface. A number of 10 or more returns -1 and leaves flags untouched, as the module does when sceNetGetIfName has no name for it and SIOCGIFFLAGS fails on the empty one (comment); the errno it sets isn't modelled.

Both are recorded under Unknown function info in docs/dev/debt/libSceNet.md.

Related: #9578 (which adds the libSceNetCtl host-gateway hook an eth0 answer would sit beside) and #9515 also edit libSceNet/Export.cpp; this merges cleanly with both.

Tested

  • GitHub's runners: run 40166706454: guest_sce_net passes 10 of 10 on Linux and on Windows, 0 skipped.
  • GitHub's runners, be3f208 (run), the commit that follows the measurement: guest_sce_net passes 10 runs in a row, and fails with e9db171's code. Linux: 1 run, 1 pass, 0 skip, 0 fail. Windows: 1 run, 1 pass, 0 skip, 0 fail. Suites: libc and libkernel pass on Linux (144 and 207) and on Windows (171 and 223). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • Linux (Ubuntu 24.04, gcc 13.3, CI's configure flags):
    • guest_sce_net gains CheckInitParam and CheckIfFlags. Each aborts with its commit's product change reverted (1 of 1 per commit) and passes with it.
    • The new cases need no IPv6; on a host without an IPv6 loopback the executable still ends in its existing skip.
    • The full ctest run: 2,211 tests, 2,116 pass and 90 skipped; the 5 failures are all IPv6 sockets on a VM booted with IPv6 disabled.
  • bf0f293, a merge of main 2b52256 (run). KernelPanicNT's fix(libSceNet): reject the flags and names the module rejects #9727 adds CheckRejectedArguments() to GuestSceNet.cpp's main right where this PR adds CheckIfFlags(); the merge keeps both, and nothing else conflicted. This PR's changed lines are the same as before the merge. guest_sce_net passes 10 runs in a row, and fails on the before arm. Linux: 1 run, 1 pass, 0 skip, 0 fail. Windows: 1 run, 1 pass, 0 skip, 0 fail. Suites: libc and libkernel pass on Linux (144 and 209), and libc passes on Windows (171). Windows' libkernel suite runs 227 tests and fails guest_timed_join_import_libkernel_sys and guest_timed_join_import_libkernel_web, which this PR doesn't touch; main 88f9967 fails the same two in this verify's Windows job (run), and main's own Windows CI passes them. The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.
  • 6f37718, after oneandonlydean's review (run): sceNetConfigGetIfFlags returns -1 with flags untouched for an interface number of 10 or more, as BunnyFl's read of the module shows, instead of throwing. CheckIfFlags asserts that for 10 and 0xffffffff, and no longer asserts that interfaces 1 and 4 (eth0 and wlan0) throw. guest_sce_net passes 10 runs in a row, and fails with bf0f293's code. Linux: 1 run, 1 pass, 0 skip, 0 fail. Windows: 1 run, 1 pass, 0 skip, 0 fail. Suites: libc and libkernel pass on Linux (144 and 209), and libc passes on Windows (171). Windows' libkernel suite runs 227 tests and fails guest_timed_join_import_libkernel_sys and guest_timed_join_import_libkernel_web, the same two as at bf0f293, which this PR doesn't touch (main's run). The suites ran with APS5_SKIP_TIMING_TESTS=1, which relaxes precise_wait's median bounds on GitHub's hosted runners.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

sceNetInitParam initializes the library as sceNetInit does and returns
its result. NetInitializeParameter's layout is unknown, so its fields are
not read; a null parameter throws because its console result is unknown.
sceNetConfigGetIfFlags answers interface 0, lo0 in the sceNetGetIfName
numbering, with IFF_UP | IFF_LOOPBACK | IFF_RUNNING | IFF_MULTICAST, the
flags FreeBSD 11 gives a configured loopback. Other interfaces and a null
flags pointer throw: the library models no other interface.
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Progress report (14c99b5 → 6f37718)

📈 System libraries: 50.57% (+0.01%, +2 implemented functions)

✅ 2 implemented
Library Name
libSceNet sceNetConfigGetIfFlags
libSceNet sceNetInitParam

Changed libraries (implemented exports)

Library Before After Change
libSceNet 77/224 (34.38%) 79/224 (35.27%) +0.89 pp

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 5836 core/libs/prx/libSceNet/Export.cpp
core/libs/tests/GuestSceNet.cpp
docs/dev/debt/libSceNet.md
PR 7201 core/libs/prx/libSceNet/Export.cpp
PR 9932 core/libs/prx/libSceNet/Export.cpp
core/libs/tests/GuestSceNet.cpp
docs/dev/debt/libSceNet.md
PR 9948 core/libs/prx/libSceNet/Export.cpp
core/libs/tests/GuestSceNet.cpp
docs/dev/debt/libSceNet.md
PR 11272 core/libs/prx/libSceNet/Export.cpp
core/libs/tests/GuestSceNet.cpp
docs/dev/debt/libSceNet.md
PR 11341 core/libs/prx/libSceNet/Export.cpp

@MarcZX10

Copy link
Copy Markdown
Contributor

The local tests and the cited FreeBSD 11 source establish the chosen host model, but the core console behavior remains unverified: both the NetInitializeParameter interpretation and the 0x8049 interface flags are explicitly marked unknown. In particular, sceNetInitParam currently returns success for every non-null pointer while ignoring its contents, so callers can receive success without the requested pool parameters being applied. sceNetConfigGetIfFlags similarly reports FreeBSD host loopback flags as the PS5 result. CONTRIBUTING says each function must do exactly what it is supposed to or throw, and unverified behavior belongs in technical debt. Could you add PS5 evidence for these results, or keep the exports throwing until their contracts are established? I have not approved this PR.

@BunnyFl

BunnyFl commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

On the PS5 evidence question: I checked both calls against firmware 13.42 libSceNet.sprx. The results below ran in an emulator on the module itself, twice with identical results, with the kernel calls (socket and ioctl) answered by the harness. Which code reads the stored parameter comes from reading the module.

sceNetInitParam(param)

  • A null param gives 0x80410116 (errno 22).
  • The first non-null call copies the first 32 bytes of param into the library and returns 0. Nothing is checked or applied at the call itself.
  • Every later call gives 0x80410110 (errno 16), with a null param too, and also after sceNetTerm: the flag is set once and never cleared.
  • The only part of the stored copy any code in the module reads is bit 0 of the first 32-bit word (there are 8 references in all: the copy, a zeroing at module start, and six bit-0 tests). With that bit set, sceNetPoolCreate allows 128 pools (IDs 3000–3127) instead of 32 (3000–3031). The next one after the limit gives 0x80410117 (errno 23). Words 1 and 0xffffffff gave 128, 0 and 0xfffffffe gave 32.
  • sceNetInit and sceNetTerm on PS5 are just return 0; they don't initialize anything.

So ignoring the contents loses nothing main models today, since main's sceNetPoolCreate has no pool limit at all. Where the PR differs from 13.42's module is the return values: later calls give 0x80410110 rather than 0, and a null parameter gives 0x80410116 where the PR throws.

sceNetConfigGetIfFlags(ifnum, flags)

  • A null flags gives 0x8041130E, before anything else (the PR throws there).
  • The name comes from sceNetGetIfName: 0..9 are lo0, eth0, eth1, dbg0, wlan0, wlan1, gbe0, bt0, phone0, pppoe0. A number of 10 or more sets errno 22 and the call carries on with an empty name.
  • It then opens an AF_INET datagram socket (failure gives 0x80411301) and issues SIOCGIFFLAGS (0xc0206911) on that name. If the ioctl fails it returns -1 (not an SCE code) and leaves flags untouched. Otherwise it writes the 32-bit flags word from the reply and returns 0. The socket is closed in both cases.
  • The flag value itself comes from the kernel, which isn't in this dump, so 13.42 can't confirm or contradict 0x8049 for lo0.

@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@BunnyFl thank you, that answers it. sceNetInitParam will follow the module: 0x80410116 for a null parameter, the first call storing the 32 bytes and returning 0, and 0x80410110 for every later call, after sceNetTerm too. sceNetConfigGetIfFlags gains the 0x8041130E null check. I'll note the bit-0 pool limit in the debt file, since main's sceNetPoolCreate has no limit yet.

…ags as measured

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.
@Queuse Queuse mentioned this pull request Oct 25, 2026
12 tasks done
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 26, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

@EagleBearerYS Thanks, the sceNetInitParam and lo0 parts look right.

One test change: in CheckIfFlags, interfaces 1 and 4 are eth0 and wlan0 (that's how sceNetGetIfName names them), valid interfaces the console answers from the kernel. Throwing for them is a fine placeholder, but the test shouldn't assert it, because it would fail once they are modelled. Please drop 1 and 4 from the loop.

For 10 and 0xffffffff, BunnyFl's read of the module shows it returns -1 with the flags untouched (the name lookup sets errno 22 and the ioctl on the empty name fails). Please either return that and assert it, or drop those two from the loop as well.

…e number of 10 or more

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.
@EagleBearerYS

Copy link
Copy Markdown
Contributor Author

@oneandonlydean Thanks. Done in 6f37718: 1 and 4 are out of the loop, and an interface number of 10 or more now returns -1 with the flags untouched, as BunnyFl read it; the test asserts that for 10 and 0xffffffff. guest_sce_net passes 10 of 10 on Linux and Windows and fails with the previous head (run).

@oneandonlydean
oneandonlydean merged commit 43c0841 into boykopovar:main Oct 26, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants