Build the harness with -fpack-struct=1 and assert the frame struct sizes,
so the host reads wire bytes the way the firmware lays them out. Add
scenarios for a port that regains edge after a hold, one that heard a BPDU
and stays non-edge, auto-edge switched off, and a captured RouterOS BPDU
fed in on every port, tagged and untagged.
stp_loop_hold_peer() takes operEdge away from the port that sent the
BPDU we got back, though that port heard nothing itself. When the hold
ran out the port stayed non-edge until its next link change, and every
later state change on it counted as a topology change. Restore edge when
the hold ends with the port still silent and auto-edge on, before the
transition is reported, so the recovery itself is not a change. Hellos
go out on edge ports too, so a loop that persists is caught again.
The console column that shows seconds since the last BPDU is now called
age[s]; it never was a receive count.