The pods do TCP/IP over Ethernet (WATTCP + NetNub real-mode server; ops console is master, pushes mission eggs to pods over TCP). Pod is a static host on an isolated 200.0.0.0/24 LAN (200.0.0.113, console 200.0.0.1); -egg is the dev bypass of this path. Fork already has NE2000 + pcap/slirp backends; since the emulated card is NE2000 not PCI Lance we skip the Novell ODI chain and load a Crynwr NE2000 packet driver directly. NET-NOTES.md has the full architecture + milestone plan (headline goal: host-side stand-in console pushes an egg over the wire, no -egg bypass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
5.6 KiB
Networking subsystem — recon & bring-up plan
Goal: bring the pod network up under the emulator so a pod boots the
production way (netnub -f BTL4OPT, mission egg delivered over the
wire) instead of the -egg test.egg dev bypass. This is also the
substrate the ops-console port will plug into.
What the pod network actually is (recon 2026-07-04)
The stack, bottom to top:
- Ethernet NIC + Novell ODI (AUTOEXEC.BAT):
lsl(Link Support Layer) →lnepci(Lance/PCnet PCI ODI driver) →odipkt(Dan Lanciani's ODI→Packet-Driver shim). The ODI/Netware login side (IPXODI/VLM/NET LOGIN in STARTNET.BAT) is for file-server access; the game itself only needs the packet-driver interface odipkt exposes.NET.CFG: LNEPCI, FRAME Ethernet_II + 802.2. - WATTCP — the TCP/IP stack. Confirmed by
WATTCP.CFGinREL410/BT,REL410/RP, and per-podVGL_LABS/THISPOD:So each pod is a static host on an isolated 200.0.0.0/24 LAN; the ops console is almost certainly 200.0.0.1.my_ip = 200.0.0.113 netmask = 255.255.255.0 gateway = 200.0.0.1 nameserver = 200.0.0.1 - NetNub (
netnub.exe, real-mode) — launches the game as a child (netnub -f BTL4OPT) and is the network server for the protected-mode game. Interface (NetNub/NETNUB.HPP): a sharedNetcomstruct (version 11, 64KB buffer) + a software interrupt. The game sets a Function code (TCP_OPEN=3, TCP_LISTEN=4, TCP_CLOSE=5, RESOLVE_ADDRESS=6, CHECK_SOCKET=7, UDP_*, plus remote file OPEN/READ/WRITE/SEEK/CLOSE 12-19), copies the marked fields to real mode, INTs, copies back.tcp_Socketis ~4300 bytes = classic WATTCP. - L4NetworkManager (
L4NET.HPP/.TCP) — the game's net brick. The console is master and connects to the pods; the pod receivesReceiveEggFileMessage(the mission egg), repliesAcknowledgeEggFileMessage("connected, ready, send the next host"), and tracksHostConnected/HostDisconnected. If the console drops, the pod is built to auto-start anyway.
Topology to replicate:
[ops console 200.0.0.1] --TCP--> [pod 200.0.0.113] (+ more pods .114..)
(master, egg source) (listens, ACKs, runs mission)
Emulator enablers (already in the fork)
- NE2000 ISA NIC emulated (
hardware/ne2000.cpp, Bochs-derived); config[ne2000] ne2000=true, nicbase=, nicirq=, macaddr=, backend=. - Two Ethernet backends built:
misc/ethernet_pcap.cpp(bridge to a host NIC via npcap) andmisc/ethernet_slirp.cpp(user-mode virtual net / NAT). Plusethernet_nothing.
Key simplification: the emulated card is an NE2000, not a PCI Lance, so
lnepci won't bind. We don't need the Novell ODI chain at all — WATTCP
finds a packet driver by scanning INT 0x60-0x80 for the PKT DRVR
signature, so we load a generic NE2000 packet driver (Crynwr
NE2000.COM) directly against the emulated card's base/IRQ. That drops
lsl/lnepci/odipkt/VLM entirely and hands NetNub/WATTCP the packet
interface they expect.
Bring-up plan
Backend choice. Two viable paths:
- pcap + host-only adapter (recommended, matches real topology): bridge the NE2000 to a host virtual switch; run the pod at 200.0.0.113 and the stand-in console at 200.0.0.1 on that segment. WATTCP's static IP + LAN assumptions hold exactly; the console connects inbound to the pod with no NAT. Cost: npcap + a host-only/loopback adapter + admin.
- slirp (fallback, self-contained): no host NIC/admin, but it's NAT and defaults to 10.0.2.0/24 — the pod LISTENS, so inbound needs slirp host-forwarding and a guest-network/IP reconciliation with WATTCP's hard-coded 200.0.0.113. Investigate whether DOSBox-X slirp allows the custom net + static guest IP + inbound forward cleanly.
Milestones
- NIC up:
[ne2000]on, NE2000.COM packet driver loaded, WATTCP/ NetNub start clean; pod boots vianetnub -f BTL4OPT(no-egg) and sits waiting for the console. Verify NetNub reports net address 200.0.0.113 and a TCP_LISTEN is queued. (New scratch conf, mirror the RIO/sound conf pattern.) - L3/L4 reachability: from the host segment, confirm the pod answers ARP/ping at 200.0.0.113 and a raw TCP connect to its listen port completes (proves NE2000↔backend↔host path end-to-end).
- Decode the console→pod egg protocol:
NetworkPacketHeader+ message framing fromnetwork.hpp/hostmgr.hpp+ the ReceiveEggFileMessage layout, cross-checked with a live capture of the pod's listen/ACK. (Pin the listen port here — not yet found in source; grep NETNUB.EXE strings / capture.) - Eggs over the wire: a minimal host-side stand-in console
(Python) connects to the pod, pushes a mission egg, handles the ACK →
pod runs the mission with no
-eggbypass. This is the headline goal. - (later, joins the console-port workstream): replace the stand-in with the ported/emulated Mac ops console; multi-pod coordination (HostConnected/Disconnected, mission review, camera ship).
Open questions / notes
- Exact TCP listen port(s) — not in the source grep; get from NETNUB.EXE or a capture at milestone 3.
- Does WATTCP need a real ARP peer for the gateway at boot, or does it proceed with a static IP and only ARP on connect? Affects whether the stand-in console must answer ARP for 200.0.0.1.
NETCLIENT=PNW(PARAMETR.bat) selects Personal NetWare — file-server side, not the game's TCP path; likely irrelevant to egg delivery and can stay unloaded under emulation.- RP uses the identical MUNGA net brick + its own WATTCP.CFG — everything here carries over to Red Planet.