diff --git a/emulator/NET-NOTES.md b/emulator/NET-NOTES.md new file mode 100644 index 0000000..b721e9b --- /dev/null +++ b/emulator/NET-NOTES.md @@ -0,0 +1,109 @@ +# 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: + +1. **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. +2. **WATTCP** — the TCP/IP stack. Confirmed by `WATTCP.CFG` in + `REL410/BT`, `REL410/RP`, and per-pod `VGL_LABS/THISPOD`: + ``` + my_ip = 200.0.0.113 netmask = 255.255.255.0 + gateway = 200.0.0.1 nameserver = 200.0.0.1 + ``` + 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**. +3. **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 shared `Netcom` + struct (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_Socket` is ~4300 bytes = classic WATTCP. +4. **L4NetworkManager** (`L4NET.HPP/.TCP`) — the game's net brick. The + **console is master and connects to the pods**; the pod receives + `ReceiveEggFileMessage` (the mission egg), replies + `AcknowledgeEggFileMessage` ("connected, ready, send the next host"), + and tracks `HostConnected/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) and `misc/ethernet_slirp.cpp` (user-mode virtual + net / NAT). Plus `ethernet_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** +1. **NIC up**: `[ne2000]` on, NE2000.COM packet driver loaded, WATTCP/ + NetNub start clean; pod boots via `netnub -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.) +2. **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). +3. **Decode the console→pod egg protocol**: `NetworkPacketHeader` + + message framing from `network.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.) +4. **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 `-egg` bypass. **This is the headline + goal.** +5. *(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.