mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
stp: BPDUs finally reach the wire (CPU tag flags + management VLAN)
Two TX bugs meant our BPDUs NEVER left the switch as valid STP frames - on the wire they appeared as ethertype 0x8899 (the raw Realtek CPU tag) and were flooded to all ports instead of directed. Every earlier root election was a solo act: no other bridge ever saw us. Both are the same bug classes fixed for LACP earlier: - rtl_tag.flags was written raw (0x0020); like every other tag field it must go through HTONS, otherwise the bits land in the wrong byte (0x2000 = EFID), the ASIC fails to parse the tag and floods the frame with the 0x8899 header still attached. - With a management VLAN set, tcpip_output() splices an 802.1Q tag after the SA, again shifting the CPU tag out of the parsed position. BPDUs are link-local and must egress untagged: suppress the VLAN insert per frame, exactly as lacp_send() does. Hardware note discovered while fixing this: RTL_TAG_KEEP on an LLC/802.3 (length-field) frame makes the ASIC drop it entirely - the same flag works fine on ethertype frames (LACP). So BPDUs use LEARN_DIS only. Verified on the wire (tcpdump on the peer): clean "802.3 ... LLC, dsap STP 0x42 ... Rapid STP, bridge-id 8000.<our mac>" at the hello interval, sent directed (no flood), management HTTP unaffected, LAN at 0% loss throughout. (cherry picked from commit 4a41a292a9ab88d4fb05a8481ad28f8ffcfd9bc4)
This commit is contained in:
+18
-1
@@ -44,6 +44,7 @@ __xdata uint8_t stp_fdb_i;
|
|||||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||||
|
|
||||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
|
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
|
||||||
|
extern __xdata uint16_t management_vlan; /* owned by rtlplayground.c; suppressed per-frame for BPDUs */
|
||||||
|
|
||||||
/* CLI tokenizer state + helpers (owned by cmd_parser.c, HOME bank) */
|
/* CLI tokenizer state + helpers (owned by cmd_parser.c, HOME bank) */
|
||||||
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||||
@@ -188,7 +189,13 @@ void stp_cnf_send(uint8_t port) __reentrant
|
|||||||
STP_O->rtl_tag.tag = HTONS(RTL_FRAME_TAG_ID);
|
STP_O->rtl_tag.tag = HTONS(RTL_FRAME_TAG_ID);
|
||||||
STP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
|
STP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
|
||||||
STP_O->rtl_tag.reason = 0x00;
|
STP_O->rtl_tag.reason = 0x00;
|
||||||
STP_O->rtl_tag.flags = 0x0020; // Disable L2 learning
|
/* Through HTONS like every tag field: raw 0x0020 lands on the wire as
|
||||||
|
* 0x2000 (EFID), the ASIC fails to parse the tag and floods the frame
|
||||||
|
* with the 0x8899 header still on it (same bug class as LACP had).
|
||||||
|
* NOTE: no RTL_TAG_KEEP here - hardware-verified that KEEP on an
|
||||||
|
* LLC/802.3 (length-field) frame makes the ASIC drop it entirely,
|
||||||
|
* while the same flag works fine on ethertype frames (LACP). */
|
||||||
|
STP_O->rtl_tag.flags = HTONS(RTL_TAG_LEARN_DIS);
|
||||||
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
|
STP_O->rtl_tag.pmask = HTONS(((uint16_t)1) << port);
|
||||||
|
|
||||||
STP_O->msg_len = HTONS(0x27);
|
STP_O->msg_len = HTONS(0x27);
|
||||||
@@ -229,8 +236,18 @@ void stp_cnf_send(uint8_t port) __reentrant
|
|||||||
STP_O->hello = stp_hello_s;
|
STP_O->hello = stp_hello_s;
|
||||||
STP_O->fwd_delay = stp_fwddelay_s;
|
STP_O->fwd_delay = stp_fwddelay_s;
|
||||||
|
|
||||||
|
/* BPDUs are link-local and must egress untagged: with a management VLAN
|
||||||
|
* set, tcpip_output() splices an 802.1Q tag after the SA, shifting the
|
||||||
|
* in-frame rtl_tag out of the position the ASIC parses - the CPU tag then
|
||||||
|
* leaks onto the wire as 0x8899 and the BPDU is flooded, not sent.
|
||||||
|
* Hardware-verified fix, same as lacp_send(). */
|
||||||
|
{
|
||||||
|
uint16_t saved_mgmt_vlan = management_vlan;
|
||||||
|
management_vlan = 0;
|
||||||
uip_len = sizeof(struct stp_pkt);
|
uip_len = sizeof(struct stp_pkt);
|
||||||
tcpip_output();
|
tcpip_output();
|
||||||
|
management_vlan = saved_mgmt_vlan;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user