mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-08-30 14:52:51 +08:00
On a QSFPTEK QT-SFP+-T (RTL8261C) 10GBase-T module, the diag type field (92) comes back as 0x00, but there's actually some statistics available like temperature. Other metrics may be hard-coded values. Add a basic struct that allows matching on vendor and/or model, using a bitfield to allow multiple quirks for a given SFP module. Only SFP_QUIRK_DDM is implemented. For modules matching SFP_QUIRK_DDM, attempt an I2C read of the MSB of module voltage during probe if DDM is "unsupported" - if it's not 0xff, override the reported options so we can pull the diagnostic data. To allow simpler comparisons, convert the ASCII fields (vendor, model, serial) from space-padded to standard NULL-terminated strings. strcmp() is moved from httpd.c to rtlplayground.c alongside other string functions and shared between them. The __reentrant keyword is used for the new functions to avoid using up additional OSEG space. This allocates the variables on the stack, which is OK for this particular code path. The JSON assembly in send_status() is slightly modified to treat the sfp_module_* data as standard NULL-terminated strings, and a repeated subtraction was moved into a uint8_t to declutter the code.
746 lines
19 KiB
C
746 lines
19 KiB
C
|
|
#include "httpd.h"
|
|
#include "page_impl.h"
|
|
#include "rtl837x_common.h"
|
|
#include "rtl837x_regs.h"
|
|
#include "cmd_parser.h"
|
|
#include "rtl837x_flash.h"
|
|
#include "uip.h"
|
|
#include "html_data.h"
|
|
|
|
// #define DEBUG
|
|
#include "debug.h"
|
|
|
|
#define SESSION_ID_LENGTH 12
|
|
#define SESSION_TIMEOUT 200
|
|
|
|
#define CMARK_S 6
|
|
|
|
#pragma codeseg BANK1
|
|
#pragma constseg BANK1
|
|
|
|
extern volatile __xdata uint8_t sfr_data[4];
|
|
extern __code uint8_t * __code hex;
|
|
extern __code struct f_data f_data[];
|
|
extern __code char * __code mime_strings[];
|
|
extern __xdata struct flash_region_t flash_region;
|
|
extern __xdata uint32_t flash_size;
|
|
|
|
// Flash buffer to optimize flash writing speed, write_len is the current filling position
|
|
extern __xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
|
__xdata uint32_t uptr; // Current flash write position
|
|
__xdata uint16_t write_len;
|
|
|
|
__xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
|
__xdata uint8_t entry;
|
|
__xdata uint16_t slen;
|
|
__xdata uint16_t o_idx;
|
|
__xdata uint16_t len_left;
|
|
__xdata uint16_t cont_len;
|
|
__xdata uint32_t cont_addr;
|
|
|
|
// HTTP header properties
|
|
__xdata uint8_t boundary[72];
|
|
__xdata uint8_t *content_type = 0;
|
|
__xdata uint8_t *session = 0;
|
|
|
|
// Global variables holding POST state
|
|
__xdata uint16_t bindex; // Current index into the boundary
|
|
__xdata uint8_t verify_crc;
|
|
__xdata uint32_t max_upload;
|
|
__xdata uint16_t short_parsed;
|
|
|
|
__xdata char passwd[21];
|
|
__xdata char session_id[SESSION_ID_LENGTH + 1];
|
|
__xdata uint8_t authenticated;
|
|
__xdata uint32_t now;
|
|
__xdata uint8_t *timeptr;
|
|
__xdata uint32_t last_session_use;
|
|
|
|
#define TSTATE_NONE 0
|
|
#define TSTATE_TX 1
|
|
#define TSTATE_ACKED 2
|
|
#define TSTATE_CLOSED 3
|
|
#define TSTATE_POST 4
|
|
#define TSTATE_MULTIPART 5
|
|
|
|
extern __xdata uint16_t crc_value;
|
|
__xdata uint16_t crc_final;
|
|
void crc16(__xdata uint8_t *v) __naked;
|
|
|
|
|
|
inline uint8_t is_separator(uint8_t c)
|
|
{
|
|
return c == ' ' || c == '\t' || c == '?' || c == '=';
|
|
}
|
|
|
|
|
|
void httpd_init(void) __banked
|
|
{
|
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
|
// Start listening to port 80
|
|
uip_listen(HTONS(80));
|
|
s->tstate = TSTATE_CLOSED;
|
|
}
|
|
|
|
|
|
uint8_t find_entry(__xdata uint8_t *e)
|
|
{
|
|
uint8_t i, j;
|
|
|
|
for (i = 0; f_data[i].len; i++) {
|
|
j = 0;
|
|
while (f_data[i].file[j] && (f_data[i].file[j] == e[j])) {
|
|
j++;
|
|
}
|
|
if ((!f_data[i].file[j]) && (!e[j])) {
|
|
return i;
|
|
}
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
|
|
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
|
{
|
|
uint8_t u, c;
|
|
|
|
while (1) {
|
|
u = *xdata_str_p++;
|
|
c = *code_str_p++;
|
|
|
|
if (c == '\0') {
|
|
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
if (c != u) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
|
|
{
|
|
uint8_t u, s;
|
|
|
|
while(1) {
|
|
u = *uri_str_p++;
|
|
s = *src_str_p++;
|
|
|
|
if (s == '\0') {
|
|
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
if (u == '%') {
|
|
bool again = true;
|
|
u = 0;
|
|
|
|
while(1) {
|
|
// Swap instruction is fine for rotation
|
|
u = (u << 4) | (u >> 4);
|
|
|
|
uint8_t p = *uri_str_p++;
|
|
u |= p - '0' < 10 ? (p - '0') : (p - 'A' + 10);
|
|
|
|
// force `jbc`-instruction.
|
|
if (again) {
|
|
again = false;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
} else if (u == '+') {
|
|
u = ' ';
|
|
}
|
|
|
|
if (s != u) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool is_word_x(__xdata uint8_t *lhs_str_p, __xdata uint8_t *rhs_str_p)
|
|
{
|
|
uint8_t u, c;
|
|
|
|
while (1) {
|
|
u = *lhs_str_p++;
|
|
c = *rhs_str_p++;
|
|
|
|
if (c == '\0') {
|
|
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
if (c != u) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
uint8_t parse_short(__xdata uint8_t *p)
|
|
{
|
|
uint8_t err = 1;
|
|
uint8_t c = 0;
|
|
|
|
short_parsed = 0;
|
|
while(1) {
|
|
c = *p++ - '0';
|
|
if (c > 9) { break; }
|
|
err = 0;
|
|
short_parsed = (short_parsed * 10) + c;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
void send_not_found(void)
|
|
{
|
|
slen = strtox(outbuf, "HTTP/1.1 404 Not found\r\nContent-Type: text/html\r\n\r\n" \
|
|
"<!DOCTYPE HTML PUBLIC>\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n");
|
|
}
|
|
|
|
|
|
void send_bad_request(void)
|
|
{
|
|
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n\r\n" \
|
|
"<!DOCTYPE HTML PUBLIC>\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n");
|
|
}
|
|
|
|
|
|
void send_to_login(void)
|
|
{
|
|
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\n" \
|
|
"Location: login.html\r\n\r\n");
|
|
}
|
|
|
|
|
|
void send_unauthorized(void)
|
|
{
|
|
slen = strtox(outbuf, "HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
}
|
|
|
|
|
|
__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)
|
|
{
|
|
content_type = 0;
|
|
session = 0;
|
|
authenticated = 0;
|
|
|
|
while (*p != '\r' || *(p + 1) != '\n' || *(p + 2) != '\r' || *(p + 3) != '\n') {
|
|
dbg_char(*p);
|
|
if (!*p++)
|
|
break;
|
|
if (is_word(p, "\nContent-Type:"))
|
|
content_type = p + 15;
|
|
else if (is_word(p, "\nCookie:"))
|
|
session = p + 17;
|
|
}
|
|
if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
|
|
dbg_string("\nFound multipart\n");
|
|
content_type += 30;
|
|
uint8_t i = 0;
|
|
while (content_type[i] != '\r' && content_type[i] != '\n') {
|
|
boundary[i + 4] = content_type[i];
|
|
i++;
|
|
}
|
|
// The boundary between parts is "\r\n--" + the boundary given in the header
|
|
boundary[0] = '\r';
|
|
boundary[1] = '\n';
|
|
boundary[2] = '-';
|
|
boundary[3] = '-';
|
|
boundary[i + 4] = 0;
|
|
}
|
|
|
|
read_reg_timer(&now);
|
|
|
|
if (session) {
|
|
if (now - last_session_use > SESSION_TIMEOUT) {
|
|
dbg_string("Session expired\n");
|
|
} else {
|
|
if (is_word_x(session, session_id))
|
|
authenticated = 1;
|
|
else
|
|
dbg_string("Invalid session cookie!\n");
|
|
}
|
|
}
|
|
return p;
|
|
}
|
|
|
|
|
|
void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes)
|
|
{
|
|
__xdata uint8_t i = 0;
|
|
while (bytes) {
|
|
if (!i)
|
|
get_random_32();
|
|
b[--bytes] = itohex(sfr_data[i]);
|
|
if (!bytes) { break; }
|
|
b[--bytes] = itohex(sfr_data[i] >> 4 | sfr_data[i] << 4);
|
|
i = (i + 1) & 0x3;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Reads post data from the http stream and writes it into flash memory
|
|
* Input: the current position in the TCP buffer (uip_appdata)
|
|
* Returns 1: More data to read, 0: Upload complete, all parts reads
|
|
*/
|
|
uint8_t stream_upload(uint16_t bptr)
|
|
{
|
|
__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');
|
|
|
|
do {
|
|
if (bptr >= uip_len) {
|
|
s->tstate = TSTATE_POST;
|
|
return 1;
|
|
}
|
|
// Have we reached the end of the part?
|
|
if (!boundary[bindex]) {
|
|
s->tstate = TSTATE_NONE;
|
|
dbg_string("len 2: "); dbg_short(write_len); dbg_char(' ');
|
|
flash_region.addr = uptr;
|
|
flash_region.len = write_len;
|
|
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');
|
|
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();
|
|
} else {
|
|
print_string("Checksum incorrect! Aborting.\n");
|
|
uip_close();
|
|
}
|
|
}
|
|
// Make sure there is a 0 at the end of the uploaded data
|
|
flash_buf[0] = 0;
|
|
flash_region.addr = uptr;
|
|
flash_region.len = 1;
|
|
flash_write_bytes(flash_buf);
|
|
if (bptr >= uip_len)
|
|
return 0;
|
|
if(!verify_crc)
|
|
//ugly hack to signal connection finished after config upload.
|
|
uip_close();
|
|
return 1;
|
|
}
|
|
if (p[bptr] == boundary[bindex]) {
|
|
if (!bindex)
|
|
crc_final = crc_value;
|
|
crc16(p + bptr);
|
|
bptr++;
|
|
bindex++;
|
|
} else {
|
|
if (bindex) {
|
|
memcpy(flash_buf + write_len, boundary, bindex);
|
|
write_len += bindex;
|
|
bindex = 0;
|
|
}
|
|
crc16(p + bptr);
|
|
flash_buf[write_len++] = p[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');
|
|
if (uptr % FLASH_SECTOR_SIZE == 0) {
|
|
flash_region.addr = uptr;
|
|
flash_sector_erase();
|
|
}
|
|
flash_region.addr = uptr;
|
|
flash_region.len = FLASH_PAGE_SIZE;
|
|
flash_write_bytes(flash_buf);
|
|
uptr += FLASH_PAGE_SIZE;
|
|
write_len -= FLASH_PAGE_SIZE;
|
|
|
|
// Copy the remaining byte for the next page to the beginning of the buffer.
|
|
if (write_len > 0) {
|
|
memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len);
|
|
}
|
|
}
|
|
bindex = 0;
|
|
}
|
|
} while(1);
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
// Was the multipart header sent in multiple packets?
|
|
if (s->tstate != TSTATE_MULTIPART) {
|
|
dbg_string("Is POST\n");
|
|
p += 5; // Skip post
|
|
// Find end of request path
|
|
while (*p && !is_separator(*p))
|
|
p++;
|
|
*p++ = '\0';
|
|
|
|
// Find end of request header
|
|
boundary[0] ='\0';
|
|
p = scan_header(p);
|
|
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
|
|
if (!*p || !content_type) {
|
|
dbg_string("Bad Request!\n");
|
|
send_not_found();
|
|
return;
|
|
}
|
|
if (is_word(request_path, "upload")) {
|
|
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
|
{
|
|
print_string("Flash too small for firmware upload!\n");
|
|
send_bad_request();
|
|
return;
|
|
}
|
|
print_string("Firmware upload started.");
|
|
uptr = FIRMWARE_UPLOAD_START;
|
|
verify_crc = 1;
|
|
max_upload = 1024576;
|
|
} else if (is_word(request_path, "config")) {
|
|
if (!authenticated) {
|
|
send_unauthorized();
|
|
return;
|
|
}
|
|
dbg_string("Configuration upload, erasing config mem!\n");
|
|
uptr = CONFIG_START;
|
|
verify_crc = 0;
|
|
max_upload = 2048;
|
|
flash_region.addr = CONFIG_START;
|
|
flash_sector_erase();
|
|
}
|
|
// Check for other POST requests, which are not multipart, below
|
|
} else {
|
|
dbg_string("Multipart request\n");
|
|
}
|
|
|
|
if (is_word(request_path, "cmd")) {
|
|
p += 4;
|
|
if (!authenticated) {
|
|
send_unauthorized();
|
|
return;
|
|
}
|
|
execute_commands(p);
|
|
if (err_status != ERR_OK) {
|
|
send_bad_request();
|
|
return;
|
|
}
|
|
} else if (is_word(request_path, "login")) {
|
|
dbg_string("POST login\n");
|
|
|
|
if (!content_type || !is_word(content_type, "application/x-www-form-urlencoded")) {
|
|
dbg_string("Bad request!\n");
|
|
send_bad_request();
|
|
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\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\nLocation: login.html\r\n\r\n");
|
|
}
|
|
return;
|
|
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
|
dbg_string("POST upload/config request\n");
|
|
if (!authenticated) {
|
|
send_unauthorized();
|
|
return;
|
|
}
|
|
if (!boundary[0]) {
|
|
dbg_string("Bad request, no boundary!\n");
|
|
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");
|
|
return;
|
|
|
|
} else {
|
|
send_not_found();
|
|
return;
|
|
}
|
|
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\n\r\n");
|
|
return;
|
|
bad_request:
|
|
send_bad_request();
|
|
return;
|
|
}
|
|
|
|
|
|
void httpd_appcall(void)
|
|
{
|
|
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
|
|
|
dbg_char('P');
|
|
#ifdef DEBUG
|
|
if (uip_newdata())
|
|
write_char('N');
|
|
print_byte(s->tstate);
|
|
write_char(' ');
|
|
#endif
|
|
if(uip_connected() && s->tstate == TSTATE_CLOSED) {
|
|
dbg_string("Connected...\n");
|
|
s->tstate = TSTATE_NONE;
|
|
} else if (uip_closed()) {
|
|
dbg_string("Connection closed\n");
|
|
s->tstate = TSTATE_CLOSED;
|
|
} else if (uip_aborted()) {
|
|
dbg_string("Connection aborted\n");
|
|
uip_close();
|
|
s->tstate = TSTATE_CLOSED;
|
|
} else if (uip_poll()) {
|
|
uip_len = 0;
|
|
if (s->tstate == TSTATE_ACKED) {
|
|
dbg_string("Closing because everything has been transmitted\n");
|
|
uip_close();
|
|
s->tstate = TSTATE_CLOSED;
|
|
}
|
|
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
|
dbg_string("ACK\n");
|
|
if (slen > uip_mss()) {
|
|
slen -= uip_mss();
|
|
o_idx += uip_mss();
|
|
} else {
|
|
slen = 0;
|
|
o_idx += slen;
|
|
}
|
|
|
|
s->tstate = TSTATE_ACKED;
|
|
|
|
if (slen > uip_mss()) {
|
|
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
|
uip_send(outbuf + o_idx, uip_mss());
|
|
s->tstate = TSTATE_TX;
|
|
} else if (slen > 0) {
|
|
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
|
uip_send(outbuf + o_idx, slen);
|
|
s->tstate = TSTATE_TX;
|
|
} else if (cont_len) {
|
|
dbg_string("CONT cont_len: "); dbg_short(cont_len);
|
|
slen = cont_len > uip_mss() ? uip_mss() : cont_len;
|
|
if (slen > TCP_OUTBUF_SIZE)
|
|
slen = TCP_OUTBUF_SIZE;
|
|
flash_region.addr = cont_addr;
|
|
flash_region.len = slen;
|
|
flash_read_bulk(outbuf);
|
|
uip_send(outbuf, slen);
|
|
cont_len -= slen;
|
|
cont_addr += slen;
|
|
s->tstate = TSTATE_TX;
|
|
}
|
|
} 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);
|
|
write_char('.');
|
|
} else {
|
|
send_bad_request();
|
|
goto do_send;
|
|
}
|
|
} else if (uip_newdata() && s->tstate != TSTATE_TX) {
|
|
cont_len = 0;
|
|
dbg_char('<'); dbg_short(uip_len); dbg_char('\n');
|
|
__xdata uint8_t *p = uip_appdata;
|
|
// Mark end of request header with \0
|
|
p[uip_len] = 0;
|
|
#ifdef DEBUG
|
|
while (*p)
|
|
dbg_char(*p++);
|
|
dbg_char('\n');
|
|
#endif
|
|
p = uip_appdata;
|
|
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART) {
|
|
handle_post();
|
|
// If this is an ongoing post stream, then wait for the next packet
|
|
if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART) {
|
|
uip_len = 0;
|
|
return;
|
|
}
|
|
goto do_send;
|
|
}
|
|
|
|
if (is_word(p, "GET"))
|
|
dbg_string("GET request ");
|
|
p += 4;
|
|
scan_header(p);
|
|
__xdata uint8_t *q = p;
|
|
while (!is_separator(*p))
|
|
p++;
|
|
*p = '\0';
|
|
dbg_string_x(q);
|
|
dbg_char('\n');
|
|
|
|
s->tstate = TSTATE_NONE;
|
|
entry = find_entry(q);
|
|
dbg_string("Entry is: "); dbg_byte(entry); dbg_char('\n');
|
|
if (entry == 0xff) {
|
|
if (!authenticated) {
|
|
dbg_string("Not authorized!\n");
|
|
send_unauthorized();
|
|
goto do_send;
|
|
}
|
|
dbg_string("Not file entry\n");
|
|
if (!strcmp(q, "/status.json")) {
|
|
send_status();
|
|
} else if (!strcmp(q, "/information.json")) {
|
|
send_basic_info();
|
|
} else if (!strcmp(q, "/vlan.json")) {
|
|
parse_short(q + 15);
|
|
send_vlan(short_parsed);
|
|
} else if (is_word(q, "/counters.json")) {
|
|
send_counters(q[20]-'0');
|
|
} else if (is_word(q, "/eee.json")) {
|
|
send_eee();
|
|
} else if (is_word(q, "/bandwidth.json")) {
|
|
send_bandwidth();
|
|
} else if (is_word(q, "/l2.json")) {
|
|
parse_short(q + 13); // e.g.: /l2.json?idx=10
|
|
send_l2(short_parsed);
|
|
} else if (is_word(q, "/l2_del.json")) {
|
|
parse_short(q + 17);
|
|
l2_delete(short_parsed);
|
|
} else if (is_word(q, "/mirror.json")) {
|
|
send_mirror();
|
|
} else if (is_word(q, "/mtu.json")) {
|
|
send_mtu();
|
|
} else if (is_word(q, "/lag.json")) {
|
|
send_lag();
|
|
} else if (is_word(q, "/vlanlist")) {
|
|
send_vlanlist();
|
|
} else if (is_word(q, "/config")) {
|
|
send_config();
|
|
} else if (is_word(q, "/cmd_log")) {
|
|
send_cmd_log();
|
|
} else if (is_word(q, "/cmd_log_clear")) {
|
|
clear_command_history();
|
|
send_mtu(); // dummy response
|
|
} else if (is_word(q, "/reset")) {
|
|
uip_close();
|
|
delay(1000); //wait for the close packet to be sent, otherwise the browser will retry
|
|
reset_chip();
|
|
} else {
|
|
send_not_found();
|
|
}
|
|
} else {
|
|
dbg_string("Have entry, authenticated: "); dbg_byte(authenticated); dbg_char('\n');
|
|
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_style_css)) {
|
|
send_to_login();
|
|
goto do_send;
|
|
}
|
|
// A web-page is actively accessed, we can reset session time-out
|
|
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
|
timeptr = (uint8_t*)&last_session_use; // last_session_use is Little endian
|
|
timeptr[0] = sfr_data[3]; timeptr[1] = sfr_data[2]; timeptr[2] = sfr_data[1]; timeptr[3] = sfr_data[0];
|
|
|
|
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: ");
|
|
slen += strtox(outbuf + slen, mime_strings[f_data[entry].mime]);
|
|
slen += strtox(outbuf + slen, "; charset=UTF-8\r\nCache-Control: max-age=60, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\nContent-Security-Policy: style-src 'self' 'unsafe-inline'\r\n\r\n");
|
|
|
|
len_left = f_data[entry].len;
|
|
if (len_left > (TCP_OUTBUF_SIZE - slen)) {
|
|
cont_len = len_left - (TCP_OUTBUF_SIZE - slen);
|
|
len_left = TCP_OUTBUF_SIZE - slen;
|
|
cont_addr = f_data[entry].start + len_left;
|
|
}
|
|
dbg_string("MIME: "); dbg_string(mime_strings[f_data[entry].mime]); dbg_char('\n');
|
|
flash_region.addr = f_data[entry].start;
|
|
flash_region.len = len_left;
|
|
flash_read_bulk(outbuf + slen);
|
|
slen += len_left;
|
|
}
|
|
do_send:
|
|
dbg_string("slen: "); dbg_short(slen); dbg_char('\n');
|
|
o_idx = 0;
|
|
if (slen > uip_mss()) {
|
|
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
|
uip_send(outbuf + o_idx, uip_mss());
|
|
dbg_string("Sending a done\n");
|
|
} else {
|
|
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
|
uip_send(outbuf + o_idx, slen);
|
|
dbg_string("Sending b done\n");
|
|
}
|
|
s->tstate = TSTATE_TX;
|
|
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
|
dbg_string("RETRANSMIT requested\n");
|
|
if (slen > uip_mss()) {
|
|
dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n');
|
|
uip_send(outbuf + o_idx, uip_mss());
|
|
dbg_string("Sending C done\n");
|
|
} else if (slen > 0) {
|
|
dbg_string("Sending D: "); dbg_short(slen); dbg_char('\n');
|
|
uip_send(outbuf + o_idx, slen);
|
|
dbg_string("Sending D done\n");
|
|
}
|
|
s->tstate = TSTATE_TX;
|
|
uip_len = 0;
|
|
} else {
|
|
uip_len = 0;
|
|
}
|
|
}
|