mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
Merge upstream/main into feat/webui-compression
Resolve conflicts against ~55 upstream commits since37eefb4: - Makefile: keep upstream parallel-build fixes (machine_init.c, SUBDIRSCLEAN, html_data grouped target) and retain minify+gzip pipeline (-z, html_min, .css/.ico) - tools: retain gzip support (zlib, -lz) lost in upstream revert - httpd/httpd.c: keep Content-Encoding: gzip alongside upstream GET walk, config upload, syslog/hostname changes - html: port upstream HTML/JS changes into SPA (single-page) bundle: * i18n: add port_col_devices / port_devices keys (en/ja/zh) * ports: add Connected devices column, devRender/devWalk via walkL2 (8c3df64) * config: add syslog port, extended stp/igmp/bw patterns, conf_toggle handling * system: show /cmd output in console (console_out), 401 handling * l2: hide delete for CPU entry, delL2Button, sort/filter improvements * navigation: add STP entry - SPA: integrate new STP page (stp.html/js) as page-stp section with sectionInits.stp, bridge/prio handling, per-port config/status tables - Remove per-page HTML/JS files (now bundled) and standalone stp.html/js Verified: tools build, html_min generation (main.js 93k->81k->19k gzip, 8 files), html_data.h gzip sizes, main.js syntax check.
This commit is contained in:
commit
d245249385
59 files changed
+3675
-960
No files matched your search
+425
-123
@@ -20,6 +20,8 @@
|
||||
#pragma constseg BANK1
|
||||
|
||||
extern volatile __xdata uint8_t sfr_data[4];
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern __xdata uint8_t cmd_capture; /* owned by rtlplayground.c, see write_char_no_syslog() */
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code struct f_data f_data[];
|
||||
extern __code char * __code mime_strings[];
|
||||
@@ -41,8 +43,19 @@ __xdata uint32_t cont_addr;
|
||||
|
||||
// HTTP header properties
|
||||
__xdata uint8_t boundary[72];
|
||||
__xdata uint8_t *content_type = 0;
|
||||
__xdata uint8_t *session = 0;
|
||||
|
||||
// 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];
|
||||
// bytes buffered in config_buf so far (config body, or a firmware part
|
||||
// header); accumulates across TCP segments
|
||||
__xdata uint16_t pre_acc;
|
||||
__xdata uint8_t * __xdata content_type = 0;
|
||||
__xdata uint8_t * __xdata session = 0;
|
||||
__xdata uint16_t content_length;
|
||||
|
||||
// Global variables holding POST state
|
||||
__xdata uint16_t bindex; // Current index into the boundary
|
||||
@@ -50,11 +63,20 @@ __xdata uint8_t verify_crc;
|
||||
__xdata uint32_t max_upload;
|
||||
__xdata uint16_t short_parsed;
|
||||
|
||||
#define POSTBODY_CMD 1
|
||||
#define POSTBODY_LOGIN 2
|
||||
#define POSTBODY_TIMEOUT (5 * SYS_TICK_HZ)
|
||||
__xdata uint8_t postbody_endpoint;
|
||||
__xdata uint16_t postbody_start;
|
||||
|
||||
__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;
|
||||
__xdata uint8_t *timeptr;
|
||||
__xdata uint8_t * __xdata timeptr;
|
||||
__xdata uint32_t last_session_use;
|
||||
|
||||
#define TSTATE_NONE 0
|
||||
@@ -63,6 +85,7 @@ __xdata uint32_t last_session_use;
|
||||
#define TSTATE_CLOSED 3
|
||||
#define TSTATE_POST 4
|
||||
#define TSTATE_MULTIPART 5
|
||||
#define TSTATE_POSTBODY 6
|
||||
|
||||
extern __xdata uint16_t crc_value;
|
||||
__xdata uint16_t crc_final;
|
||||
@@ -77,10 +100,12 @@ 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));
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
fw_reset_pending = 0; // xdata is not zeroed by the startup code
|
||||
}
|
||||
|
||||
|
||||
@@ -109,8 +134,8 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
u = *xdata_str_p++;
|
||||
c = *code_str_p++;
|
||||
|
||||
if (c == '\0') {
|
||||
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
||||
if (c == NUL) {
|
||||
if (u != NUL && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -122,6 +147,24 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
}
|
||||
|
||||
|
||||
/* name must be lower-case, starting with the '\n' of the previous line's end */
|
||||
__xdata uint8_t *header_value(__xdata uint8_t *p, __code uint8_t *name)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
while ((c = *name++)) {
|
||||
u = *p++;
|
||||
if (u >= 'A' && u <= 'Z')
|
||||
u += 'a' - 'A';
|
||||
if (u != c)
|
||||
return 0;
|
||||
}
|
||||
while (*p == ' ' || *p == '\t')
|
||||
p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
|
||||
{
|
||||
uint8_t u, s;
|
||||
@@ -130,8 +173,8 @@ bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
|
||||
u = *uri_str_p++;
|
||||
s = *src_str_p++;
|
||||
|
||||
if (s == '\0') {
|
||||
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
||||
if (s == NUL) {
|
||||
if (u != NUL && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -165,7 +208,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;
|
||||
|
||||
@@ -173,9 +216,9 @@ bool is_word_x(__xdata uint8_t *lhs_str_p, __xdata uint8_t *rhs_str_p)
|
||||
u = *lhs_str_p++;
|
||||
c = *rhs_str_p++;
|
||||
|
||||
if (c == '\0') {
|
||||
if (c == NUL) {
|
||||
/* ';' separates cookies in a Cookie header, so it ends a value too. */
|
||||
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r' && u != ';')
|
||||
if (u != NUL && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r' && u != ';')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -197,7 +240,10 @@ uint8_t parse_short(__xdata uint8_t *p)
|
||||
c = *p++ - '0';
|
||||
if (c > 9) { break; }
|
||||
err = 0;
|
||||
short_parsed = (short_parsed * 10) + c;
|
||||
if (short_parsed > 6552)
|
||||
short_parsed = 0xffff;
|
||||
else
|
||||
short_parsed = (short_parsed * 10) + c;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -230,41 +276,48 @@ void send_unauthorized(void)
|
||||
}
|
||||
|
||||
|
||||
__xdata uint8_t *skip_boundary(__xdata uint8_t *p)
|
||||
void send_length_required(void)
|
||||
{
|
||||
while (*p) {
|
||||
if (is_word_x(p, boundary))
|
||||
return p + strlen_x(boundary);
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
slen = strtox(outbuf, "HTTP/1.1 411 Length Required\r\nConnection: close\r\n\r\n");
|
||||
}
|
||||
|
||||
|
||||
__xdata uint8_t *scan_header(__xdata uint8_t *p)
|
||||
void send_ok(void)
|
||||
{
|
||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
|
||||
}
|
||||
|
||||
|
||||
__xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
||||
{
|
||||
__xdata uint8_t *v;
|
||||
|
||||
content_type = 0;
|
||||
content_length = 0;
|
||||
session = 0;
|
||||
authenticated = 0;
|
||||
|
||||
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
||||
while (!strstart(p, "\r\n\r\n")) {
|
||||
dbg_char(*p);
|
||||
if (!*p++)
|
||||
if (!*p)
|
||||
break;
|
||||
if (is_word(p, "\nContent-Type:"))
|
||||
content_type = p + 15;
|
||||
else if (is_word(p, "\nCookie:")) {
|
||||
p++;
|
||||
if ((v = header_value(p, "\ncontent-type:")))
|
||||
content_type = v;
|
||||
else if ((v = header_value(p, "\ncontent-length:"))) {
|
||||
parse_short(v);
|
||||
content_length = short_parsed;
|
||||
} else if ((v = header_value(p, "\ncookie:"))) {
|
||||
/* Scan for the "session" key: the header may hold several
|
||||
* cookies in any order. Match "session" not "session=" -
|
||||
* is_word() requires a separator after the match and '=' is
|
||||
* one, so this also rejects a longer key like "sessionx". */
|
||||
__xdata uint8_t *c = p + 8; /* past "\nCookie:" */
|
||||
while (*c && *c != '\r' && *c != '\n') {
|
||||
if (is_word(c, "session")) {
|
||||
session = c + 8; /* past "session=" */
|
||||
while (*v && *v != '\r' && *v != '\n') {
|
||||
if (is_word(v, "session")) {
|
||||
session = v + 8; /* past "session=" */
|
||||
break;
|
||||
}
|
||||
c++;
|
||||
v++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -300,10 +353,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();
|
||||
@@ -315,21 +370,110 @@ 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)
|
||||
{
|
||||
// #386: needs static, otherwise it still lands in SRAM/DSEG
|
||||
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
|
||||
__xdata uint8_t cfg_bl;
|
||||
|
||||
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 >= pre_acc)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -342,17 +486,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
|
||||
@@ -360,18 +510,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) {
|
||||
@@ -379,8 +526,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');
|
||||
@@ -405,12 +552,184 @@ uint8_t stream_upload(uint16_t bptr)
|
||||
}
|
||||
|
||||
|
||||
static void handle_config_fragment(__xdata uint8_t *p)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata uint16_t frag_len;
|
||||
uint8_t taken;
|
||||
|
||||
frag_len = uip_len - (p - uip_appdata);
|
||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Configuration too large, aborting.\n");
|
||||
config_upload = 0;
|
||||
s->tstate = TSTATE_NONE;
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
memcpy(config_buf + pre_acc, p, frag_len);
|
||||
pre_acc += frag_len;
|
||||
taken = config_take();
|
||||
if (!taken) {
|
||||
s->tstate = TSTATE_MULTIPART;
|
||||
return;
|
||||
}
|
||||
config_upload = 0;
|
||||
s->tstate = TSTATE_NONE;
|
||||
if (taken == 2) {
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
send_ok();
|
||||
}
|
||||
|
||||
|
||||
static void handle_firmware_fragment(__xdata uint8_t *p)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata uint16_t frag_len, payload_start;
|
||||
|
||||
frag_len = uip_len - (p - uip_appdata);
|
||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Firmware upload header too large, aborting.\n");
|
||||
config_upload = 0;
|
||||
s->tstate = TSTATE_NONE;
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
memcpy(config_buf + pre_acc, p, frag_len);
|
||||
pre_acc += frag_len;
|
||||
payload_start = preamble_payload_start(pre_acc);
|
||||
if (!payload_start) {
|
||||
s->tstate = TSTATE_MULTIPART;
|
||||
return;
|
||||
}
|
||||
dbg_string("Have content octets\n");
|
||||
|
||||
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails
|
||||
set_sys_led_state(SYS_LED_FAST);
|
||||
|
||||
crc_value = 0;
|
||||
bindex = 0;
|
||||
write_len = 0;
|
||||
// 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 = payload_start;
|
||||
upload_settings.plen = pre_acc;
|
||||
stream_upload();
|
||||
|
||||
dbg_string("Done reading first fragment\n");
|
||||
}
|
||||
|
||||
|
||||
static void run_cmd_body(__xdata uint8_t *body)
|
||||
{
|
||||
uint16_t hdr_len = strtox(outbuf, HTTP_RESPONCE_TXT);
|
||||
|
||||
slen = hdr_len;
|
||||
cmd_capture = 1;
|
||||
execute_commands(body);
|
||||
if (cmd_capture == 2)
|
||||
slen += strtox(outbuf + slen, CMD_TRUNCATED);
|
||||
cmd_capture = 0;
|
||||
/* Commands that configure something print nothing at all. Saying
|
||||
* so beats an empty body, which reads the same as "nothing ran".
|
||||
* Only on success: a silent failure must not answer with "OK". */
|
||||
if (err_status == ERR_OK && slen == hdr_len)
|
||||
slen += strtox(outbuf + slen, "OK\n");
|
||||
/* On a parse error keep what the parser printed, because that text
|
||||
* is the explanation, and only restate the status. "400 NO" is as
|
||||
* long as "200 OK", so the header does not have to be rebuilt. */
|
||||
if (err_status != ERR_OK) {
|
||||
outbuf[9] = '4';
|
||||
outbuf[10] = '0';
|
||||
outbuf[11] = '0';
|
||||
outbuf[13] = 'N';
|
||||
outbuf[14] = 'O';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void run_login_body(__xdata uint8_t *body)
|
||||
{
|
||||
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
|
||||
dbg_string("Password accepted!\n");
|
||||
read_reg_timer(&last_session_use);
|
||||
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 (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 {
|
||||
dbg_string("Password invalid!\n");
|
||||
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: login.html\r\n\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t post_body_take(__xdata uint8_t *p)
|
||||
{
|
||||
uint16_t have;
|
||||
|
||||
if (!content_length) {
|
||||
send_length_required();
|
||||
return 0;
|
||||
}
|
||||
if (content_length >= CONFIG_UPLOAD_BUF) {
|
||||
send_bad_request();
|
||||
return 0;
|
||||
}
|
||||
have = uip_len - (p - uip_appdata);
|
||||
if (have >= content_length) {
|
||||
p[content_length] = NUL;
|
||||
return 1;
|
||||
}
|
||||
memcpy(config_buf, p, have);
|
||||
pre_acc = have;
|
||||
postbody_start = ticks;
|
||||
uip_conn->appstate.tstate = TSTATE_POSTBODY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void post_body_continue(void)
|
||||
{
|
||||
uint16_t take;
|
||||
|
||||
// no header scan runs while the body is pending: content_length is this request's
|
||||
take = content_length - pre_acc;
|
||||
if (take > uip_len)
|
||||
take = uip_len;
|
||||
memcpy(config_buf + pre_acc, uip_appdata, take);
|
||||
pre_acc += take;
|
||||
if (pre_acc < content_length) {
|
||||
postbody_start = ticks;
|
||||
return;
|
||||
}
|
||||
config_buf[pre_acc] = NUL;
|
||||
uip_conn->appstate.tstate = TSTATE_NONE;
|
||||
if (postbody_endpoint == POSTBODY_CMD)
|
||||
run_cmd_body(config_buf);
|
||||
else
|
||||
run_login_body(config_buf);
|
||||
}
|
||||
|
||||
|
||||
void handle_post(void)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata uint8_t *p = uip_appdata;
|
||||
__xdata uint8_t *request_path = p + 6;
|
||||
|
||||
if (s->tstate == TSTATE_POSTBODY) {
|
||||
post_body_continue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Was the multipart header sent in multiple packets?
|
||||
if (s->tstate != TSTATE_MULTIPART) {
|
||||
dbg_string("Is POST\n");
|
||||
@@ -418,10 +737,10 @@ void handle_post(void)
|
||||
// Find end of request path
|
||||
while (*p && !is_separator(*p))
|
||||
p++;
|
||||
*p++ = '\0';
|
||||
*p++ = NUL;
|
||||
|
||||
// Find end of request header
|
||||
boundary[0] ='\0';
|
||||
boundary[0] =NUL;
|
||||
p = scan_header(p);
|
||||
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
||||
if (!*p || !content_type) {
|
||||
@@ -437,20 +756,20 @@ void handle_post(void)
|
||||
return;
|
||||
}
|
||||
print_string("Firmware upload started.");
|
||||
config_upload = 0;
|
||||
uptr = FIRMWARE_UPLOAD_START;
|
||||
verify_crc = 1;
|
||||
max_upload = 1024576;
|
||||
pre_acc = 0;
|
||||
} else if (is_word(request_path, "config")) {
|
||||
if (!authenticated) {
|
||||
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;
|
||||
pre_acc = 0;
|
||||
}
|
||||
// Check for other POST requests, which are not multipart, below
|
||||
} else {
|
||||
@@ -463,11 +782,11 @@ void handle_post(void)
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
execute_commands(p);
|
||||
if (err_status != ERR_OK) {
|
||||
send_bad_request();
|
||||
postbody_endpoint = POSTBODY_CMD;
|
||||
if (!post_body_take(p))
|
||||
return;
|
||||
}
|
||||
run_cmd_body(p);
|
||||
return;
|
||||
} else if (is_word(request_path, "login")) {
|
||||
dbg_string("POST login\n");
|
||||
|
||||
@@ -477,21 +796,11 @@ void handle_post(void)
|
||||
return;
|
||||
}
|
||||
|
||||
p += 8; // Read also over "pwd="
|
||||
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);
|
||||
session_id[SESSION_ID_LENGTH] = '\0';
|
||||
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++)
|
||||
outbuf[slen++] = session_id[i];
|
||||
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
|
||||
} else {
|
||||
dbg_string("Password invalid!\n");
|
||||
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: login.html\r\n\r\n");
|
||||
}
|
||||
p += 4;
|
||||
postbody_endpoint = POSTBODY_LOGIN;
|
||||
if (!post_body_take(p))
|
||||
return;
|
||||
run_login_body(p);
|
||||
return;
|
||||
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
dbg_string("POST upload/config request\n");
|
||||
@@ -504,42 +813,15 @@ void handle_post(void)
|
||||
send_bad_request();
|
||||
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"));
|
||||
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);
|
||||
|
||||
crc_value = 0;
|
||||
bindex = 0;
|
||||
write_len = 0;
|
||||
stream_upload(p - uip_appdata);
|
||||
|
||||
dbg_string("Done reading first fragment\n");
|
||||
if (config_upload)
|
||||
handle_config_fragment(p);
|
||||
else
|
||||
handle_firmware_fragment(p);
|
||||
return;
|
||||
|
||||
} else {
|
||||
send_not_found();
|
||||
return;
|
||||
}
|
||||
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
|
||||
return;
|
||||
bad_request:
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -560,7 +842,7 @@ void httpd_appcall(void)
|
||||
} else if (uip_closed()) {
|
||||
dbg_string("Connection closed\n");
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
} else if (uip_aborted()) {
|
||||
} else if (uip_aborted() || uip_timedout()) {
|
||||
dbg_string("Connection aborted\n");
|
||||
uip_close();
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
@@ -570,6 +852,11 @@ void httpd_appcall(void)
|
||||
dbg_string("Closing because everything has been transmitted\n");
|
||||
uip_close();
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
} else if (s->tstate == TSTATE_POSTBODY
|
||||
&& (uint16_t)ticks - postbody_start > POSTBODY_TIMEOUT) {
|
||||
dbg_string("Body never arrived\n");
|
||||
uip_abort();
|
||||
s->tstate = TSTATE_CLOSED;
|
||||
}
|
||||
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
||||
dbg_string("ACK\n");
|
||||
@@ -603,11 +890,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();
|
||||
@@ -625,24 +924,31 @@ void httpd_appcall(void)
|
||||
dbg_char('\n');
|
||||
#endif
|
||||
p = uip_appdata;
|
||||
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART) {
|
||||
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART
|
||||
|| s->tstate == TSTATE_POSTBODY) {
|
||||
handle_post();
|
||||
// If this is an ongoing post stream, then wait for the next packet
|
||||
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART) {
|
||||
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART
|
||||
|| s->tstate == TSTATE_POSTBODY) {
|
||||
uip_len = 0;
|
||||
return;
|
||||
}
|
||||
goto do_send;
|
||||
}
|
||||
|
||||
if (is_word(p, "GET"))
|
||||
dbg_string("GET request ");
|
||||
// We only expect a GET request here.
|
||||
if (!is_word(p, "GET")) {
|
||||
send_bad_request();
|
||||
goto do_send;
|
||||
}
|
||||
|
||||
dbg_string("GET request ");
|
||||
p += 4;
|
||||
scan_header(p);
|
||||
__xdata uint8_t *q = p;
|
||||
while (*p && !is_separator(*p))
|
||||
p++;
|
||||
*p = '\0';
|
||||
*p = NUL;
|
||||
dbg_string_x(q);
|
||||
dbg_char('\n');
|
||||
|
||||
@@ -664,16 +970,9 @@ void httpd_appcall(void)
|
||||
parse_short(q + 15);
|
||||
send_vlan(short_parsed);
|
||||
} else if (is_word(q, "/counters.json")) {
|
||||
/* 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)
|
||||
if (send_counters(cport))
|
||||
send_bad_request();
|
||||
else
|
||||
send_counters(cport);
|
||||
} else if (is_word(q, "/eee.json")) {
|
||||
send_eee();
|
||||
} else if (is_word(q, "/bandwidth.json")) {
|
||||
@@ -690,6 +989,8 @@ void httpd_appcall(void)
|
||||
send_mtu();
|
||||
} else if (is_word(q, "/lag.json")) {
|
||||
send_lag();
|
||||
} else if (is_word(q, "/stp.json")) {
|
||||
send_stp();
|
||||
} else if (is_word(q, "/vlanlist")) {
|
||||
send_vlanlist();
|
||||
} else if (is_word(q, "/config")) {
|
||||
@@ -711,6 +1012,7 @@ void httpd_appcall(void)
|
||||
if (!authenticated && !(f_data[entry].start == FDATA_START_login_html
|
||||
|| f_data[entry].start == FDATA_START_port_svg
|
||||
|| f_data[entry].start == FDATA_START_sfp_svg
|
||||
|| f_data[entry].start == FDATA_START_i18n_js
|
||||
|| f_data[entry].start == FDATA_START_style_css)) {
|
||||
send_to_login();
|
||||
goto do_send;
|
||||
|
||||
+185
-64
@@ -12,6 +12,7 @@
|
||||
#include "phy.h"
|
||||
#include "version.h"
|
||||
#include "machine.h"
|
||||
#include "rtl837x_stp.h"
|
||||
#include "page_impl.h"
|
||||
#include "syslog.h"
|
||||
|
||||
@@ -47,7 +48,7 @@ extern __xdata char sfp_module_serial[2][17];
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
|
||||
__code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||
__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n";
|
||||
__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
||||
|
||||
// Convert uint8_t to ascii HEX char push on html-buffer.
|
||||
void charhex_to_html(char c)
|
||||
@@ -157,14 +158,14 @@ void sfr_data_to_html(void)
|
||||
}
|
||||
|
||||
|
||||
void reg_to_html(register uint16_t reg)
|
||||
void reg_to_html(uint16_t reg)
|
||||
{
|
||||
reg_read_m(reg);
|
||||
sfr_data_to_html();
|
||||
}
|
||||
|
||||
|
||||
void reg_to_html_long(register uint16_t reg)
|
||||
void reg_to_html_long(uint16_t reg)
|
||||
{
|
||||
reg_read_m(reg);
|
||||
byte_to_html(sfr_data[0]);
|
||||
@@ -177,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))
|
||||
return;
|
||||
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);
|
||||
}
|
||||
@@ -193,32 +196,11 @@ 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);
|
||||
}
|
||||
if (!sfp_read_block(slot, reg, len))
|
||||
return;
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -241,11 +223,12 @@ void send_basic_info(void)
|
||||
itoa_html(uip_netmask[0] >> 8); char_to_html('.');
|
||||
itoa_html(uip_netmask[1]); char_to_html('.');
|
||||
itoa_html(uip_netmask[1] >> 8);
|
||||
slen += strtox(outbuf + slen, "\",\"syslog_server_ip\":\"");
|
||||
slen += strtox(outbuf + slen, "\",\"syslog_server\":\"");
|
||||
itoa_html(syslog_state.server_ip[0]); char_to_html('.');
|
||||
itoa_html(syslog_state.server_ip[1]); char_to_html('.');
|
||||
itoa_html(syslog_state.server_ip[2]); char_to_html('.');
|
||||
itoa_html(syslog_state.server_ip[3]);
|
||||
itoa_html(syslog_state.server_ip[3]); char_to_html(':');
|
||||
itoa16_html(syslog_state.server_port);
|
||||
slen += strtox(outbuf + slen, "\",\"mac_address\":\"");
|
||||
byte_to_html(uip_ethaddr.addr[0]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[1]); char_to_html(':');
|
||||
@@ -309,17 +292,26 @@ void send_vlan(uint16_t vlan)
|
||||
slen += strtox(outbuf + slen, "\"}");
|
||||
}
|
||||
|
||||
|
||||
void send_counters(char port)
|
||||
/* Send counters
|
||||
* Only accepts physical port 1..9.
|
||||
* Returns an error if the port physical don't exists.
|
||||
*/
|
||||
bool send_counters(uint8_t phys_port)
|
||||
{
|
||||
dbg_string("send_counters called: "); dbg_byte(port); dbg_char('\n');
|
||||
uint8_t phys_port_idx = phys_port - 1;
|
||||
if (phys_port_idx > 8)
|
||||
goto err;
|
||||
uint8_t log_port = machine.phys_to_log_port[phys_port_idx];
|
||||
if (log_port == 0)
|
||||
goto err;
|
||||
|
||||
dbg_string("send_counters called: "); dbg_byte(phys_port_idx); dbg_char('\n');
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("sending counters\n");
|
||||
dbg_byte(port);
|
||||
uint8_t i = machine.phys_to_log_port[port];
|
||||
slen += strtox(outbuf + slen, "[");
|
||||
dbg_string("sending counters\n"); dbg_byte(phys_port_idx);
|
||||
|
||||
char_to_html('[');
|
||||
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
||||
STAT_GET(counter, i);
|
||||
STAT_GET(counter, log_port);
|
||||
slen += strtox(outbuf + slen, "\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||
@@ -328,6 +320,12 @@ void send_counters(char port)
|
||||
char_to_html(',');
|
||||
}
|
||||
char_to_html(']');
|
||||
|
||||
return false;
|
||||
|
||||
err:
|
||||
dbg_string("Error: counters: phy_port_idx don't exists\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -397,7 +395,7 @@ void send_l2(uint16_t idx)
|
||||
|
||||
// type
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_C);
|
||||
if (sfr_data[2] & 0x1)
|
||||
if (sfr_data[1] & 0x1)
|
||||
slen += strtox(outbuf + slen, "\",\"type\":\"s\",\"port\":");
|
||||
else
|
||||
slen += strtox(outbuf + slen, "\",\"type\":\"l\",\"port\":");
|
||||
@@ -435,42 +433,52 @@ void l2_delete(uint16_t idx)
|
||||
__xdata uint8_t entries_left = L2_MAX_TRANSFER;
|
||||
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & TBL_EXECUTE);
|
||||
reg_read(RTL837X_TBL_CTRL);
|
||||
} while (SFR_DATA_0 & TBL_EXECUTE);
|
||||
slen += strtox(outbuf + slen, "{\"result\":");
|
||||
// First, search for the entry based on the index
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
REG_WRITE(RTL837x_TBL_DATA_0, sfr_data[0], sfr_data[1] & 0xfc, sfr_data[2] | (TBL_LUTREAD_NEXT_L2UC << 6), sfr_data[3]);
|
||||
sfr_data[1] &= 0xfc;
|
||||
sfr_data[2] |= (TBL_LUTREAD_NEXT_L2UC << 6);
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
|
||||
REG_WRITE(RTL837X_TBL_CTRL, (idx >> 8) & 0xf, idx, TBL_L2_UNICAST, TBL_EXECUTE);
|
||||
do {
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
reg_read(RTL837X_TBL_CTRL);
|
||||
} while (SFR_DATA_0 & 0x1);
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
if (!(sfr_data[0] & 0x20)) {
|
||||
if (!(SFR_DATA_24 & 0x20)) {
|
||||
char_to_html('0');
|
||||
} else {
|
||||
__bit is_our_mac_addr = uip_ethaddr.addr[0] == SFR_DATA_8 && uip_ethaddr.addr[1] == SFR_DATA_0;
|
||||
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 (is_our_mac_addr && uip_ethaddr.addr[2] == SFR_DATA_24 && uip_ethaddr.addr[3] == SFR_DATA_16
|
||||
&& uip_ethaddr.addr[4] == SFR_DATA_8 && uip_ethaddr.addr[5] == SFR_DATA_0) {
|
||||
// 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);
|
||||
sfr_data[2] = TBL_L2_UNICAST;
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
|
||||
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(RTL837X_TBL_CTRL);
|
||||
} while (SFR_DATA_0 & TBL_EXECUTE);
|
||||
|
||||
char_to_html('1');
|
||||
char_to_html('1');
|
||||
}
|
||||
}
|
||||
char_to_html('}');
|
||||
}
|
||||
@@ -535,6 +543,119 @@ void send_lag(void)
|
||||
}
|
||||
|
||||
|
||||
static __xdata uint32_t pi_u32;
|
||||
static __xdata uint8_t pi_prio, pi_ext;
|
||||
static __xdata uint8_t * __xdata pi_mac;
|
||||
|
||||
|
||||
static void u32hex_html(void)
|
||||
{
|
||||
__xdata uint8_t *b = (__xdata uint8_t *)&pi_u32;
|
||||
byte_to_html(b[3]);
|
||||
byte_to_html(b[2]);
|
||||
byte_to_html(b[1]);
|
||||
byte_to_html(b[0]);
|
||||
}
|
||||
|
||||
|
||||
static void bridge_to_html(void)
|
||||
{
|
||||
byte_to_html(pi_prio);
|
||||
byte_to_html(pi_ext);
|
||||
for (uint8_t i = 0; i < 6; i++)
|
||||
byte_to_html(pi_mac[i]);
|
||||
}
|
||||
|
||||
|
||||
void send_stp(void)
|
||||
{
|
||||
uint8_t i, j, st, dsg;
|
||||
|
||||
dbg_string("send_stp called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
|
||||
slen += strtox(outbuf + slen, "{\"on\":");
|
||||
bool_to_html(stp_enabled);
|
||||
slen += strtox(outbuf + slen, ",\"rstp\":");
|
||||
bool_to_html(stp_rstp);
|
||||
slen += strtox(outbuf + slen, ",\"prio\":");
|
||||
itoa_html(stp_prio >> 4);
|
||||
slen += strtox(outbuf + slen, ",\"hello\":");
|
||||
itoa_html(stp_hello_s);
|
||||
slen += strtox(outbuf + slen, ",\"maxage\":");
|
||||
itoa_html(stp_maxage_s);
|
||||
slen += strtox(outbuf + slen, ",\"fwd\":");
|
||||
itoa_html(stp_fwddelay_s);
|
||||
slen += strtox(outbuf + slen, ",\"txhold\":");
|
||||
itoa_html(stp_txhold);
|
||||
slen += strtox(outbuf + slen, ",\"rootPrio\":\"");
|
||||
byte_to_html(root_bridge.prio);
|
||||
byte_to_html(root_bridge.ext);
|
||||
slen += strtox(outbuf + slen, "\",\"rootMac\":\"");
|
||||
for (j = 0; j < 6; j++)
|
||||
byte_to_html(root_bridge.mac[j]);
|
||||
slen += strtox(outbuf + slen, "\",\"myMac\":\"");
|
||||
for (j = 0; j < 6; j++)
|
||||
byte_to_html(uip_ethaddr.addr[j]);
|
||||
slen += strtox(outbuf + slen, "\",\"cost\":\"");
|
||||
byte_to_html(root_bridge_cost >> 24);
|
||||
byte_to_html(root_bridge_cost >> 16);
|
||||
byte_to_html(root_bridge_cost >> 8);
|
||||
byte_to_html(root_bridge_cost);
|
||||
slen += strtox(outbuf + slen, "\",\"weRoot\":");
|
||||
bool_to_html(stp_root_port == 0xff ? 1 : 0);
|
||||
slen += strtox(outbuf + slen, ",\"rootPort\":");
|
||||
itoa_html(stp_root_port == 0xff ? 0 : machine.log_to_phys_port[stp_root_port]);
|
||||
slen += strtox(outbuf + slen, ",\"tc\":\"");
|
||||
byte_to_html(stp_tc_count >> 8);
|
||||
byte_to_html(stp_tc_count);
|
||||
slen += strtox(outbuf + slen, "\",\"ports\":[");
|
||||
reg_read_m(RTL837X_MSTP_STATES);
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"p\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
slen += strtox(outbuf + slen, ",\"st\":");
|
||||
st = (sfr_data[3 - (i >> 2)] >> ((i << 1) & 0x7)) & 0x3;
|
||||
itoa_html(st);
|
||||
slen += strtox(outbuf + slen, ",\"role\":");
|
||||
if (!(stp_pflags[i] & STP_PF_ENABLED) || (stp_pflags[i] & STP_PF_TRIPPED))
|
||||
itoa_html(0);
|
||||
else if (i == stp_root_port)
|
||||
itoa_html(1);
|
||||
else if (st == 3)
|
||||
itoa_html(2);
|
||||
else
|
||||
itoa_html(3);
|
||||
slen += strtox(outbuf + slen, ",\"f\":");
|
||||
itoa_html(stp_pflags[i]);
|
||||
slen += strtox(outbuf + slen, ",\"pc\":\"");
|
||||
pi_u32 = stp_pcost[i]; u32hex_html();
|
||||
slen += strtox(outbuf + slen, "\",\"prio\":");
|
||||
itoa_html(stp_pprio[i]);
|
||||
slen += strtox(outbuf + slen, ",\"p2\":");
|
||||
itoa_html(stp_pp2p[i]);
|
||||
dsg = stp_dpid[i] && stp_bpdu_age[i] < (uint16_t)stp_maxage_s * STP_HZ;
|
||||
slen += strtox(outbuf + slen, ",\"db\":\"");
|
||||
if (dsg) {
|
||||
pi_prio = stp_dbridge[i].prio; pi_ext = stp_dbridge[i].ext;
|
||||
pi_mac = stp_dbridge[i].mac;
|
||||
} else {
|
||||
pi_prio = stp_prio; pi_ext = 0;
|
||||
pi_mac = uip_ethaddr.addr;
|
||||
}
|
||||
bridge_to_html();
|
||||
slen += strtox(outbuf + slen, "\",\"dp\":\"");
|
||||
byte_to_html(dsg ? (stp_dpid[i] >> 8) : stp_pprio[i]);
|
||||
byte_to_html(dsg ? stp_dpid[i] : (i + 1));
|
||||
slen += strtox(outbuf + slen, "\",\"dc\":\"");
|
||||
pi_u32 = dsg ? stp_dcost[i] : root_bridge_cost; u32hex_html();
|
||||
slen += strtox(outbuf + slen, "\"},");
|
||||
}
|
||||
slen -= 1; // remove comma
|
||||
slen += strtox(outbuf + slen, "]}");
|
||||
}
|
||||
|
||||
|
||||
void send_eee(void)
|
||||
{
|
||||
dbg_string("send_eee called\nsending EEE status\n");
|
||||
@@ -702,13 +823,13 @@ void send_status(void)
|
||||
sfp_send_data(sfp, 238, 1);
|
||||
}
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
||||
for (register uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_vendor[sfp][s];
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
||||
for (register uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_model[sfp][s];
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
||||
for (register uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_serial[sfp][s];
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
||||
if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
|
||||
@@ -822,7 +943,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;
|
||||
|
||||
+6
-1
@@ -1,7 +1,11 @@
|
||||
#ifndef __PAGE_IMPL_H__
|
||||
#define __PAGE_IMPL_H__
|
||||
|
||||
void send_counters(char port);
|
||||
#include <stdbool.h>
|
||||
|
||||
extern __code uint8_t * __code HTTP_RESPONCE_TXT;
|
||||
|
||||
bool send_counters(uint8_t phys_port);
|
||||
void send_status(void);
|
||||
void send_vlan(uint16_t vlan);
|
||||
void send_basic_info(void);
|
||||
@@ -14,6 +18,7 @@ void send_mtu(void);
|
||||
void send_config(void);
|
||||
void send_cmd_log(void);
|
||||
void send_lag(void);
|
||||
void send_stp(void);
|
||||
void send_vlanlist(void);
|
||||
|
||||
/* Convert only the lower nibble to ascii HEX char.
|
||||
|
||||
Reference in new issue
Block a user