Merge upstream/main into the Spanning Tree branch

Only httpd.c conflicted: main added the buffered configuration upload
next to the pointers this branch had moved into xdata to free internal
RAM. Both belong, so the new globals sit above declarations that keep
their storage class.
This commit is contained in:
d00f
2026-08-25 23:28:09 +02:00
10 changed files with 384 additions and 120 deletions
+99 -5
View File
@@ -42,6 +42,15 @@ __xdata uint32_t cont_addr;
// HTTP header properties
__xdata uint8_t boundary[72];
// a client may split the request anywhere, including inside a boundary or a
// part header, so a configuration upload is parsed only once it is complete;
// sized for a full config sector plus the multipart framing around it
#define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384)
__xdata uint8_t config_upload;
__xdata uint8_t config_buf[CONFIG_UPLOAD_BUF];
__xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
__xdata uint8_t cfg_bl;
__xdata uint8_t * __xdata content_type = 0;
__xdata uint8_t * __xdata session = 0;
@@ -78,6 +87,7 @@ inline uint8_t is_separator(uint8_t c)
void httpd_init(void) __banked
{
config_upload = 0; // xdata is not zeroed by the startup code
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
// Start listening to port 80
uip_listen(HTONS(80));
@@ -316,6 +326,65 @@ void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes)
}
/* 0: body incomplete, 1: configuration stored, 2: malformed */
static uint8_t config_take(void)
{
cfg_bl = strlen_x(boundary);
// the body is complete once the closing boundary has arrived
cfg_last = 0;
while (1) {
if (cfg_last + cfg_bl + 1 >= write_len)
return 0;
if (strstart_x(&config_buf[cfg_last], boundary)
&& strstart(&config_buf[cfg_last + cfg_bl], "--"))
break;
cfg_last++;
}
// every part lies ahead of the closing boundary, so it bounds the walk
cfg_pos = 0;
while (cfg_pos < cfg_last) {
if (!strstart_x(&config_buf[cfg_pos], boundary)) {
cfg_pos++;
continue;
}
cfg_hdr = cfg_pos + cfg_bl;
cfg_body = cfg_hdr;
while (1) {
if (cfg_body + 3 >= cfg_last)
return 2;
if (strstart(&config_buf[cfg_body], "\r\n\r\n"))
break;
cfg_body++;
}
cfg_end = cfg_body;
cfg_body += 4;
// reaching cfg_last is a match: the last part ends at the closing boundary
while (cfg_end < cfg_last && !strstart_x(&config_buf[cfg_end], boundary))
cfg_end++;
while (cfg_hdr + 8 < cfg_body) {
// the part carrying a filename holds the configuration
if (strstart(&config_buf[cfg_hdr], "filename")) {
// the payload plus its terminator must fit the sector
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
return 2;
config_buf[cfg_end] = 0;
flash_region.addr = CONFIG_START;
flash_sector_erase();
flash_region.addr = CONFIG_START;
flash_region.len = cfg_end - cfg_body + 1;
flash_write_bytes(config_buf + cfg_body);
return 1;
}
cfg_hdr++;
}
cfg_pos = cfg_end;
}
return 2;
}
/*
* Reads post data from the http stream and writes it into flash memory
* Input: the current position in the TCP buffer (uip_appdata)
@@ -438,6 +507,7 @@ void handle_post(void)
return;
}
print_string("Firmware upload started.");
config_upload = 0;
uptr = FIRMWARE_UPLOAD_START;
verify_crc = 1;
max_upload = 1024576;
@@ -446,12 +516,10 @@ void handle_post(void)
send_unauthorized();
return;
}
dbg_string("Configuration upload, erasing config mem!\n");
uptr = CONFIG_START;
dbg_string("Configuration upload\n");
verify_crc = 0;
max_upload = 2048;
flash_region.addr = CONFIG_START;
flash_sector_erase();
config_upload = 1;
write_len = 0;
}
// Check for other POST requests, which are not multipart, below
} else {
@@ -505,6 +573,32 @@ void handle_post(void)
send_bad_request();
return;
}
if (config_upload) {
cfg_pos = uip_len - (p - uip_appdata);
if (write_len + cfg_pos >= CONFIG_UPLOAD_BUF) {
print_string("Configuration too large, aborting.\n");
config_upload = 0;
s->tstate = TSTATE_NONE;
send_bad_request();
return;
}
memcpy(config_buf + write_len, p, cfg_pos);
write_len += cfg_pos;
uint8_t taken = config_take();
if (!taken) {
s->tstate = TSTATE_MULTIPART;
return;
}
config_upload = 0;
s->tstate = TSTATE_NONE;
if (taken == 2) {
send_bad_request();
return;
}
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
return;
}
// We skip the intial parts as part of the header
do {
p = skip_boundary(p);
+9 -29
View File
@@ -178,10 +178,12 @@ void reg_to_html_long(register uint16_t reg)
void send_sfp_info(uint8_t sfp)
{
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
for (uint8_t i = 20; i < 60; i++) {
if (i >= 36 && i < 40) // Skip Non-ASCII codes
for (uint8_t i = 16; i < 64; i++) {
if (!(i & 0xf))
sfp_read_block(sfp, i, 16);
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
continue;
uint8_t c = sfp_read_reg(sfp, i);
uint8_t c = sfp_buf[i & 0xf];
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
char_to_html(c);
}
@@ -194,32 +196,10 @@ void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
if (len > 16)
return;
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
}
sfp_read_block(slot, reg, len);
reg_read_m(RTL837X_REG_I2C_CTRL);
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2);
reg_write_m(RTL837X_REG_I2C_CTRL);
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
// Execute I2C Read
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
// Wait for execution to finish
do {
reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1);
for (uint8_t i = 0; i < len; i++) {
if (!(i & 0x3))
reg_read_m(RTL837X_REG_I2C_OUT + i);
byte_to_html(sfr_data[3 - (i & 0x3)]);
}
for (uint8_t i = 0; i < len; i++)
byte_to_html(sfp_buf[i]);
}
@@ -936,7 +916,7 @@ found_end:
if (valid_len > (TCP_OUTBUF_SIZE - slen)) {
cont_len = valid_len - (TCP_OUTBUF_SIZE - slen);
valid_len = TCP_OUTBUF_SIZE - slen;
cont_addr = valid_len;
cont_addr = CONFIG_START + valid_len;
}
flash_region.addr = CONFIG_START;