mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
stp: answer TCN BPDUs and validate the received BPDU length
Accept legacy Topology Change Notification BPDUs (v0, type 0x80): reply on the ingress port with a Config BPDU carrying Topology Change Acknowledgment so the sender stops repeating, and count the change. Also stop reading fields past the end of short frames: require the header through bpdu_type (33 bytes with the CPU/VLAN prefix) before classifying, and the full 35-byte body before the election logic - truncated or fuzzed BPDUs are dropped instead of parsed as garbage.
This commit is contained in:
+33
-3
@@ -94,6 +94,8 @@ __xdata uint16_t stp_sec_tick; /* 1 s window for the tx budget */
|
|||||||
|
|
||||||
/* Scratch (8051: locals would overflow the internal-RAM overlay area) */
|
/* Scratch (8051: locals would overflow the internal-RAM overlay area) */
|
||||||
__xdata uint8_t stp_scratch;
|
__xdata uint8_t stp_scratch;
|
||||||
|
__xdata uint8_t stp_tx_flags_extra; /* one-shot flags OR-ed into the next BPDU (TCA) */
|
||||||
|
__xdata uint16_t stp_rxlen; /* received frame length, saved before uip_len is consumed */
|
||||||
__xdata uint8_t stp_i; /* shared loop iterator (DSEG relief) */
|
__xdata uint8_t stp_i; /* shared loop iterator (DSEG relief) */
|
||||||
__xdata uint32_t stp_cost_scratch;
|
__xdata uint32_t stp_cost_scratch;
|
||||||
|
|
||||||
@@ -233,6 +235,8 @@ void stp_cnf_send(uint8_t port) __reentrant
|
|||||||
STP_O->bpdu_type = 0x00; /* Config BPDU */
|
STP_O->bpdu_type = 0x00; /* Config BPDU */
|
||||||
STP_O->flags = 0x00;
|
STP_O->flags = 0x00;
|
||||||
}
|
}
|
||||||
|
STP_O->flags |= stp_tx_flags_extra; /* e.g. TCA in reply to a TCN */
|
||||||
|
stp_tx_flags_extra = 0;
|
||||||
|
|
||||||
memcpy(STP_O->src_addr, uip_ethaddr.addr, 6);
|
memcpy(STP_O->src_addr, uip_ethaddr.addr, 6);
|
||||||
memcpy(STP_O->root.mac, root_bridge.mac, 6);
|
memcpy(STP_O->root.mac, root_bridge.mac, 6);
|
||||||
@@ -276,7 +280,16 @@ void stp_cnf_send(uint8_t port) __reentrant
|
|||||||
|
|
||||||
void stp_in(void) __banked
|
void stp_in(void) __banked
|
||||||
{
|
{
|
||||||
// By default we do not send anything out
|
/* Robustness: never read fields past the received frame. 33 covers the
|
||||||
|
* header through bpdu_type; the full Config/RST body is re-checked below.
|
||||||
|
* (uip_len is consumed and zeroed at the end - keep a local view.) */
|
||||||
|
if (uip_len < 33) {
|
||||||
|
uip_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stp_rxlen = uip_len;
|
||||||
|
|
||||||
|
// By default we do not send anything out (handle_rx would TX otherwise)
|
||||||
uip_len = 0;
|
uip_len = 0;
|
||||||
|
|
||||||
/* Ingress port: low nibble of the CPU tag's pmask on RX */
|
/* Ingress port: low nibble of the CPU tag's pmask on RX */
|
||||||
@@ -293,9 +306,11 @@ void stp_in(void) __banked
|
|||||||
return;
|
return;
|
||||||
if (STP_I->proto)
|
if (STP_I->proto)
|
||||||
return;
|
return;
|
||||||
/* Accept RSTP BPDUs (v2 type 2) and legacy Config BPDUs (v0 type 0) */
|
/* Accept RSTP BPDUs (v2 type 2), legacy Config BPDUs (v0 type 0) and
|
||||||
|
* legacy TCN BPDUs (v0 type 0x80, 4-byte body) */
|
||||||
if (!((STP_I->version == 2 && STP_I->bpdu_type == 2)
|
if (!((STP_I->version == 2 && STP_I->bpdu_type == 2)
|
||||||
|| (STP_I->version == 0 && STP_I->bpdu_type == 0)))
|
|| (STP_I->version == 0
|
||||||
|
&& (STP_I->bpdu_type == 0 || STP_I->bpdu_type == 0x80))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(stp_pflags[port] & STP_PF_ENABLED) || (stp_pflags[port] & STP_PF_FILTER))
|
if (!(stp_pflags[port] & STP_PF_ENABLED) || (stp_pflags[port] & STP_PF_FILTER))
|
||||||
@@ -313,6 +328,21 @@ void stp_in(void) __banked
|
|||||||
|
|
||||||
stp_bpdu_age[port] = 0;
|
stp_bpdu_age[port] = 0;
|
||||||
|
|
||||||
|
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). */
|
||||||
|
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++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Everything below reads the full Config/RST body. */
|
||||||
|
if (stp_rxlen < 64)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Our own BPDU coming back at us = a loop in the network. Block the port
|
/* Our own BPDU coming back at us = a loop in the network. Block the port
|
||||||
* for a listen period; if the loop persists the BPDUs keep arriving and
|
* for a listen period; if the loop persists the BPDUs keep arriving and
|
||||||
* the port stays blocked. */
|
* the port stays blocked. */
|
||||||
|
|||||||
Reference in New Issue
Block a user