bank_occupancy.sh takes the main and branch build directories as
optional arguments and prints a markdown table, so CI calls it instead
of a second script. It gains the HOME, BANK4 and stack rows, and reads
the web assets from the build directory, where html_min is now.
A port named in the CLI or the web UI (port <n> name ...) now carries
that name in a Port Description TLV, so a neighbour sees "Uplink" next
to "Port 9". The tail of the frame is built per port, since the TLV
length differs from port to port; ports without a name send no TLV.
The bank growth step only exported the sizes to the environment since the
comment that used them was removed, so nothing showed them any more. It now
writes a table of the code banks, XSEG, the stack left after the internal
RAM is allocated and the web assets, main against the branch, to the job
summary, which needs no write permission on the pull request.
The mcs51 library target writes into ../build/$(PORT) without depending on
it, so with -j the archiver can start before the directory exists and the
toolchain build fails with
sdar: ../build/small/mcs51.lib: No such file or directory
It is intermittent: the same tree builds fine on a retry.
The port ID in the BPDUs was the chip port plus one, so on most boards
it did not match the port label, neither on the Spanning Tree page nor
on the neighbour. Send the front panel number instead, and 101 and up
for the LAGs, the same numbers the page already uses for the Port
column. A returned BPDU of our own is mapped back to the port by that
number.
Scenario 66 gives one port a front panel number that differs from its
chip port.
send_lldp(), send_eee(), send_bandwidth(), send_storm(), send_mtu() and
send_status() wrote the closing ']' inside the loop, on the last port.
Write it once after the loop, as send_isolation() already does, so the
array is closed however the loop ends.
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.
stp_reselect() took every port with fresh information as a candidate, so a
BPDU credited to a port whose carrier the once-a-second link poll had not
seen yet made that port the root port before the port was set up for it.
A candidate now needs its link bit as well; the poll that sees the carrier
a moment later runs the selection again. Scenario 54.
stp_in() propagated the TC flag of any BPDU that did not arrive on an
alternate port, and acknowledged and propagated a TCN from any port, so a
port still in its listen period or held discarding in a dispute could flush
the addresses of every other port and move the topology change counter.
802.1D-2004 17.31 keeps the Topology Change machine in LEARNING until the
port forwards and drops rcvdTc and rcvdTcn there. Both paths now ask for
the forwarding state first; an alternate port is discarding, so the old
check is covered by the new one.
Scenario 53 plays a TC flag and a TCN into a port that is still discarding,
and then into the same port once it forwards. Scenario 51 used a TCN on a
port one tick short of its edge transition as the trigger for the clock it
tests; it now waits for the transition.
The frame the simulator builds carries a vlan_tag between the RTL tag and the BPDU, but left its TPID zero. stp_in() now takes the body offset from TRAP_RX_BODY(), which reads those two bytes, so it took the untagged branch and parsed the body four bytes early. Writing 0x8100 makes the frame what its layout says it is.
Reception moved to the RMA trap in main, so rtl837x_stp.c calls trap_rma_set() from stp_setup() and stp_off(). The simulator defines neither, so it does not link. Linking rtl837x_trap.c instead would pull trap_init() and the register primitives it needs, which the simulator does not mock.
stp_sim.c declared variables in the middle of the scenarios and put
whole loops and conditions on one line. Each block now starts with its
declarations; an initializer that depends on what happens before it
stays where it was as an assignment. Bodies of if and for are on lines
of their own, functions are separated by an empty line, and lines stay
within 120 columns. The output of stp_sim -v is unchanged.