Files
vt1200/lat/local/HANDOFF.md
T

235 lines
9.0 KiB
Markdown

# latd ↔ VT1200 — status, instructions & handoff
**Current state: latd is STOPPED.** No `latd`, `login`, `osc-filter.py` or
`tcpdump` processes remain; `lat/local/run/` is empty. Everything is inside
`lat/` — nothing was installed system-wide.
Root of this directory = `lat/` (referred to as `$LAT` below).
```
$LAT = /home/arti/code/k-space/vt1200/lat
```
---
## 1. Endpoint facts (needed to reproduce)
| Thing | Value |
|---|---|
| VT1200 LAT/Ethernet MAC | `08:00:2b:16:4b:5a` |
| VT1200 IP | `100.103.100.103` |
| Host interface on that segment | `enp197s0f3u1` (host `100.103.255.254`) |
| latd node name | `SID` (this host's hostname) |
| LAT Ethertype | `0x6004` |
| LAT service-announcement multicast | `09:00:2b:00:00:0f` |
**Important:** the VT1200's *LAT Terminal Window* connects by default to the
service named after the **latd node name** (`SID`), i.e. the node-name service —
not to a service you type, unless you type one explicitly.
---
## 2. One-command workflow (`lat/run-local.sh`)
```sh
cd $LAT
sudo ./run-local.sh build # bootstrap + configure + make -> lat/local/build-debug/
sudo ./run-local.sh start # start latd + apply group/service config
sudo ./run-local.sh status # show config + advertised services
sudo ./run-local.sh capture # tcpdump LAT frames to lat/local/capture-*.pcap
sudo ./run-local.sh stop # stop latd
sudo ./run-local.sh restart
```
Env overrides:
```sh
IFACE=enp197s0f3u1 VARIANT=debug sudo -E ./run-local.sh start
# IFACE interface latd uses (default enp197s0f3u1)
# VARIANT release|debug (default debug; debug = verbose, -DNO_FORK)
```
`build` writes its output to `lat/local/build.log`.
`start` writes the verbose latd log to `lat/local/latd.log`.
### What `start` does
1. `setsid latcp -s -d -v -v -i $IFACE` (foreground/verbose latd, detached)
2. `latcp -m 10` — advertise every 10 s
3. `latcp -G 1` — advertise in group 1 (must match the VT1200's group code)
4. **removes** the default `SID` service, then re-adds `SID` and `VT1200` both
running `$LAT/tools/osc-filter.py`
> The default service that latd creates at startup is named after the node
> (`SID`) and runs `/bin/login` **unfiltered** — it must be replaced, or the
> VT1200 will freeze on it. `latcp -A` on an existing name fails
> ("Local service already exists"), so `start` deletes it first.
---
## 3. Manual equivalent (exactly how it was run by hand)
All commands run as root (`sudo`). `BUILD` below is the chosen build dir.
### Build
```sh
cd $LAT/code/latd && ./bootstrap.sh # only once; needs autoconf+automake
# release build
mkdir -p $LAT/local/build && cd $LAT/local/build
../../code/latd/configure \
--with-latcp-socket=$LAT/local/run/latcp \
--with-llogin-socket=$LAT/local/run/latlogin
make -j"$(nproc)"
# verbose/debug build (what was used for the investigation)
mkdir -p $LAT/local/build-debug && cd $LAT/local/build-debug
../../code/latd/configure --enable-debug \
--with-latcp-socket=$LAT/local/run/latcp \
--with-llogin-socket=$LAT/local/run/latlogin
make -j"$(nproc)"
```
`--enable-debug` adds `-g3 -O0 -DVERBOSE_DEBUG -DNO_FORK`; the running latd was
the debug one. Sockets are kept under `lat/local/run/` (configure options), so
nothing lands in `/var/run`. `/etc/latd.conf` does not exist, so no global
startup script is run.
### Run
```sh
cd $LAT/local/build-debug
sudo setsid ./latcp -s -d -v -v -i enp197s0f3u1 >$LAT/local/latd.log 2>&1 </dev/null &
sudo ./latcp -m 10
sudo ./latcp -G 1
sudo ./latcp -D -a SID # drop the unfiltered default
sudo ./latcp -A -a SID -i 'filtered login (node name)' -r 100 -C $LAT/tools/osc-filter.py
sudo ./latcp -A -a VT1200 -i 'filtered login' -r 100 -C $LAT/tools/osc-filter.py
sudo ./latcp -d # verify
sudo ./latcp -h # stop
```
### Capture / decode
```sh
sudo tcpdump -i enp197s0f3u1 -w $LAT/local/out.pcap 'ether proto 0x6004'
tshark -r $LAT/local/out.pcap -T fields -e frame.number -e eth.src \
-e lat.msg_typ -e lat.slot.type -e lat.slot.slot_data
tshark -r $LAT/local/out.pcap -Y 'lat.msg_typ==10' -V -O lat # announcements
```
---
## 4. Root cause of the "login hangs" behaviour
Modern Linux writes **OSC strings** (`ESC ] … BEL` / `ESC ] … ESC \`) into the
terminal stream. The VT1200's 1990 terminal emulator is not a general VT
emulator for control strings and **locks up** on them. Sources observed here:
| Source | Sequence | Guard |
|---|---|---|
| `pam_systemd` (via `login`) | `OSC 3008 type=session` | only if `TERM` != `dumb` (`pam_systemd.c`: `if (streq_ptr(term,"dumb")) return PAM_SUCCESS;`) |
| `/etc/profile.d/80-systemd-osc-context.sh` | `OSC 3008 type=shell/command` | bash-only; skipped when `TERM=dumb` |
| `~/.config/zsh/functions/semantic-prompt.zsh` | `OSC 133`, `OSC 122` | **none** — unconditional |
| `~/.config/zsh/functions/osc7-pwd.zsh` | `OSC 7` | **none** — unconditional |
Evidence: `vt-session.pcap` — latd sends a 222-byte `OSC 3008` then a 160-byte
prompt containing `OSC 133`, after which the VT1200 never transmits again.
Confirmation: a service running a bare `/bin/sh` (no OSC) works.
Upstream context: systemd issues #38527 and #41973.
Because the zsh scripts emit OSC unconditionally, `TERM=dumb` alone is not
enough — the output must be filtered.
---
## 5. Fix: `lat/tools/osc-filter.py`
A pty filter used as the latd service command (default inner command
`/bin/login`):
- forks `login` on an **inner** pty and relays both directions;
- drops control strings (`ESC ]` OSC, `ESC P` DCS, `ESC X` SOS, `ESC ^` PM,
`ESC _` APC) from child→terminal; keeps all CSI (e.g. colours);
- handles sequences split across reads;
- puts the **outer** pty (latd's) into **raw mode**, so it is a transparent pipe
— this is what makes passwords hidden (no local echo) and makes `^C` reach
`login` (no `ISIG` on the outer tty).
Verified locally against the exact captured `OSC 3008` / `OSC 133` bytes.
**Status:** with the filter, login and authentication succeeded on the VT1200
and the password/`^C` problems were fixed by the raw-mode change. The **final
test produced a VT1200 coredump** — see §7.
---
## 6. Pitfalls / gotchas learned
- The VT1200 connects to the **node-name service (`SID`)** by default; that
service is created by latd **unfiltered**. Always replace/re-point it.
- `latcp -A` refuses an existing service name ("Local service already exists");
delete with `latcp -D -a NAME` first.
- Services need **group 1** on both ends (`latcp -G 1` + the terminal's
`Customize → LAT…` group code), or they won't appear in the VT's list.
- `latcp -s` runs `/etc/latd.conf` if it exists (hardcoded) — it does not here.
- `latd` must be started via `latcp -s` (it refuses `LATCP_STARTED` otherwise);
`-C <cmd>` and `-u <user>` on `latcp -A` set the service's command/user.
- Don't `pkill -f 'login -- …'` — the pattern matches your own shell; use
`pkill -x login`.
---
## 7. VT1200 CRASH (open item for the next session)
During the last test (login via `osc-filter.py`, outer pty in raw mode) the
**terminal crashed with a coredump**. This may be a usefully reachable firmware
bug — the whole `EXPLOIT_NOTES.md` effort is about exactly that.
- Capture of that session: **`lat/local/filter-test2.pcap`** (547 LAT frames).
- Related earlier capture (OSC leaking, using the unfiltered `SID`):
`lat/local/filter-test.pcap`.
Suggested next steps: replay/step the frames in `filter-test2.pcap`, isolate the
byte sequence that trips the firmware, and compare against `vt-session.pcap`
(which merely froze, no crash).
---
## 8. Evidence / artifacts (`lat/local/`)
| File | What |
|---|---|
| `filter-test2.pcap` | capture around the run that **crashed** the VT1200 |
| `filter-test.pcap` | earlier filtered attempt where OSC still leaked (unfiltered `SID`) |
| `vt-session.pcap` | the original freeze, with the `OSC 3008` + `OSC 133` payloads |
| `probe.pcap`, `lat-announce.pcap`, `session-*.pcap` | service announcements / early probes |
| `latd.log` | full verbose latd log (sessions, slots, credits) |
| `build.log` | last `run-local.sh build` output |
| `svc-plain.sh`, `svc-osc.sh` | A/B probe scripts used to confirm the OSC trigger |
| `HANDOFF.md` | this file |
Other relevant paths:
```
lat/code/latd/ # latd 1.36 source (GPL-2.0)
lat/manuals/ # DEC LAT specification + network manager's guide
lat/tools/osc-filter.py # the filter
lat/run-local.sh # build/run/capture helper
lat/local/build/ # release build
lat/local/build-debug/ # debug build (used for the investigation)
```
---
## 9. Remaining open items
1. Reproduce/root-cause the **VT1200 coredump** from `filter-test2.pcap` (§7).
2. Set a proper `TERM` for the VT1200 session (currently unset) — e.g. `vt220`.
3. Decide the service naming (node-name `SID` vs an explicit `VT1200`).
4. Optional: build latd with `--disable-defservice` so the unfiltered default
service never exists (then `run-local.sh` needn't delete `SID`).