From dd7f9f7c7bbbc506f95661ec0795c90b4b19bf56 Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Thu, 3 Sep 2026 10:33:53 -0500 Subject: [PATCH] httpd: refuse to delete the switch's own L2 entry The L2 page's Delete button removes any table entry by index, including the entry for the switch's own MAC on the CPU port. Without that entry unicast to the management address is no longer delivered to the CPU, so management goes dark until the CPU happens to transmit again and the entry is relearned. Compare the entry's MAC against uip_ethaddr before rewriting it and answer result 0 for the switch's own address, as for a missing entry. The compare is inline: this handler sits at the bottom of the uIP call chain, where every extra call level costs internal RAM. --- httpd/page_impl.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/httpd/page_impl.c b/httpd/page_impl.c index d063f4c1..3addb19c 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -447,27 +447,34 @@ void l2_delete(uint16_t idx) if (!(sfr_data[0] & 0x20)) { char_to_html('0'); } else { + __bit own = sfr_data[2] == uip_ethaddr.addr[0] && sfr_data[3] == uip_ethaddr.addr[1]; sfr_data[0] &= 0x3f; // Clear SPA reg_write_m(RTL837x_TBL_DATA_IN_B); // Second half of MAC is copied reg_read_m(RTL837x_L2_DATA_OUT_A); - reg_write_m(RTL837x_TBL_DATA_IN_A); + if (own && sfr_data[0] == uip_ethaddr.addr[2] && sfr_data[1] == uip_ethaddr.addr[3] + && sfr_data[2] == uip_ethaddr.addr[4] && sfr_data[3] == uip_ethaddr.addr[5]) { + // the switch's own entry keeps management reachable + char_to_html('0'); + } else { + reg_write_m(RTL837x_TBL_DATA_IN_A); - reg_read_m(RTL837x_L2_DATA_OUT_C); - sfr_data[3] &= 0xc0; // Clear age, auth and second part of ports - sfr_data[1] &= 0xfe; // Clear nosalearn - reg_write_m(RTL837x_TBL_DATA_IN_C); + reg_read_m(RTL837x_L2_DATA_OUT_C); + sfr_data[3] &= 0xc0; // Clear age, auth and second part of ports + sfr_data[1] &= 0xfe; // Clear nosalearn + reg_write_m(RTL837x_TBL_DATA_IN_C); - reg_read_m(RTL837x_TBL_DATA_0); - REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1], TBL_L2_UNICAST, sfr_data[3]); + reg_read_m(RTL837x_TBL_DATA_0); + REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1], TBL_L2_UNICAST, sfr_data[3]); - REG_WRITE(RTL837X_TBL_CTRL, idx >> 8, idx, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE); - do { - reg_read_m(RTL837X_TBL_CTRL); - } while (sfr_data[3] & TBL_EXECUTE); + REG_WRITE(RTL837X_TBL_CTRL, idx >> 8, idx, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE); + do { + reg_read_m(RTL837X_TBL_CTRL); + } while (sfr_data[3] & TBL_EXECUTE); - char_to_html('1'); + char_to_html('1'); + } } char_to_html('}'); }