Merge upstream/main into feat/webui-compression

Resolve the conflicts against the 41 upstream commits since 52692d0:

- Makefile: keep the upstream parallel-build fixes (grouped html_data
  target with order-only deps, create_build_dir, crtbank, deterministic
  BUILD_DATE, atomic version.h write) and keep the minify + gzip
  pipeline (-z, html_min, .css/.ico in the html file list) on top.
- html: l2.js stays removed; port the upstream L2 fixes into the
  single-page main.js (walkL2() with empty-reply and 4096-entry cap
  handling, 3 retries on error).  The L2 poll now re-schedules itself
  after each walk and stops when the section is hidden.
- httpd/httpd.c merged cleanly (gzip Content-Encoding alongside the
  upstream GET walk bound and counters.json port check).
- doc/webui-compression.md: describe the upstream version.h write.

Verified: KP_9000_6XHML_X2 and PCB_K0402WS_V3 build sequentially and
with make -j8; all 8 embedded files decompress byte-identically;
httpd_sim serves main.js/index.html and the L2 JSON endpoint.
This commit is contained in:
eraiza0816 committed 2026-08-17 22:53:06 +09:00
commit 37eefb4b35
20 files changed
+301 -143

No files matched your search

+21 -14
View File
@@ -32,6 +32,17 @@ endif
VERSION_EXTENSION = v$(VERSION)-$(GIT_VERSION)
FILENAME_EXTENSION = $(VERSION_EXTENSION)-$(MACHINE)
# Deterministic build date: honor SOURCE_DATE_EPOCH, else the HEAD commit date,
# else wall-clock (no-git fallback). Keeps same-commit builds byte-identical
# (BUILD_DATE is baked into the image and covered by the trailing CRC).
SOURCE_DATE_EPOCH ?= $(shell git show -s --format=%ct HEAD 2>/dev/null)
ifeq ($(SOURCE_DATE_EPOCH),)
BUILD_DATE := $(shell date +"%Y-%m-%d %H:%M:%S")
else
BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/dev/null \
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
endif
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
create_build_dir:
@@ -87,18 +98,14 @@ html_min: $(HTML)
mkdir -p $(HTML_MIN)
@for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done
html_data.c html_data.h: $(HTML) tools/output/fileadder html_min
html_data.c html_data.h &: $(HTML) | tools html_min
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
# httpd.c includes html_data.h; declare it explicitly so a parallel
# build (-j) does not compile httpd before the header is generated.
$(BUILDDIR)/httpd/httpd.rel: html_data.h
$(VERSION_HEADER):
@echo "#ifndef VERSION_H" > $(VERSION_HEADER)
@echo "#define VERSION_H" >> $(VERSION_HEADER)
@echo "#define VERSION_SW \"$(VERSION_EXTENSION)\"" >> $(VERSION_HEADER)
@echo "#define BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
@echo "#endif" >> $(VERSION_HEADER)
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
"#endif" > $(VERSION_HEADER)
httpd: html_data.h
@@ -113,20 +120,20 @@ distclean:
-rm -f html_data.c html_data.h $(VERSION_HEADER)
-rm -rf $(BUILDDIR)
$(BUILDDIR)/%.rel: %.c
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)/%.rel: %.asm
$(BUILDDIR)/%.rel: %.asm | create_build_dir
${ASM} ${AFLAGS} -o $@ $<
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtstart.rel $(BUILDDIR)/crc16.rel
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
objcopy --input-target=ihex -O binary $< $@
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img | tools
if [ -e $@ ]; then rm $@; fi
tools/output/imagebuilder -i $^ $@
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
@@ -135,7 +142,7 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i
tools/output/crc_calculator -u $@
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER)
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER) create_build_dir
.PHONY:
machine_check:
+5 -2
View File
@@ -40,8 +40,10 @@ void cmd_edit(void) __banked
{
while (l != sbuf_ptr) {
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
if (cmd_line_len >= CMD_BUF_SIZE)
continue;
// Reserve one byte for the terminating NUL written on Enter. When the
// line is full, drop the character but still fall through to advance the
// serial-ring read pointer below; a 'continue' here would spin forever.
if (cmd_line_len < CMD_BUF_SIZE - 1) {
write_char(sbuf[l]);
// Shift buffer to right
for (uint8_t i = cmd_line_len; i > cursor; i--)
@@ -55,6 +57,7 @@ void cmd_edit(void) __banked
// Move backwards
for (uint8_t i = cursor; i < cmd_line_len; i++)
write_char('\010'); // BS works like cursor-left
}
} else if (sbuf[l] == '\033') { // ESC-Sequence
// Wait until we have at least 3 characters including the ESC character in the serial buffer
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
+18 -6
View File
@@ -250,8 +250,7 @@ void parse_lag(void)
print_string("LAG status:\n");
for (uint8_t i = 0; i < 4; i++) {
write_char(' '); write_char('1' + i);
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (i << 2));
members = ((uint16_t)sfr_data[2]) << 8 | sfr_data[3];
members = port_lag_members_get(i);
if (!members) {
print_string(" disabled\n");
continue;
@@ -274,7 +273,9 @@ void parse_lag(void)
if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]]))
goto err;
group = cmd_buffer[cmd_words_b[1]] - '0';
group = cmd_buffer[cmd_words_b[1]] - '1';
if (group > 3) /* '0' wraps well past three, so one test does both ends */
goto err;
uint8_t w = 2;
while (w < cmd_words_len) {
@@ -284,6 +285,8 @@ void parse_lag(void)
port = cmd_buffer[cmd_words_b[w]] - '1';
if (isnumber(cmd_buffer[cmd_words_b[w] + 1]))
port = (port + 1) * 10 + cmd_buffer[cmd_words_b[w] + 1] - '1';
if (port > 8) /* phys_to_log_port holds nine entries */
goto err;
port = machine.phys_to_log_port[port];
} else {
goto err;
@@ -296,7 +299,7 @@ void parse_lag(void)
port_lag_members_set(group, members);
return;
err:
print_string("Error: lag <lag> [port]...\n");
print_string("Error: lag <1-4> [port]...\n");
}
@@ -305,7 +308,11 @@ void parse_lag_hash(void)
__xdata uint8_t group;
__xdata uint8_t hash = 0;
group = cmd_buffer[cmd_words_b[1]] - '0';
if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]]))
goto err;
group = cmd_buffer[cmd_words_b[1]] - '1';
if (group > 3) /* '0' wraps well past three, so one test does both ends */
goto err;
uint8_t w = 2;
while (w < cmd_words_len) {
@@ -331,6 +338,9 @@ void parse_lag_hash(void)
w++;
}
port_lag_hash_set(group, hash);
return;
err:
print_string("Error: lag hash <1-4> [type]...\n");
}
@@ -1530,10 +1540,12 @@ void cmd_parser(void) __banked
} else if (cmd_compare(0, "igmp")) {
if (cmd_compare(1, "on"))
igmp_enable();
else if (cmd_compare(1, "off"))
igmp_setup();
else if (cmd_compare(1, "show"))
igmp_show();
else
igmp_setup(); // Reverts to default with IP-MC being flooded
print_string("Error: igmp on|off|show\n");
} else if (cmd_compare(0, "hostname")) {
/* "hostname" alone reports the current name; "hostname <text>"
* sets it, sanitized to JSON-safe printable ASCII. A name with
+29
View File
@@ -0,0 +1,29 @@
.area HOME (CODE)
.area GSINIT0 (CODE)
.area GSINIT1 (CODE)
.area GSINIT2 (CODE)
.area GSINIT3 (CODE)
.area GSINIT4 (CODE)
.area GSINIT5 (CODE)
.area GSINIT (CODE)
.area GSFINAL (CODE)
.area CSEG (CODE)
.area HOME (CODE)
__sdcc_banked_call::
push _PSBANK
xch a,r0
push a
mov a,r1
push a
mov a,r2
anl a,#0x1f
mov _PSBANK, a
xch a, r0
ret
__sdcc_banked_ret::
pop _PSBANK
ret
-17
View File
@@ -1,17 +0,0 @@
.area GSFINAL (CODE)
__sdcc_banked_call::
push _PSBANK
xch a,r0
push a
mov a,r1
push a
mov a,r2
anl a,#0x1f
mov _PSBANK, a
xch a, r0
ret
__sdcc_banked_ret::
pop _PSBANK
ret
+17
View File
@@ -41,6 +41,7 @@ __xdata uip_ipaddr_t server;
#define DHCP_REBIND_LEN 4
#define DHCP_CLIENT_ID 61
#define DHCP_CLIENT_ID_LEN 7
#define DHCP_HOSTNAME 12
#define DHCP_REQUEST_IP 50
#define DHCP_REQUEST_IP_LEN 4
#define DHCP_PARAMS 55
@@ -116,6 +117,20 @@ void dhcp_addopt_client_id(void)
}
void dhcp_addopt_hostname(void)
{
uint8_t len = 0;
while (hostname[len])
len++;
if (!len)
return;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HOSTNAME;
DHCP_OPT[dhcp_state.opt_ptr++] = len;
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], hostname, len);
dhcp_state.opt_ptr += len;
}
void dhcp_addopt_request_ip(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
@@ -152,6 +167,7 @@ void dhcp_send_discover(void)
dhcp_addopt_client_id();
dhcp_addopt_request_ip();
dhcp_addopt_hostname();
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
@@ -188,6 +204,7 @@ void dhcp_send_request(void)
dhcp_addopt_client_id();
dhcp_addopt_request_ip();
dhcp_addopt_server_id();
dhcp_addopt_hostname();
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
+1 -1
View File
@@ -92,7 +92,7 @@ The following shows the network configuration
On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes
source and destination ports into account, e.g. just use the default:
```
> lag 0 1 2
> lag 1 1 2
```
+4 -2
View File
@@ -75,8 +75,10 @@ JSON polling of the visible section).
- `fileadder` terminates the embedded files with a NUL directly after the
content (previously at `data_read + 1`), so the `strlen()`-based size
computation no longer depends on uninitialised buffer content.
- `version.h` is no longer `.PHONY`; every build previously rewrote it
while a parallel build (`make -j`) could read a half-written copy.
- `version.h` is now written by a single atomic `printf` (change from
upstream) instead of five separate `echo`s, so a parallel build
(`make -j`) can no longer read a half-written copy. It stays in
`.PHONY` so it is regenerated on every build.
## Verification
+77 -42
View File
@@ -934,6 +934,10 @@ function setSectionInterval(fn, ms) {
function clearSectionIntervals() {
sectionIntervals.forEach(function(t) { clearInterval(t); });
sectionIntervals = [];
if (l2Timer) {
clearTimeout(l2Timer);
l2Timer = null;
}
}
function showSection(name) {
@@ -1650,10 +1654,7 @@ sectionInits.stat = function() {
});
};
var l2GetInterval;
var l2Entries = [];
var l2CurrentEntry = 0;
var l2Timer;
function l2CMP(a, b)
{
@@ -1744,7 +1745,6 @@ function fillL2(s)
s = uniq(s);
l2All = s;
renderL2();
l2Entries = [];
}
function paintL2(tbl, s)
@@ -1773,50 +1773,22 @@ function paintL2(tbl, s)
}
function getL2() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var s = JSON.parse(xhttp.responseText);
var s = s.map(function(e) {
e.vlan = parseInt(e.vlan, 16);
e.idx = parseInt(e.idx, 16);
e.type = e.type == "s" ? t('l2_static') : t('l2_learned');
e.port = e.port == 9 ? 'CPU' : logToPhysPort[e.port];
return e;
walkL2(function(entries, ok) {
if (ok) {
for (var i = 0; i < entries.length; i++)
entries[i].type = entries[i].type == "s" ? t('l2_static') : t('l2_learned');
fillL2(entries);
}
var sec = document.getElementById('page-l2');
if (sec && sec.style.display === 'block')
l2Timer = setTimeout(getL2, 1000);
});
l2Entries.push(...s);
if (l2Entries >= 4096) {
l2Entries = [];
l2CurrentEntry = 0;
clearInterval(l2GetInterval);
return;
}
var w = 0;
for (var i = l2Entries.length-1; i > 0; i--) {
if (l2Entries[0].idx == l2Entries[i].idx) {
w = 1;
break;
}
}
if (w) {
l2CurrentEntry = 0;
fillL2(l2Entries);
} else {
l2CurrentEntry = s[s.length-1].idx + 1;
}
}
};
xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
xhttp.timeout = 1500; sendXHTTP(xhttp);
}
sectionInits.l2 = function() {
l2Entries = [];
l2CurrentEntry = 0;
update( () => {
getL2();
setSectionInterval(update, 2000);
l2GetInterval = setSectionInterval(getL2, 1000);
});
};
@@ -2497,3 +2469,66 @@ document.addEventListener("DOMContentLoaded", function () {
})
.catch(error => console.error('Error fetching the data:', error));
});
function walkL2(onDone)
{
var entries = [];
var idx = 0;
var tries = 0;
function retry() {
if (++tries < 3) {
setTimeout(page, 1000);
return;
}
onDone(entries, false);
}
function page() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState != 4)
return;
if (this.status != 200) {
retry();
return;
}
var s;
try {
s = JSON.parse(xhttp.responseText);
} catch (err) {
retry();
return;
}
tries = 0;
s = s.map(function(e) {
e.vlan = parseInt(e.vlan, 16);
e.idx = parseInt(e.idx, 16);
e.port = e.port == 9 ? 'CPU' : logToPhysPort[e.port];
return e;
});
if (!s.length) {
onDone(entries, true);
return;
}
entries.push(...s);
for (var i = entries.length - 1; i > 0; i--) {
if (entries[0].idx == entries[i].idx) {
onDone(entries, true);
return;
}
}
if (entries.length >= 4096) {
onDone(entries, true);
return;
}
idx = s[s.length - 1].idx + 1;
setTimeout(page, 1000);
};
xhttp.open("GET", "/l2.json?idx=" + idx, true);
xhttp.timeout = 1500;
sendXHTTP(xhttp);
}
page();
}
+11 -2
View File
@@ -640,7 +640,7 @@ void httpd_appcall(void)
p += 4;
scan_header(p);
__xdata uint8_t *q = p;
while (!is_separator(*p))
while (*p && !is_separator(*p))
p++;
*p = '\0';
dbg_string_x(q);
@@ -664,7 +664,16 @@ void httpd_appcall(void)
parse_short(q + 15);
send_vlan(short_parsed);
} else if (is_word(q, "/counters.json")) {
send_counters(q[20]-'0');
/* The port is one raw character of the request line and
* indexes a nine entry table, so bound it here instead
* of trusting the client to have sent a digit. Anything
* below '0' wraps well past eight, so the one test
* covers both ends. */
uint8_t cport = q[20] - '0';
if (cport > 8)
send_bad_request();
else
send_counters(cport);
} else if (is_word(q, "/eee.json")) {
send_eee();
} else if (is_word(q, "/bandwidth.json")) {
+24 -23
View File
@@ -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
__bit 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
__bit 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];
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(',');
if (first_entry == 0xffff)
first_entry = entry;
} else {
if (first_entry == entry || !entries_left) {
char_to_html(']');
else if (first_entry == entry || !entries_left)
break;
} else {
char_to_html(',');
}
}
}
char_to_html(']');
}
@@ -518,8 +520,7 @@ void send_lag(void)
slen += strtox(outbuf + slen, "{\"lagNum\":");
itoa_html(l);
slen += strtox(outbuf + slen, ",\"members\":\"");
reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (l << 2));
uint16_t ports = ((uint16_t)sfr_data[2] << 8) | sfr_data[3];
uint16_t ports = port_lag_members_get(l);
for (uint8_t i = 0; i < 16; i++) {
bool_to_html(!!(ports & 0x8000));
ports <<= 1;
+1
View File
@@ -415,6 +415,7 @@ void machine_custom_init(void) { }
__code const struct machine machine = {
.machine_name = "SWTGW218AS 8+1 Managed Switch",
.isRTL8373 = 1,
.mac_flash_offset = 0x1FC000,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
+1
View File
@@ -85,6 +85,7 @@ typedef struct machine {
uint32_t led_sets[4][4];
uint8_t led_mux_custom;
uint8_t led_mux[28];
uint32_t mac_flash_offset;
};
typedef struct machine_runtime
+5 -7
View File
@@ -16,6 +16,7 @@
#include "machine.h"
extern __code struct machine machine;
extern __xdata uint8_t igmpEnabled;
#include "uip.h"
@@ -85,6 +86,7 @@ void igmp_setup(void) __banked
{
uint8_t i;
print_string("igmp_setup called\n");
igmpEnabled = 0;
// For now, forward all unkown IP-MC pkts (2 bits per port. 00: flood via floodmask, 01: drop, 10: trap, 11: to rport)
REG_SET(RTL837X_IPV4_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
REG_SET(RTL837X_IPV6_PORT_MC_LM_ACT, LOOKUP_MISS_FLOOD);
@@ -96,11 +98,6 @@ void igmp_setup(void) __banked
// Enable lookup of IPv4 MC addresses in table
reg_bit_set(RTL837X_L2_CTRL, L2_CTRL_LUT_IPMC_HASH);
// Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping,
// bits 16-24 configure max MC group used by that port. For now all protocols are flooded (01)
for (i = machine.min_port; i <= machine.max_port; i++)
REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), 0x00ff7c15);
/* Configure per-port IGMP operations when protocol messages are received
* bits 0-9 enable MC protocol snooping
* bit 10: Enable dynamic router port learning
@@ -135,6 +132,7 @@ void igmp_setup(void) __banked
void igmp_enable(void) __banked
{
print_string("igmp_enable called\n");
igmpEnabled = 1;
// Configure trapping of unhandled IGMP protocol packets to CPU
REG_SET(RTL837X_IGMP_TRAP_CFG, IGMP_CPU_PORT | IGMP_TRAP_PRIORITY);
@@ -223,7 +221,7 @@ void igmp_packet_handler(void) __banked
#endif
#ifdef IPMC_USES_L3MC
memset(&entry, 0, sizeof(struct ipmc_table_entry));
memset((__xdata uint8_t *)&entry, 0, sizeof(struct ipmc_table_entry));
// For IPv4 MC, the Source-IP is 0.0.0.0
entry.sip[0] = 0x00; entry.sip[1] = 0x00; entry.sip[2] = 0x00; entry.sip[3] = 0x00;
// For IPv4 MC, the Destination-IP is the IPv4 MC address
@@ -235,7 +233,7 @@ void igmp_packet_handler(void) __banked
* yy = MC_IP[2]
* zz = MC_IP[3]
*/
memset(&entry, 0, sizeof(struct l2mc_table_entry));
memset((__xdata uint8_t *)&entry, 0, sizeof(struct l2mc_table_entry));
entry.mac[0] = 0x01; entry.mac[1] = 0x00; entry.mac[2] = 0x5e;
entry.mac[3] = IGMP_I->mc_ip[1] & 0x7f; entry.mac[4] = IGMP_I->mc_ip[2]; entry.mac[5] = IGMP_I->mc_ip[3];
entry.vlan = 1; //TODO: Get this out of the packet and compare with VLAN table!
+24 -6
View File
@@ -733,6 +733,19 @@ void port_rldp_on(__xdata uint16_t p_ms)
}
/*
* Reads the member port bitmask of a Link Aggregation Group.
* The groups have numbers 0-3; bit n is set when logical port n is a member.
* The bitmask reflects what the hardware holds, so it covers groups set up
* statically and groups a protocol brought up, without either having to say so.
*/
uint16_t port_lag_members_get(uint8_t lag) __banked
{
reg_read(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2));
return ((uint16_t)SFR_DATA_8 << 8) | SFR_DATA_0;
}
/*
* Configure LAGs
* Sets the members via port bitmask of a given Link Aggregation Group
@@ -744,11 +757,14 @@ void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banke
{
print_string("port_lag_members_set, lag: "); print_byte(lag); print_string(", members: "); print_short(members);
write_char('\n');
if (lag > 3)
print_string("Link aggregation group must be 0-3!\n");
if (lag > 3) {
print_string("Link aggregation group out of range\n");
return;
}
reg_read_m(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2));
if (!(sfr_data[0] | sfr_data [1] | sfr_data [2] | sfr_data [3]))
REG_SET(RTL837X_TRK_HASH_CTRL_BASE, LAG_HASH_DEFAULT);
if (!(sfr_data[0] | sfr_data[1] | sfr_data[2])
&& (sfr_data[3] == LAG_HASH_RESET || sfr_data[3] == 0))
REG_SET(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), LAG_HASH_DEFAULT);
REG_WRITE(RTL837X_TRK_MBR_CTRL_BASE + (lag << 2), 0, 0, members >> 8, members & 0xff);
}
@@ -761,8 +777,10 @@ void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked
{
print_string("port_lag_hash_set, lag: "); print_byte(lag); print_string(", hash: "); print_byte(hash_bits);
write_char('\n');
if (lag > 3)
print_string("Link aggregation group must be 0-3!\n");
if (lag > 3) {
print_string("Link aggregation group out of range\n");
return;
}
REG_WRITE(RTL837X_TRK_HASH_CTRL_BASE + (lag << 2), 0, 0, 0, hash_bits);
}
+1
View File
@@ -61,6 +61,7 @@ void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata u
void port_mirror_del(void) __banked;
bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked;
void port_l2_setup(void) __banked;
uint16_t port_lag_members_get(uint8_t lag) __banked;
void port_lag_members_set(__xdata uint8_t lag, __xdata uint16_t members) __banked;
void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash) __banked;
void port_eee_enable_all(__xdata uint8_t speed) __banked;
+18 -8
View File
@@ -232,6 +232,8 @@
#define LAG_HASH_L4_SPORT 0x20
#define LAG_HASH_L4_DPORT 0x40
#define LAG_HASH_DEFAULT (LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC | LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT | LAG_HASH_L4_DPORT)
#define LAG_HASH_RESET (LAG_HASH_SOURCE_PORT_NUMBER | LAG_HASH_L2_SMAC | LAG_HASH_L2_DMAC \
| LAG_HASH_L3_SIP | LAG_HASH_L3_DIP | LAG_HASH_L4_SPORT)
/*
* Port isolation
@@ -305,32 +307,40 @@
#ifdef REGDBG
#define REG_SET(r, v) SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
#define REG_SET(r, v) do { \
SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
SFR_DATA_16 = (((uint32_t)v) >> 16) & 0xff; \
SFR_DATA_8 = (((uint16_t)v) >> 8 & 0xff); \
SFR_DATA_0 = (v) & 0xff; \
reg_write(r); \
write_char('R'); print_byte(r >> 8); print_byte(r); write_char('-'); \
print_byte(((v) >> 24) & 0xff); print_byte((v) >> 16 & 0xff); print_byte((v) >> 8 & 0xff); print_byte( (v) & 0xff); write_char(' ');
print_byte(((v) >> 24) & 0xff); print_byte((v) >> 16 & 0xff); print_byte((v) >> 8 & 0xff); print_byte( (v) & 0xff); write_char(' '); \
} while (0)
#define REG_WRITE(r, v24, v16, v8, v0) SFR_DATA_24 = (v24); \
#define REG_WRITE(r, v24, v16, v8, v0) do { \
SFR_DATA_24 = (v24); \
SFR_DATA_16 = (v16); \
SFR_DATA_8 = (v8); \
SFR_DATA_0 = (v0); \
reg_write(r); \
write_char('R'); print_byte(r>>8); print_byte(r); write_char('-'); print_byte(v24); print_byte(v16); print_byte(v8); print_byte(v0); write_char(' ');
write_char('R'); print_byte(r>>8); print_byte(r); write_char('-'); print_byte(v24); print_byte(v16); print_byte(v8); print_byte(v0); write_char(' '); \
} while (0)
#else
#define REG_SET(r, v) SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
#define REG_SET(r, v) do { \
SFR_DATA_24 = (((uint32_t)v) >> 24) & 0xff; \
SFR_DATA_16 = (((uint32_t)v) >> 16) & 0xff; \
SFR_DATA_8 = (((uint16_t)v) >> 8 & 0xff); \
SFR_DATA_0 = (v) & 0xff; \
reg_write(r);
reg_write(r); \
} while (0)
#define REG_WRITE(r, v24, v16, v8, v0) SFR_DATA_24 = (v24); \
#define REG_WRITE(r, v24, v16, v8, v0) do { \
SFR_DATA_24 = (v24); \
SFR_DATA_16 = (v16); \
SFR_DATA_8 = (v8); \
SFR_DATA_0 = (v0); \
reg_write(r);
reg_write(r); \
} while (0)
#endif
#endif
+16 -7
View File
@@ -121,6 +121,7 @@ __xdata uint16_t management_vlan;
__xdata uint8_t tx_seq;
__xdata uint8_t stpEnabled;
__xdata uint8_t igmpEnabled;
__xdata char hostname[24]; /* device hostname, default set at boot, see rtl837x_common.h */
__code uint16_t bit_mask[16] = {
@@ -1152,7 +1153,7 @@ void handle_rx(void)
print_string("STP TX\n");
tcpip_output();
}
} else if (uip_buf[0] == 0x01 && uip_buf[1] == 0x00 && uip_buf[2] == 0x5e // IPv4-MC packet?
} else if (igmpEnabled && uip_buf[0] == 0x01 && uip_buf[1] == 0x00 && uip_buf[2] == 0x5e // IPv4-MC packet?
&& uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x16) {
igmp_packet_handler();
if (uip_len) {
@@ -2112,20 +2113,28 @@ void main(void)
uip_ipaddr(&uip_hostaddr, ownIP[0], ownIP[1], ownIP[2], ownIP[3]);
uip_ipaddr(&uip_draddr, gatewayIP[0], gatewayIP[1], gatewayIP[2], gatewayIP[3]);
uip_ipaddr(&uip_netmask, netmask[0], netmask[1], netmask[2], netmask[3]);
uip_ethaddr.addr[0] = 0xff;
if (machine.mac_flash_offset) {
flash_region.addr = machine.mac_flash_offset;
flash_region.len = FLASH_BUF_SIZE;
flash_read_bulk(flash_buf);
// accept only a real unicast, globally-administered address (reject blank/LAA/multicast/all-zero OUI)
if (flash_buf[0] != 0xff && !(flash_buf[0] & 0x03) && (flash_buf[0] | flash_buf[1] | flash_buf[2])) {
uip_ethaddr.addr[0] = flash_buf[0]; uip_ethaddr.addr[1] = flash_buf[1];
uip_ethaddr.addr[2] = flash_buf[2]; uip_ethaddr.addr[3] = flash_buf[3];
uip_ethaddr.addr[4] = flash_buf[4]; uip_ethaddr.addr[5] = flash_buf[5];
}
}
if (uip_ethaddr.addr[0] == 0xff) { // no valid flash MAC -> generate locally-administered
reg_read_m(RTL837X_REG_CHIP_UUID);
#ifdef DEBUG
print_string("SoC UUID: "); print_sfr_data();
#endif
uip_ethaddr.addr[0] = 0x06; // LAA prefix
uip_ethaddr.addr[3] = sfr_data[0] ^ sfr_data[3];
uip_ethaddr.addr[4] = sfr_data[1] ^ sfr_data[3];
uip_ethaddr.addr[5] = sfr_data[2] ^ sfr_data[3];
reg_read_m(RTL837X_REG_CHIP_LOT_NO);
#ifdef DEBUG
print_string(", LOT: "); print_sfr_data(); write_char(' ');
#endif
uip_ethaddr.addr[1] = sfr_data[0] ^ sfr_data[2];
uip_ethaddr.addr[2] = sfr_data[1] ^ sfr_data[3];
}
print_string("Setting MAC to: ");
print_byte(uip_ethaddr.addr[0]); write_char(':'); print_byte(uip_ethaddr.addr[1]); write_char(':');
print_byte(uip_ethaddr.addr[2]); write_char(':'); print_byte(uip_ethaddr.addr[3]); write_char(':');
+15 -1
View File
@@ -106,9 +106,23 @@ typedef unsigned short uip_stats_t;
/**
* uIP buffer size.
*
* Sized to the largest frame the CPU port accepts on ingress: anything above
* that the NIC drops in hardware, so a larger buffer only costs XDATA. Measured
* with ICMP, which bypasses MSS and so probes the hardware directly: a 1502-byte
* payload is answered and 1503 is not, which puts the frame at 1556 bytes of
* uip_buf. The limit is the NIC's rather than a port's, so how the frame was
* tagged on the wire does not change it.
*
* \hideinitializer
*/
#define UIP_CONF_BUFFER_SIZE 2200
#define UIP_CONF_BUFFER_SIZE 1556
/**
* Bytes of the buffer kept out of the advertised MSS.
*
* \hideinitializer
*/
#define UIP_CONF_BUFFER_EXTRA 30
/**
* CPU byte order.
+13 -5
View File
@@ -298,11 +298,8 @@
/**
* The TCP maximum segment size.
*
* This is should not be to set to more than
* UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN.
*/
#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN)
#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN - UIP_BUFFER_EXTRA)
/**
* The size of the advertised receiver's window.
@@ -381,6 +378,17 @@
#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE
#endif /* UIP_CONF_BUFFER_SIZE */
/**
* Bytes of uip_buf kept out of the advertised MSS.
*
* \hideinitializer
*/
#ifndef UIP_CONF_BUFFER_EXTRA
#define UIP_BUFFER_EXTRA 0
#else /* UIP_CONF_BUFFER_EXTRA */
#define UIP_BUFFER_EXTRA UIP_CONF_BUFFER_EXTRA
#endif /* UIP_CONF_BUFFER_EXTRA */
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
@@ -447,7 +455,7 @@ void uip_log(char *msg);
#ifdef UIP_CONF_LLH_LEN
#define UIP_LLH_LEN UIP_CONF_LLH_LEN
#else /* UIP_CONF_LLH_LEN */
#define UIP_LLH_LEN ETHER_HEADER_SIZE + RTL_FRAME_DESC_SIZE
#define UIP_LLH_LEN (ETHER_HEADER_SIZE + RTL_FRAME_DESC_SIZE)
#endif /* UIP_CONF_LLH_LEN */
/** @} */