Skip to content

net: make src/net_abi.inc the real backend boundary (c64-lib-contract §13, #70) - #142

Open
JC-000 wants to merge 1 commit into
masterfrom
feat/70-net-abi-s13
Open

net: make src/net_abi.inc the real backend boundary (c64-lib-contract §13, #70)#142
JC-000 wants to merge 1 commit into
masterfrom
feat/70-net-abi-s13

Conversation

@JC-000

@JC-000 JC-000 commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Closes #70 (items 1–6 plus the audit's P1/P5; P2/P4/P6 were already discharged by #122 or are gated on the X25519 sibling linking).

What changes

src/net_abi.inc is now the build-enforced boundary: boot.s, http.s, tls_record_io.s and tls13.s .include it and import no net_* symbol directly. ld65 resolves every import whether used or not, so both backends must export the whole core/TCP/DNS surface (SPEC §13.1) or the link fails by name.

ip65 UCI
net_dhcp_acquire / net_local_ip / net_last_error / net_tcp_state / net_resolved_ip added (error codes $41-$45, ip65_errors.inc, the §13.2 ip65 range) already there; net_dhcp alias removed
net_tcp_set_recv_cb deleted (§13.1)
net_print_ip removed → removed → one consumer-side print_local_ip in boot.s reading net_local_ip
net_recv_ready retired (net_recv_byte's C flag is the same test)
NET_TCP_* names used promoted; UCI_TCP_* kept as aliases
tcp_recv_overflow on ring-full (§13.3) already added
net_manifest.s (NET_BACKEND_FAMILIES = CORE|TCP|DNS) + §13.7 blob equates, LIB_NET_IP65_BLOB_SIZE link-asserted against the .incbin span DNS by deferral
$8A UCI_ERR_LONG_READ reserved with c64-wireguard's meaning (not emitted)

Plus src/net/net_families.inc (contract block verbatim, never exported), src/net/net_states.inc, and src/net_abi_asserts.s (§13.8 family asserts; the §13.3 ring-mask assert moved here from lib_contract_asserts.s).

Byte accounting (ip65 is the constraint)

ip65's adapter lives in LOADER, which had 16 B free. The ~95 B of new logic fits in place only because net_print_ip (~83 B) and net_recv_ready (14 B) left first — LOADER now ends with 58 B free. print_local_ip rides LOADER_OVERFLOW (NET_CODE tail) rather than CRYPTO_RESIDENT, deliberately: that is where the next nistcurves bump lands. Cost: the ip65 HTTPS_HOST/HTTPS_PATH tail budget is ~60 B beyond the defaults now; the wikipedia target (+46 B) still builds on both ip65 profiles (14 B to spare on onchip).

NET_BACKEND_FAMILIES is exported : absolute — a byte-sized equate otherwise infers zeropage and ld65 warns (contract #74 recurring in §13.0; noted for the spec).

Evidence

  • Links clean, no ld65 warnings: ip65-plain, uci-plain, ip65-onchip + wikipedia target, uci-comb + wikipedia + HTTPS_BODY_TO_REU=1. PRG sizes unchanged (47,105 / 62,977 B).
  • VICE: test_net.py 65/65 (incl. a new empty-ring net_recv_byte oracle), test_http.py 61/61, test_tls_handshake.py 21/21.
  • U64E, uci-onchip (9e31c1bc…), 48 MHz: boot_check PASS; phase2_check PASS (DHCP via net_dhcp_acquire, net_local_ip = 10.43.23.81 read back over DMA, net_last_error = 0); rig_https_live github.com PASS, HTTP 200, CFIN 48.1 s.
  • rig_https_local FAILs on this branch and identically on master ab5de2b as a control — it sends the listener's IP as the hostname and the v0.4.2 SAN check rejects it. Pre-existing; filed as rig_https_local.py has failed on every UCI image since #135: it sends the listener's IP as the hostname, which the SAN check rejects #141.
  • UCI_TCP_*NET_TCP_* is byte-neutral: same onchip PRG hash before and after.
  • Not run: the ip65 VICE ethernet rig (needs sudo for the feth pair); ip65 is covered at the adapter level by test_net.py.

Cross-repo

🤖 Generated with Claude Code

… §13, #70)

The header used to be documentation: nothing included it, its declared
surface overlapped the used one in 6 of 17 symbols, and the ip65 adapter
had no error channel. Now every network-touching TU (boot, http,
tls_record_io, tls13) `.include`s it and imports no `net_*` directly, so
both backends must export the whole core/TCP/DNS surface or the link
fails by name.

ip65 (the tight one, LOADER had 16 B free):
  - net_dhcp -> net_dhcp_acquire; net_local_ip / net_resolved_ip copied
    from ip65_cfg_ip / ip65_dns_ip_addr on success; net_last_error with
    NET_ERR_IP65_* ($41-$45, ip65_errors.inc, the §13.2 ip65 range);
    net_tcp_state per §13.1.
  - net_print_ip and net_recv_ready left the adapter (below), which is
    what paid for the ~95 B of new logic in place. LOADER ends with
    58 B free instead of 16.
  - net_tcp_recv_cb / net_save_zp / net_restore_zp un-exported (§13.5).
  - net_manifest.s: NET_BACKEND_FAMILIES = CORE|TCP|DNS plus the §13.7
    blob equates, with LIB_NET_IP65_BLOB_SIZE link-asserted against
    ip65_blob_end - ip65_blob_start (labels added around the .incbin).

UCI:
  - net_dhcp alias, net_tcp_set_recv_cb stub and net_print_ip deleted;
    UCI_TCP_* -> NET_TCP_* in code (aliases kept in uci_errors.inc);
    ring-full now sets tcp_recv_overflow (§13.3); $8A UCI_ERR_LONG_READ
    reserved with c64-wireguard's meaning, not emitted.
  - net_manifest.s: CORE|TCP|DNS (DNS by deferral).

Consumer side:
  - src/net/net_families.inc (contract block verbatim, never exported),
    src/net/net_states.inc (NET_TCP_* values), src/net_abi_asserts.s
    (§13.8 family asserts + the §13.3 ring-mask assert moved out of
    lib_contract_asserts.s).
  - print_local_ip in boot.s replaces the two identical per-backend
    net_print_ip routines (§13.1 "deliberately not in the contract"),
    reading the now-ABI net_local_ip; it rides LOADER_OVERFLOW so the
    ip65 LOADER region gains rather than loses. Cost: the ip65
    HTTPS_HOST/HTTPS_PATH tail budget is ~60 B beyond the defaults now;
    the wikipedia target (+46 B) still builds on both ip65 profiles.
  - NET_BACKEND_FAMILIES exported `: absolute` — a byte-sized equate
    otherwise infers zeropage and ld65 warns (contract #74 recurring).

Evidence:
  - ip65-plain, uci-plain, ip65-onchip+wikipedia, uci-comb+wikipedia+
    HTTPS_BODY_TO_REU all link clean, no ld65 warnings; PRG sizes
    unchanged (47,105 / 62,977 B).
  - VICE: test_net.py 65/65, test_http.py 61/61, test_tls_handshake.py
    21/21.
  - U64E (uci-onchip, 48 MHz): boot_check PASS; phase2_check PASS —
    DHCP through net_dhcp_acquire, net_local_ip = 10.43.23.81 read back
    over DMA, net_last_error = 0. rig_https_local FAILs on this branch
    AND on master ab5de2b identically (name check vs the IP-as-hostname
    the rig sends) — filed separately; see the PR for the live-server
    run used instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Align networking surface with c64-lib-contract SPEC §13 (network backend ABI)

1 participant