mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-09-02 15:02:51 +08:00
Merge upstream/main into the Spanning Tree branch
Both conflicts are the register keyword removal meeting a change of ours, so each takes main's signature and keeps what the branch was saying: nic_rx_packet() still returns a bool, and port_ingress_filter_get() stays declared. main has since put its own copy of the STP module in BANK2, so the pragma this branch carried is now duplicated. The one with main's comment stays.
This commit is contained in:
+99
-56
@@ -50,6 +50,8 @@ __xdata uint8_t boundary[72];
|
||||
__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;
|
||||
// part-header bytes buffered so far; accumulates across TCP segments
|
||||
__xdata uint16_t pre_acc;
|
||||
__xdata uint8_t cfg_bl;
|
||||
__xdata uint8_t * __xdata content_type = 0;
|
||||
__xdata uint8_t * __xdata session = 0;
|
||||
@@ -61,6 +63,9 @@ __xdata uint32_t max_upload;
|
||||
__xdata uint16_t short_parsed;
|
||||
|
||||
__xdata char passwd[21];
|
||||
// Set when a verified firmware upload awaits its response ACK, after
|
||||
// which the chip resets to apply the staged image
|
||||
__xdata uint8_t fw_reset_pending;
|
||||
__xdata char session_id[SESSION_ID_LENGTH + 1];
|
||||
__xdata uint8_t authenticated;
|
||||
__xdata uint32_t now;
|
||||
@@ -92,6 +97,7 @@ void httpd_init(void) __banked
|
||||
// Start listening to port 80
|
||||
uip_listen(HTONS(80));
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
fw_reset_pending = 0; // xdata is not zeroed by the startup code
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +182,7 @@ bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
|
||||
}
|
||||
|
||||
|
||||
bool is_word_x(__xdata uint8_t *lhs_str_p, __xdata uint8_t *rhs_str_p)
|
||||
bool is_word_x(__xdata uint8_t * lhs_str_p, __xdata uint8_t * rhs_str_p)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
@@ -241,18 +247,7 @@ void send_unauthorized(void)
|
||||
}
|
||||
|
||||
|
||||
__xdata uint8_t *skip_boundary(__xdata uint8_t *p)
|
||||
{
|
||||
while (*p) {
|
||||
if (is_word_x(p, boundary))
|
||||
return p + strlen_x(boundary);
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
__xdata uint8_t *scan_header(__xdata uint8_t *p)
|
||||
__xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
||||
{
|
||||
content_type = 0;
|
||||
session = 0;
|
||||
@@ -311,10 +306,12 @@ __xdata uint8_t *scan_header(__xdata uint8_t *p)
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes)
|
||||
/*
|
||||
* Generate random HEX-chars at the buffer location.
|
||||
*/
|
||||
void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
|
||||
{
|
||||
__xdata uint8_t i = 0;
|
||||
uint8_t i = 0;
|
||||
while (bytes) {
|
||||
if (!i)
|
||||
get_random_32();
|
||||
@@ -385,21 +382,47 @@ static uint8_t config_take(void)
|
||||
}
|
||||
|
||||
|
||||
// unlike scan_header(), keeps no auth state, so it may run on every buffered segment
|
||||
static uint16_t preamble_payload_start(uint16_t n)
|
||||
{
|
||||
uint16_t pos;
|
||||
|
||||
for (pos = 0; pos + 24 <= n; pos++) {
|
||||
if (strstart(&config_buf[pos], "application/octet-stream"))
|
||||
break;
|
||||
}
|
||||
if (pos + 24 > n)
|
||||
return 0;
|
||||
pos += 24;
|
||||
while (pos + 3 < n && !strstart(&config_buf[pos], "\r\n\r\n"))
|
||||
pos++;
|
||||
if (pos + 3 >= n)
|
||||
return 0;
|
||||
return pos + 4;
|
||||
}
|
||||
|
||||
|
||||
// Source window for stream_upload(); filled by the caller before the call
|
||||
__xdata struct {
|
||||
__xdata uint8_t *p;
|
||||
uint16_t bptr;
|
||||
uint16_t plen;
|
||||
} upload_settings;
|
||||
|
||||
/*
|
||||
* Reads post data from the http stream and writes it into flash memory
|
||||
* Input: the current position in the TCP buffer (uip_appdata)
|
||||
* Input: upload_settings, set by the caller
|
||||
* Returns 1: More data to read, 0: Upload complete, all parts reads
|
||||
*/
|
||||
uint8_t stream_upload(uint16_t bptr)
|
||||
uint8_t stream_upload(void)
|
||||
{
|
||||
__xdata uint8_t *p = uip_appdata;
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
|
||||
dbg_string("Stream_upload called: ");
|
||||
dbg_short(bptr); dbg_char('\n');
|
||||
dbg_short(upload_settings.bptr); dbg_char('\n');
|
||||
|
||||
do {
|
||||
if (bptr >= uip_len) {
|
||||
if (upload_settings.bptr >= upload_settings.plen) {
|
||||
s->tstate = TSTATE_POST;
|
||||
return 1;
|
||||
}
|
||||
@@ -412,17 +435,23 @@ uint8_t stream_upload(uint16_t bptr)
|
||||
flash_write_bytes(flash_buf);
|
||||
uptr += write_len;
|
||||
write_len = 0;
|
||||
// TODO: This is a bit premature, what about a nice web-page saying the device will reset???
|
||||
if (verify_crc) {
|
||||
dbg_string("CRC16: "); dbg_short(crc_final); dbg_char('\n');
|
||||
// Both bodies are 33 bytes; Content-Length lets the
|
||||
// browser complete the response without waiting for
|
||||
// the connection close (which a reset would swallow)
|
||||
if (crc_final == 0xb001) {
|
||||
print_string("Checksum OK.\nUpload to flash done, will reset!\n");
|
||||
// close connection to avoid retries by browser
|
||||
uip_close();
|
||||
reset_chip();
|
||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Length: 33\r\n"
|
||||
"Content-Type: text/plain\r\n\r\n"
|
||||
"OK: checksum verified, rebooting\n");
|
||||
// Reset once the response is fully ACKed
|
||||
fw_reset_pending = 1;
|
||||
} else {
|
||||
print_string("Checksum incorrect! Aborting.\n");
|
||||
uip_close();
|
||||
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 33\r\n"
|
||||
"Content-Type: text/plain\r\n\r\n"
|
||||
"NO: checksum failed, not applied\n");
|
||||
}
|
||||
}
|
||||
// Make sure there is a 0 at the end of the uploaded data
|
||||
@@ -430,18 +459,15 @@ uint8_t stream_upload(uint16_t bptr)
|
||||
flash_region.addr = uptr;
|
||||
flash_region.len = 1;
|
||||
flash_write_bytes(flash_buf);
|
||||
if (bptr >= uip_len)
|
||||
if (upload_settings.bptr >= upload_settings.plen)
|
||||
return 0;
|
||||
if(!verify_crc)
|
||||
//ugly hack to signal connection finished after config upload.
|
||||
uip_close();
|
||||
return 1;
|
||||
}
|
||||
if (p[bptr] == boundary[bindex]) {
|
||||
if (upload_settings.p[upload_settings.bptr] == boundary[bindex]) {
|
||||
if (!bindex)
|
||||
crc_final = crc_value;
|
||||
crc16(p + bptr);
|
||||
bptr++;
|
||||
crc16(upload_settings.p + upload_settings.bptr);
|
||||
upload_settings.bptr++;
|
||||
bindex++;
|
||||
} else {
|
||||
if (bindex) {
|
||||
@@ -449,8 +475,8 @@ uint8_t stream_upload(uint16_t bptr)
|
||||
write_len += bindex;
|
||||
bindex = 0;
|
||||
}
|
||||
crc16(p + bptr);
|
||||
flash_buf[write_len++] = p[bptr++];
|
||||
crc16(upload_settings.p + upload_settings.bptr);
|
||||
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
||||
if (write_len >= FLASH_PAGE_SIZE) {
|
||||
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
||||
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
||||
@@ -511,6 +537,7 @@ void handle_post(void)
|
||||
uptr = FIRMWARE_UPLOAD_START;
|
||||
verify_crc = 1;
|
||||
max_upload = 1024576;
|
||||
pre_acc = 0;
|
||||
} else if (is_word(request_path, "config")) {
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
@@ -550,11 +577,11 @@ void handle_post(void)
|
||||
if (is_url_word_x(p, passwd)) {
|
||||
dbg_string("Password accepted!\n");
|
||||
read_reg_timer(&last_session_use);
|
||||
gen_random_bytes(session_id, SESSION_ID_LENGTH);
|
||||
gen_random_hex_chars(session_id, SESSION_ID_LENGTH);
|
||||
session_id[SESSION_ID_LENGTH] = NUL;
|
||||
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
|
||||
"Set-Cookie: session=");
|
||||
for (register uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
|
||||
for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
|
||||
outbuf[slen++] = session_id[i];
|
||||
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
||||
} else {
|
||||
@@ -599,21 +626,21 @@ void handle_post(void)
|
||||
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);
|
||||
if (!*p) {
|
||||
s->tstate = TSTATE_MULTIPART;
|
||||
return;
|
||||
}
|
||||
p = scan_header(p);
|
||||
if (!*p)
|
||||
goto bad_request;
|
||||
if (!content_type) // We are waiting for the part with the octet stream
|
||||
continue;
|
||||
} while (!is_word(content_type, "application/octet-stream"));
|
||||
cfg_pos = uip_len - (p - uip_appdata);
|
||||
if (pre_acc + cfg_pos >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Firmware upload header too large, aborting.\n");
|
||||
s->tstate = TSTATE_NONE;
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
memcpy(config_buf + pre_acc, p, cfg_pos);
|
||||
pre_acc += cfg_pos;
|
||||
cfg_end = preamble_payload_start(pre_acc);
|
||||
if (!cfg_end) {
|
||||
s->tstate = TSTATE_MULTIPART;
|
||||
return;
|
||||
}
|
||||
dbg_string("Have content octets\n");
|
||||
p += 4; // Skip \r\n\r\n sequence at end of preamble of part
|
||||
|
||||
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
@@ -621,7 +648,14 @@ void handle_post(void)
|
||||
crc_value = 0;
|
||||
bindex = 0;
|
||||
write_len = 0;
|
||||
stream_upload(p - uip_appdata);
|
||||
// A verdict is only built once the upload part completes;
|
||||
// clear any stale response so the completion check in the
|
||||
// appcall POST branch cannot send leftovers
|
||||
slen = 0;
|
||||
upload_settings.p = config_buf;
|
||||
upload_settings.bptr = cfg_end;
|
||||
upload_settings.plen = pre_acc;
|
||||
stream_upload();
|
||||
|
||||
dbg_string("Done reading first fragment\n");
|
||||
return;
|
||||
@@ -632,9 +666,6 @@ void handle_post(void)
|
||||
}
|
||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
|
||||
return;
|
||||
bad_request:
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -698,11 +729,23 @@ void httpd_appcall(void)
|
||||
cont_len -= slen;
|
||||
cont_addr += slen;
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (fw_reset_pending) {
|
||||
// The upload verdict has been fully ACKed by the client;
|
||||
// now it is safe to reset and apply the staged image
|
||||
print_string("Resetting to apply update\n");
|
||||
reset_chip();
|
||||
}
|
||||
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||
// Check here maxupload by subtracting uip_len and close socekt if fails!
|
||||
if (max_upload - uip_len > 0) {
|
||||
stream_upload(0);
|
||||
upload_settings.p = uip_appdata;
|
||||
upload_settings.bptr = 0;
|
||||
upload_settings.plen = uip_len;
|
||||
stream_upload();
|
||||
// A completed part with a built verdict must go out
|
||||
// through the normal TX path
|
||||
if (s->tstate == TSTATE_NONE && slen)
|
||||
goto do_send;
|
||||
write_char('.');
|
||||
} else {
|
||||
send_bad_request();
|
||||
|
||||
Reference in New Issue
Block a user