From 5a6b854c5d249921334748d83a741e69c701009c Mon Sep 17 00:00:00 2001 From: d00f Date: Wed, 12 Aug 2026 16:46:29 +0200 Subject: [PATCH] stp: record the designated bridge, port and cost from received BPDUs stp_dbridge, stp_dpid and stp_dcost were declared and read by the status page, but nothing ever wrote them, so they stayed zero for the life of the firmware. The page's validity test then always failed, and the Designated Bridge, Designated Port ID and Designated Cost columns reported our own values on every port, including the root port where the answer is the upstream neighbour. The three arrays reserved 140 bytes of xdata and never used any of it. They are filled now, right after the loop check, so a frame that came back from one of our own ports is not mistaken for a neighbour. The validity test moves from the last byte of the stored MAC to the stored Port ID. A Port ID is 1-based on the wire and cannot be zero, while a neighbour whose MAC happens to end in 0x00 would have failed the old test. The root path cost byte swap happens once now, and the root port branch reuses the value instead of repeating the shifts. BANK2 grows 148 bytes, BANK1 loses 9, and xdata does not move. --- httpd/page_impl.c | 2 +- rtl837x_stp.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/httpd/page_impl.c b/httpd/page_impl.c index bef34d9..ac389e8 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -637,7 +637,7 @@ void send_stp(void) itoa_html(stp_pp2p[pi_i]); /* designated info: a freshly heard BPDU wins, else we are the * segment's designated bridge and report our own values */ - stp_we_root = stp_dbridge[pi_i].mac[5] && stp_bpdu_age[pi_i] < (uint16_t)stp_maxage_s * STP_HZ; + stp_we_root = stp_dpid[pi_i] && stp_bpdu_age[pi_i] < (uint16_t)stp_maxage_s * STP_HZ; slen += strtox(outbuf + slen, ",\"db\":\""); if (stp_we_root) { pi_prio = stp_dbridge[pi_i].prio; pi_ext = stp_dbridge[pi_i].ext; diff --git a/rtl837x_stp.c b/rtl837x_stp.c index 6ad56e5..a0387e4 100644 --- a/rtl837x_stp.c +++ b/rtl837x_stp.c @@ -451,6 +451,16 @@ void stp_in(void) __banked return; } + stp_dbridge[port].prio = STP_I->bridge.prio; + stp_dbridge[port].ext = STP_I->bridge.ext; + memcpy(stp_dbridge[port].mac, STP_I->bridge.mac, 6); + stp_dpid[port] = ((uint16_t)STP_I->port_prio << 8) | STP_I->port_id; + stp_cost_scratch = STP_I->root_path_cost; + stp_dcost[port] = ((stp_cost_scratch & 0xff) << 24) + | ((stp_cost_scratch & 0xff00) << 8) + | ((stp_cost_scratch >> 8) & 0xff00) + | (stp_cost_scratch >> 24); + /* Better root than the one we know? */ if (STP_I->root.prio < root_bridge.prio || ((STP_I->root.prio == root_bridge.prio) && cmpMAC(STP_I->root.mac, root_bridge.mac) < 0)) { @@ -480,13 +490,7 @@ void stp_in(void) __banked /* Age of the information we now hold (see the TX note on the wire * format); saturate rather than wrap on absurd input. */ stp_msg_age = (STP_I->age > 254) ? 254 : (uint8_t)STP_I->age; - stp_cost_scratch = STP_I->root_path_cost; - /* big-endian on the wire */ - root_bridge_cost = ((stp_cost_scratch & 0xff) << 24) - | ((stp_cost_scratch & 0xff00) << 8) - | ((stp_cost_scratch >> 8) & 0xff00) - | (stp_cost_scratch >> 24); - root_bridge_cost += PCOST(port); + root_bridge_cost = stp_dcost[port] + PCOST(port); } } }