stp: pass a received topology change through the switch

The tree structure already crossed the switch by regeneration, but the
topology-change information did not: a received TC flag was ignored and
a TCN only acknowledged, so bridges behind this one kept stale entries
until normal aging.

A TC flag in a received BPDU now flushes the other non-edge ports once
and arms the transmit window our BPDUs already copy the flag from,
refreshed to hello+1 seconds by every further flagged frame so it ends
one hello after the neighbour stops, without shortening the longer
window a local change arms. A TCN is acknowledged as before and then
treated like a local change on that port.
This commit is contained in:
d00f
2026-08-18 23:30:44 +02:00
parent 201c7e333d
commit 78b3971782
2 changed files with 38 additions and 3 deletions
+25 -3
View File
@@ -501,12 +501,14 @@ void stp_in(void) __banked
if (STP_I->bpdu_type == 0x80) {
/* TCN: a downstream bridge reports a topology change. Acknowledge it
* on this port so the sender stops repeating; the change itself is
* counted (and, once implemented, propagated rootward). */
* on this port so the sender stops repeating, then treat it like a
* change of our own: flush the port and carry the TC flag on the
* designated ports for the full window. No TCN goes towards the
* root, so a legacy root further up keeps its normal aging. */
stp_tx_flags_extra = 0x80; /* Topology Change Acknowledgment */
stp_cnf_send(port); /* transmits internally */
uip_len = 0; /* ...so handle_rx must not TX again */
stp_tc_count++;
stp_topology_change(port);
return;
}
@@ -563,6 +565,26 @@ void stp_in(void) __banked
return;
}
/* Topology Change in transit. The flag arms a short window that our
* own BPDUs copy downstream (the TX side already sends TC while
* stp_tc_while runs) and that each further flagged BPDU refreshes, so
* it expires one hello after the neighbour stops - without shortening
* the long window a local change may have armed. The flush runs once,
* on the arming edge: everything learned on the other non-edge ports
* may sit behind the moved link and must be relearned. */
if (STP_I->flags & 0x01) {
if (!stp_tc_while) {
uint8_t i;
stp_tc_count++;
for (i = machine.min_port; i <= machine.max_port; i++)
if (i != port && (stp_pflags[i] & STP_PF_ENABLED)
&& !(stp_pflags[i] & STP_PF_OPEREDGE))
port_l2_forget_port(i);
}
if (stp_tc_while < ((uint16_t)stp_hello_s + 1) * STP_HZ)
stp_tc_while = ((uint16_t)stp_hello_s + 1) * STP_HZ;
}
stp_record_designated(port);
/* Better root than the one we know? The identifier is priority, system