diff --git a/cmd_parser.c b/cmd_parser.c index 66b05bde..0c3cbff4 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -65,6 +65,13 @@ __xdata char save_cmd; __xdata uint8_t ip[4]; +/* Scratch for parse_syslog()'s port parser, in xdata: locals here would take + * internal RAM the linker has none of. */ +__xdata uint16_t syslog_port_scratch; +__xdata uint8_t syslog_port_idx; +__xdata uint8_t syslog_port_digit; +__xdata uint8_t syslog_port_was_on; + // These variables combined create a Fixed-capacity vector/bounded buffer. // `N_WORDS`: The total number of command arguments that can be tracked. // `cmd_words_len` stores the number of arguments found inside `cmd_buffer` @@ -1411,6 +1418,7 @@ void parse_syslog(void) if (syslog_state.enabled) { print_string("enabled, sending to "); print_ip(syslog_state.server_ip); + write_char(':'); itoa_short(syslog_state.server_port); write_char('\n'); } else { print_string("disabled\n"); @@ -1439,11 +1447,66 @@ void parse_syslog(void) } else { print_string("Invalid IP address\n"); } + } else if (cmd_compare(1, "port")) { + if (cmd_words_len < 3) { // no additional argument -> print current port + print_string("Current syslog port: "); + itoa_short(syslog_state.server_port); write_char('\n'); + return; + } + /* Parsed here rather than with atoi_short(), which reports "no + * digits" but not overflow - 65540 would quietly wrap to 4 and we + * would open a connection to a port nobody asked for. Checking + * before each multiply keeps this in 16-bit arithmetic. */ + syslog_port_scratch = 0; + syslog_port_idx = cmd_words_b[2]; + for (;;) { + /* Plain comparisons instead of isnumber() in the loop + * condition, and nested ifs instead of || and &&: either form + * makes SDCC park a boolean in the bit area, and an image + * carrying LACP and STP as well is one bit short of needing a + * third byte of it - which would push everything up and stop + * the link. */ + syslog_port_digit = cmd_buffer[syslog_port_idx]; + if (syslog_port_digit < '0') + break; + if (syslog_port_digit > '9') + break; + syslog_port_digit -= '0'; + if (syslog_port_scratch > 6553) { + syslog_port_scratch = 0; /* too large - reject below */ + break; + } + if (syslog_port_scratch == 6553) { + if (syslog_port_digit > 5) { + syslog_port_scratch = 0; + break; + } + } + syslog_port_scratch = syslog_port_scratch * 10 + syslog_port_digit; + syslog_port_idx++; + } + /* Zero covers all three ways to be wrong: no digits at all, a value + * past 65535, and an explicit "0", which is not a port either. */ + if (!syslog_port_scratch) { + print_string("Invalid port\n"); + return; + } + /* The port is frozen into the connection by uip_udp_new(), so + * changing it has to tear the connection down and build a new one - + * same dance as setting the address above. */ + syslog_port_was_on = syslog_state.enabled; + if (syslog_port_was_on) + syslog_stop(); + print_string("Setting new syslog port.\n"); + syslog_state.server_port = syslog_port_scratch; + if (syslog_port_was_on) + syslog_start(); } else { - print_string("Error: syslog [on|off|ip [ip-address]]\n"); - print_string(" on/off enables or disables syslog, ip sets the syslog server IP address\n"); + print_string("Error: syslog [on|off|ip [ip-address]|port [number]]\n"); + print_string(" on/off enables or disables syslog, ip sets the syslog server IP address,\n"); + print_string(" port sets the destination UDP port (default 514)\n"); } } diff --git a/html/config.js b/html/config.js index 8af3fbaa..7edeafd7 100644 --- a/html/config.js +++ b/html/config.js @@ -7,6 +7,7 @@ const conf_cmds = [ /^netmask\s+(\d{1,3}\.){3}\d{1,3}$/, /^syslog\s+(on|off)$/, /^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/, + /^syslog\s+port\s+\d{1,5}$/, /^passwd\s+\S+$/, /^vlan\s+\d{1,4}\s+d$/, /^vlan\s+\d{1,4}\s+mgmt$/, @@ -32,6 +33,7 @@ const conf_overwrite = [ /^gw\b/, /^netmask\b/, /^syslog\s+ip\b/, + /^syslog\s+port\b/, /^syslog\b/, /^passwd\b/, /^vlan\s+\d{1,4}\s+mgmt$/, diff --git a/rtl837x_common.h b/rtl837x_common.h index c3d83cb2..5547ca7e 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -133,6 +133,7 @@ void print_long(uint32_t a); void print_short(uint16_t a); void print_byte(uint8_t a); void itoa(uint8_t v); +void itoa_short(uint16_t v); void print_sfr_data(void); void print_phy_data(void); void print_cmd_prompt(void); diff --git a/rtlplayground.c b/rtlplayground.c index cd5e14eb..31695504 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -278,6 +278,32 @@ void itoa(uint8_t v) } +/* Same as itoa(), one decade wider: enough for a port number. Kept separate + * rather than widening itoa() itself, because every existing caller passes a + * byte and would start paying for 16-bit divisions it does not need. */ +void itoa_short(uint16_t v) +{ + uint8_t t = v / 10000; + uint8_t print_zeros = t; + + if (print_zeros) + write_char('0' + t); + t = (v / 1000) % 10; + print_zeros |= t; + if (print_zeros) + write_char('0' + t); + t = (v / 100) % 10; + print_zeros |= t; + if (print_zeros) + write_char('0' + t); + t = (v / 10) % 10; + print_zeros |= t; + if (print_zeros) + write_char('0' + t); + write_char('0' + (v % 10)); +} + + void print_string(__code char *p) { while (*p) diff --git a/syslog.c b/syslog.c index 81d722b2..7b3edca7 100644 --- a/syslog.c +++ b/syslog.c @@ -27,20 +27,22 @@ void syslog_init(void) __banked state.readptr = 0; state.line_available = 0; state.server_ip[0] = 0; state.server_ip[1] = 0; state.server_ip[2] = 0; state.server_ip[3] = 0;// Default to 0.0.0.0 + state.server_port = SYSLOG_PORT_DEFAULT; } void syslog_start(void) __banked { if (state.syslog_conn == 0) { uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]); - state.syslog_conn = uip_udp_new(&server_ip, HTONS(514)); + state.syslog_conn = uip_udp_new(&server_ip, HTONS(state.server_port)); if (state.syslog_conn == 0) { print_string_newline_no_syslog("Failed to create a new UDP client"); return; } print_string_newline_no_syslog("Started syslog to IP "); itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.'); - itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n'); + itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); + write_char(':'); itoa_short(state.server_port); write_char('\n'); state.enabled = 1; } else { diff --git a/syslog.h b/syslog.h index f3666da8..47bf968f 100644 --- a/syslog.h +++ b/syslog.h @@ -5,12 +5,15 @@ #define LOGBUF_SIZE 512 +#define SYSLOG_PORT_DEFAULT 514 + struct syslog_state { uint8_t enabled; uint8_t line_available; uint16_t writeptr ; uint16_t readptr; uint8_t server_ip[4]; + uint16_t server_port; struct uip_udp_conn *syslog_conn; };