From 3be66677895e254903fd8aa1229d33d14de38e11 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Sat, 15 Aug 2026 13:21:05 +0200 Subject: [PATCH] httpd: emit valid JSON from send_l2 The MAC table listing wrote its separator once per iteration rather than once per object. An entry the table engine reports as invalid produces no object, so it contributed a bare comma, and two in a row give ",," which JSON.parse rejects. The whole table then fails to load, not just the row that was missing. The separator now goes before each object and the closing bracket after the loop, which is the shape send_vlanlist already uses further down the file. The next index for an invalid entry was computed as h | low + 1, and the addition binds tighter than the or. That agrees with (h | low) + 1 except when the low byte reads 0xff and bit 8 of the index is already set, eight of the 4096 combinations. There the result is the start of the current block of 256 rather than the start of the next one, so the walk repeats a block it has already covered. Reading the index once after the branch rather than once in each arm removes the second copy of that expression along with the bug. The VLAN now comes first in each object. It is taken from the same L2_DATA_OUT_B read that decides whether the entry is valid, which saves reading that register a second time. The page addresses the fields by name, so the order they arrive in does not matter to it. A bound check on the output buffer goes in for consistency with send_vlanlist. Thirty entries of at most 74 bytes plus the brackets fit in the 2500 byte buffer with 179 to spare, so nothing changes today, but the margin was nowhere stated and L2_MAX_TRANSFER is a tunable. 5 bytes of BANK1, nothing in BANK2, xdata or internal RAM. Built for SWTGW218AS and KP_9000_6XHML_X2 on sdcc 4.5.0. --- httpd/page_impl.c | 52 ++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 19796ed..7b12927 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -356,6 +356,7 @@ void send_l2(uint16_t idx) */ __xdata uint16_t entry = idx & 0xfff; __xdata uint16_t first_entry = 0xffff; // An illegal entry index + bool first = true; char_to_html('['); while (1) { entries_left--; @@ -369,9 +370,22 @@ void send_l2(uint16_t idx) } while (sfr_data[3] & TBL_EXECUTE); reg_read_m(RTL837x_L2_DATA_OUT_B); - if ((sfr_data[0] & 0x20)) { // Check entry is valid + bool valid = (sfr_data[0] & 0x20) != 0; + if (valid) { + /* separator + 74-byte worst-case entry + closing "]" */ + if (slen + 76 > TCP_OUTBUF_SIZE) + break; + if (!first) + char_to_html(','); + first = false; + + // VLAN, taken from the read above instead of reading the register twice + slen += strtox(outbuf + slen, "{\"vlan\":\""); + charhex_to_html(sfr_data[0] & 0x0f); + byte_to_html(sfr_data[1]); + // MAC - slen += strtox(outbuf + slen, "{\"mac\":\""); + slen += strtox(outbuf + slen, "\",\"mac\":\""); byte_to_html(sfr_data[2]); char_to_html(':'); byte_to_html(sfr_data[3]); char_to_html(':'); port = (sfr_data[0] >> 6) & 0x3; @@ -381,12 +395,6 @@ void send_l2(uint16_t idx) byte_to_html(sfr_data[2]); char_to_html(':'); byte_to_html(sfr_data[3]); - // VLAN - slen += strtox(outbuf + slen, "\",\"vlan\":\""); - reg_read_m(RTL837x_L2_DATA_OUT_B); - charhex_to_html(sfr_data[0] & 0x0f); - byte_to_html(sfr_data[1]); - // type reg_read_m(RTL837x_L2_DATA_OUT_C); if (sfr_data[2] & 0x1) @@ -396,32 +404,26 @@ void send_l2(uint16_t idx) port |= (sfr_data[3] & 0x3) << 2; itoa_html(port); + } - // Index - reg_read_m(RTL837x_TBL_DATA_0); - entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3]; + // Index + reg_read_m(RTL837x_TBL_DATA_0); + entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3]; + if (valid) { slen += strtox(outbuf + slen, ",\"idx\":\""); byte_to_html(entry >> 8); byte_to_html(entry); char_to_html('"'); char_to_html('}'); - entry += 1; // We want the next entry following after the current entry - } else { - reg_read_m(RTL837x_TBL_DATA_0); - entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3] + 1; } - if (first_entry == 0xffff) { - char_to_html(','); + entry += 1; // We want the next entry following after the current entry + + if (first_entry == 0xffff) first_entry = entry; - } else { - if (first_entry == entry || !entries_left) { - char_to_html(']'); - break; - } else { - char_to_html(','); - } - } + else if (first_entry == entry || !entries_left) + break; } + char_to_html(']'); }