From 115aa8d3f62ccd791b336c022442a095e3cc105a Mon Sep 17 00:00:00 2001 From: d00f Date: Tue, 21 Jul 2026 07:52:34 +0200 Subject: [PATCH] stp: actually promote ports out of blocking; calibrate timers "stp on" put every port into blocking (stp_setup, port_timers = "10 s") but nothing ever counted those timers down: stp_timers() only sent hello BPDUs. On a network with no other (R)STP bridge - i.e. nobody sends us BPDUs - every port therefore stayed blocking FOREVER and enabling STP took the whole network down until "stp off". - stp_timers(): count port_timers down; when a port's listen period expires with no better root heard, promote it to forwarding in MSTP_STATES (we are the designated bridge on that port). - Calibrate the tick constants to the real stp_timers() rate (~64 Hz: main loop ~256 Hz / (STP_TICK_DIVIDER+1)): TIME_HELLO 0x200->0x80 is an actual 2 s hello, port_timers 0xa00->0x280 an actual 10 s listen period. Measured before the fix, ports converged only after ~40 s. - Move struct bridge into rtl837x_stp.h and export root_bridge/-_cost for the web UI status endpoint. Verified on hardware: "stp on" -> ports report Blocking, after the 10 s listen period all ports promote to Forwarding and LAN connectivity returns; "stp off" restores forwarding immediately. We elect ourselves root (weRoot) with no other bridge present. (cherry picked from commit 8537a15ca254b2122272b20bec7a66426e86df4b) --- rtl837x_stp.c | 25 ++++++++++++++++++------- rtl837x_stp.h | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/rtl837x_stp.c b/rtl837x_stp.c index 6ba1847..3266041 100644 --- a/rtl837x_stp.c +++ b/rtl837x_stp.c @@ -34,12 +34,7 @@ extern __xdata struct uip_eth_addr uip_ethaddr; extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2]; -struct bridge { - uint8_t prio; - uint8_t ext; - uint8_t mac[6]; -}; - +/* struct bridge now lives in rtl837x_stp.h (shared with the web UI). */ __xdata struct bridge root_bridge; __xdata uint32_t root_bridge_cost; @@ -211,6 +206,22 @@ void stp_timers(void) __banked print_byte(i); write_char('\n'); stp_cnf_send(i); } + /* Promote a port out of the initial blocking state once its listen + * period expires. stp_setup() puts every port into blocking with + * port_timers = 10 s, but nothing ever counted that down - so on a + * network with no other RSTP bridge (nobody sends us BPDUs) every + * port stayed blocking FOREVER and "stp on" killed the whole + * network. If no better root was heard during the listen period we + * are the designated bridge on that port: go to forwarding. */ + if (port_timers[i]) { + if (!--port_timers[i]) { + reg_read_m(RTL837X_MSTP_STATES); + sfr_data[3 - (i >> 2)] |= (uint8_t)(0b11 << ((i << 1) & 0x7)); + reg_write_m(RTL837X_MSTP_STATES); + print_string("STP: port forwarding "); + print_byte(i); write_char('\n'); + } + } } } @@ -258,7 +269,7 @@ void stp_setup(void) __banked uint8_t bit_mask = 0b01 << ( (i << 1) & 0x7); sfr_data[3 - (i >> 2)] |= bit_mask; port_hello[i] = TIME_HELLO; - port_timers[i] = 0xa00; // 10 sec in blocking state + port_timers[i] = 0x280; // 10 s in blocking state (at the ~64 Hz stp_timers rate) } sfr_data[1] |= 0x0f; // Do not block CPU-Port reg_write_m(RTL837X_MSTP_STATES); // R5310-000d555f diff --git a/rtl837x_stp.h b/rtl837x_stp.h index b1c2a71..4aaf959 100644 --- a/rtl837x_stp.h +++ b/rtl837x_stp.h @@ -7,6 +7,20 @@ void stp_setup(void) __banked; void stp_timers(void) __banked; void stp_off(void) __banked; -#define TIME_HELLO 0x200 // 2 sec +#define TIME_HELLO 0x80 // 2 sec (stp_timers runs at ~64 Hz: main loop ~256 Hz / STP_TICK_DIVIDER+1) + +/* Bridge identifier as carried in a BPDU (priority, extension, MAC). */ +struct bridge { + uint8_t prio; + uint8_t ext; + uint8_t mac[6]; +}; + +/* Protocol state, exposed read-only for the web UI (page_impl.c send_stp()) + * - the elected root bridge and our path cost to it. Owned by rtl837x_stp.c; + * stpEnabled is owned by rtlplayground.c. */ +extern __xdata uint8_t stpEnabled; +extern __xdata struct bridge root_bridge; +extern __xdata uint32_t root_bridge_cost; #endif