mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-09-02 15:02:51 +08:00
stp: name the BPDU version, type and flag constants
The comments they replace are gone with them. Two things the comments carried that the names do not: Accepting version >= 2 rather than == 2 is deliberate. 802.1D-2004 14.4 has an RSTP bridge accept a higher Protocol Version and treat it as RST, and MSTP sends version 3 type 2 with a prefix identical to an RST BPDU for exactly that reason, so insisting on == 2 would make us blind to every MST bridge on the segment. In the TCN branch stp_cnf_send() transmits by itself, so uip_len is cleared afterwards to keep handle_rx() from sending the frame twice.
This commit is contained in:
+37
-42
@@ -137,6 +137,24 @@ struct stp_pkt_in {
|
|||||||
#define STP_O ((__xdata struct stp_pkt *)&uip_buf[RTL_FRAME_DESC_SIZE])
|
#define STP_O ((__xdata struct stp_pkt *)&uip_buf[RTL_FRAME_DESC_SIZE])
|
||||||
#define STP_I ((__xdata struct stp_pkt_in *)&uip_buf[0])
|
#define STP_I ((__xdata struct stp_pkt_in *)&uip_buf[0])
|
||||||
|
|
||||||
|
#define BPDU_VER_STP 0x00
|
||||||
|
#define BPDU_VER_RSTP 0x02
|
||||||
|
|
||||||
|
#define BPDU_TYPE_CONFIG 0x00
|
||||||
|
#define BPDU_TYPE_RST 0x02
|
||||||
|
#define BPDU_TYPE_TCN 0x80
|
||||||
|
|
||||||
|
#define BPDU_LEN_CONFIG 0x26 // LLC and a 35 byte body
|
||||||
|
#define BPDU_LEN_RST 0x27 // LLC and a 36 byte body
|
||||||
|
|
||||||
|
#define BPDU_FLAG_TC 0x01
|
||||||
|
#define BPDU_FLAG_LEARNING 0x10
|
||||||
|
#define BPDU_FLAG_FORWARDING 0x20
|
||||||
|
#define BPDU_FLAG_TCACK 0x80
|
||||||
|
|
||||||
|
#define BPDU_ROLE_ROOT (0b10 << 2)
|
||||||
|
#define BPDU_ROLE_DESIGNATED (0b11 << 2)
|
||||||
|
|
||||||
/* Console messages name the port on the front panel, not the internal index. */
|
/* Console messages name the port on the front panel, not the internal index. */
|
||||||
static void print_port_nl(uint8_t port) __reentrant
|
static void print_port_nl(uint8_t port) __reentrant
|
||||||
{
|
{
|
||||||
@@ -345,34 +363,22 @@ void stp_cnf_send(uint8_t port) __reentrant
|
|||||||
STP_O->ctrl = 0x03;
|
STP_O->ctrl = 0x03;
|
||||||
STP_O->proto = 0x0000;
|
STP_O->proto = 0x0000;
|
||||||
if (stp_rstp) {
|
if (stp_rstp) {
|
||||||
/* 802.3 length = LLC (3) + RST BPDU body (36, incl. version1_length) */
|
STP_O->msg_len = HTONS(BPDU_LEN_RST);
|
||||||
STP_O->msg_len = HTONS(0x27);
|
STP_O->version = BPDU_VER_RSTP;
|
||||||
STP_O->version = 0x02; /* RSTP */
|
STP_O->bpdu_type = BPDU_TYPE_RST;
|
||||||
STP_O->bpdu_type = 0x02; /* Rapid Spanning Tree BPDU */
|
|
||||||
/* Flags describe this port, so derive them instead of announcing
|
|
||||||
* designated+learning+forwarding unconditionally: a blocked port
|
|
||||||
* claiming to forward, or the root port claiming designated, is a
|
|
||||||
* lie on the wire even when nothing downstream acts on it (yet).
|
|
||||||
* Role is root on the root port and designated everywhere else -
|
|
||||||
* there is no alternate/backup role computation, so a port blocked
|
|
||||||
* by loop detection still transmits as designated, just with the
|
|
||||||
* learning and forwarding bits clear. Those two mirror the ASIC
|
|
||||||
* state (0b11 = forwarding); a listening or blocked port sends
|
|
||||||
* neither. */
|
|
||||||
reg_read_m(RTL837X_MSTP_STATES);
|
reg_read_m(RTL837X_MSTP_STATES);
|
||||||
STP_O->flags = (uint8_t)((port == stp_root_port ? 0b10 : 0b11) << 2);
|
STP_O->flags = port == stp_root_port ? BPDU_ROLE_ROOT : BPDU_ROLE_DESIGNATED;
|
||||||
if (((sfr_data[3 - (port >> 2)] >> ((port << 1) & 0x7)) & 0b11) == 0b11)
|
if (((sfr_data[3 - (port >> 2)] >> ((port << 1) & 0x7)) & 0b11) == 0b11)
|
||||||
STP_O->flags |= 0x30; /* learning + forwarding */
|
STP_O->flags |= BPDU_FLAG_LEARNING | BPDU_FLAG_FORWARDING;
|
||||||
} else {
|
} else {
|
||||||
/* 802.3 length = LLC (3) + Config BPDU body (35) */
|
STP_O->msg_len = HTONS(BPDU_LEN_CONFIG);
|
||||||
STP_O->msg_len = HTONS(0x26);
|
STP_O->version = BPDU_VER_STP;
|
||||||
STP_O->version = 0x00; /* legacy STP */
|
STP_O->bpdu_type = BPDU_TYPE_CONFIG;
|
||||||
STP_O->bpdu_type = 0x00; /* Config BPDU */
|
|
||||||
STP_O->flags = 0x00;
|
STP_O->flags = 0x00;
|
||||||
}
|
}
|
||||||
if (stp_tc_while)
|
if (stp_tc_while)
|
||||||
STP_O->flags |= 0x01; /* Topology Change */
|
STP_O->flags |= BPDU_FLAG_TC;
|
||||||
STP_O->flags |= stp_tx_flags_extra; /* e.g. TCA in reply to a TCN */
|
STP_O->flags |= stp_tx_flags_extra;
|
||||||
stp_tx_flags_extra = 0;
|
stp_tx_flags_extra = 0;
|
||||||
|
|
||||||
memcpy(STP_O->src_addr, uip_ethaddr.addr, 6);
|
memcpy(STP_O->src_addr, uip_ethaddr.addr, 6);
|
||||||
@@ -447,16 +453,10 @@ void stp_in(void) __banked
|
|||||||
return;
|
return;
|
||||||
if (STP_I->proto)
|
if (STP_I->proto)
|
||||||
return;
|
return;
|
||||||
/* Accept RSTP BPDUs (v2 type 2), legacy Config BPDUs (v0 type 0) and
|
if (!((STP_I->version >= BPDU_VER_RSTP && STP_I->bpdu_type == BPDU_TYPE_RST)
|
||||||
* legacy TCN BPDUs (v0 type 0x80, 4-byte body).
|
|| (STP_I->version == BPDU_VER_STP
|
||||||
* Version 2 *or greater*: 802.1D-2004 14.4 requires an RSTP bridge to
|
&& (STP_I->bpdu_type == BPDU_TYPE_CONFIG
|
||||||
* accept a higher Protocol Version and treat it as RST, ignoring what
|
|| STP_I->bpdu_type == BPDU_TYPE_TCN))))
|
||||||
* it does not understand. MSTP (802.1s) sends version 3 type 2 with a
|
|
||||||
* prefix deliberately identical to an RST BPDU for exactly this reason;
|
|
||||||
* insisting on == 2 makes us blind to every MST bridge on the segment. */
|
|
||||||
if (!((STP_I->version >= 2 && STP_I->bpdu_type == 2)
|
|
||||||
|| (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))
|
||||||
@@ -484,15 +484,10 @@ void stp_in(void) __banked
|
|||||||
* L2 flush for a port that has a bridge behind it. */
|
* L2 flush for a port that has a bridge behind it. */
|
||||||
stp_pflags[port] &= ~STP_PF_OPEREDGE;
|
stp_pflags[port] &= ~STP_PF_OPEREDGE;
|
||||||
|
|
||||||
if (STP_I->bpdu_type == 0x80) {
|
if (STP_I->bpdu_type == BPDU_TYPE_TCN) {
|
||||||
/* TCN: a downstream bridge reports a topology change. Acknowledge it
|
stp_tx_flags_extra = BPDU_FLAG_TCACK;
|
||||||
* on this port so the sender stops repeating, then treat it like a
|
stp_cnf_send(port);
|
||||||
* change of our own: flush the port and carry the TC flag on the
|
uip_len = 0;
|
||||||
* 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_topology_change(port);
|
stp_topology_change(port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -557,7 +552,7 @@ void stp_in(void) __banked
|
|||||||
* the long window a local change may have armed. The flush runs once,
|
* 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
|
* on the arming edge: everything learned on the other non-edge ports
|
||||||
* may sit behind the moved link and must be relearned. */
|
* may sit behind the moved link and must be relearned. */
|
||||||
if (STP_I->flags & 0x01) {
|
if (STP_I->flags & BPDU_FLAG_TC) {
|
||||||
if (!stp_tc_while) {
|
if (!stp_tc_while) {
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
stp_tc_count++;
|
stp_tc_count++;
|
||||||
|
|||||||
Reference in New Issue
Block a user