1 Commits
Author SHA1 Message Date
logicog 85244d85f9 ChaCha20 implementation for encryption
Add an implementation in 8051 assembler for the generation of a
ChaCha20 keystream and an encryption function using the keystream
in C.

A test function using the example from RFC7539 is provided in
chacha20_test.

Keys, nonce, and block counter and the pointers to the input plaintext,
its length and the output pointer are provided via a struct chacha20,
which also holds the working state of the ChaCha20 algorithm
2026-04-26 10:30:55 +02:00
127 changed files with 1440 additions and 4849 deletions
-19
View File
@@ -1,19 +0,0 @@
.git/
.gitignore
.gitattributes
.github/
output/
installer/output/
*.bin
html_data.c
html_data.h
*.o
*.rel
*.lst
*.sym
*.asm
*.ihx
*.img
*.map
*.mem
*.lk
-19
View File
@@ -1,19 +0,0 @@
FROM debian:13-slim
RUN apt-get update && apt-get install -y \
make \
gcc \
sdcc \
xxd \
python3 \
libjson-c-dev \
golang-go \
git \
&& rm -rf /var/lib/apt/lists/*
# git safe.directory for mounted repos (Makefile uses git describe)
RUN git config --global --add safe.directory /workspace
WORKDIR /workspace
CMD ["bash"]
+35 -90
View File
@@ -4,98 +4,48 @@ DEFAULT_CONFIG_LOCATION = 454656
CONFIG_LOCATION = 458752 CONFIG_LOCATION = 458752
HTML_LOCATION = 262144 HTML_LOCATION = 262144
ifeq ($(origin CC),default)
CC = sdcc CC = sdcc
endif
CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip
ASM ?= sdas8051 ASM = sdas8051
AFLAGS= -plosgff AFLAGS= -plosgff
SUBDIRS := tools SUBDIRS := tools
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS)) SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
BUILDDIR = output
VERSION_HEADER := version.h
ifeq ($(MACHINE),) ifeq ($(MACHINE),)
MACHINE:= $(shell grep "^\s*#define MACHINE_" machine.h | sed "s/^\s*#define MACHINE_//")
else else
CC_FLAGS += -DMACHINE_$(MACHINE) CC_FLAGS += -DMACHINE_$(MACHINE)
endif endif
BUILDDIR = output/$(MACHINE) all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground.bin
VERSION_HEADER := version.h
GIT_VERSION := $(shell git rev-parse --short HEAD)
ifeq ($(shell git status --porcelain --untracked-files=no),)
else
GIT_VERSION := $(GIT_VERSION)-dirty
endif
VERSION_EXTENSION = v$(VERSION)-$(GIT_VERSION)
FILENAME_EXTENSION = $(VERSION_EXTENSION)-$(MACHINE)
# Deterministic build date: honor SOURCE_DATE_EPOCH, else the HEAD commit date,
# else wall-clock (no-git fallback). Keeps same-commit builds byte-identical
# (BUILD_DATE is baked into the image and covered by the trailing CRC).
SOURCE_DATE_EPOCH ?= $(shell git show -s --format=%ct HEAD 2>/dev/null)
ifeq ($(SOURCE_DATE_EPOCH),)
BUILD_DATE := $(shell date +"%Y-%m-%d %H:%M:%S")
else
BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/dev/null \
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
endif
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
create_build_dir: create_build_dir:
mkdir -p "$(BUILDDIR)" mkdir -p $(BUILDDIR)
mkdir -p "$(BUILDDIR)/uip" mkdir -p $(BUILDDIR)/uip
mkdir -p "$(BUILDDIR)/httpd" mkdir -p $(BUILDDIR)/httpd
mkdir -p $(BUILDDIR)/crypto
# Keep machine.c in first position to fail immediately on invalid $MACHINE value
SRCS = \
machine.c \
cmd_editor.c \
cmd_parser.c \
dhcp.c \
html_data.c \
rtlplayground.c \
syslog.c \
udp_apps.c
# RTL837x
SRCS += \
rtl837x_bandwidth.c \
rtl837x_flash.c \
rtl837x_igmp.c \
rtl837x_init.c \
rtl837x_leds.c \
rtl837x_phy.c \
rtl837x_pins.c\
rtl837x_port.c \
rtl837x_stp.c
SRCS += \
httpd/httpd.c \
httpd/page_impl.c
SRCS += \
uip/timer.c \
uip/uip.c \
uip/uiplib.c \
uip/uip_arp.c \
uip/uip-fw.c \
uip/uip-neighbor.c \
uip/uip-split.c
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c
SRCS += rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c cmd_editor.c rtl837x_bandwidth.c rtl837x_init.c
SRCS += uip/timer.c uip/uip.c uip/uip_arp.c uip/uiplib.c uip/uip-fw.c uip/uip-neighbor.c uip/uip-split.c
SRCS += httpd/httpd.c httpd/page_impl.c
SRCS += crypto/chacha20.c
OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel} OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel}
DEPS := ${SRCS:%.c=$(BUILDDIR)/%.d} DEPS := ${SRCS:%.c=$(BUILDDIR)/%.d}
HTML := $(shell find html -name '*.js' -or -name '*.html' -or -name '*.svg') HTML := $(shell find $(html) -name '*.js' -or -name '*.html' -or -name '*.svg')
html_data.c html_data.h &: $(HTML) | tools html_data.c html_data.h: $(HTML) tools/$(BUILDDIR)/fileadder
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
$(VERSION_HEADER): $(VERSION_HEADER):
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \ @echo "#ifndef VERSION_H" > $(VERSION_HEADER)
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \ @echo "#define VERSION_H" >> $(VERSION_HEADER)
"#define BUILD_DATE \"$(BUILD_DATE)\"" \ @echo "#define VERSION_SW \"v$(VERSION)-g$(shell git rev-parse --short HEAD)\"" >> $(VERSION_HEADER)
"#endif" > $(VERSION_HEADER) @echo "#define BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
@echo "#endif" >> $(VERSION_HEADER)
httpd: html_data.h httpd: html_data.h
@@ -103,36 +53,31 @@ $(SUBDIRS):
$(MAKE) -C $@ $(MAKE) -C $@
clean: clean:
-rm -f html_data.c html_data.h $(VERSION_HEADER)
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
distclean:
-rm -f html_data.c html_data.h $(VERSION_HEADER) -rm -f html_data.c html_data.h $(VERSION_HEADER)
-rm -rf $(BUILDDIR) -rm -rf $(BUILDDIR)
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h $(BUILDDIR)/%.rel: %.asm
${ASM} ${AFLAGS} -o $@ $<
$(BUILDDIR)/%.rel: %.c
$(CC) -MMD $(CC_FLAGS) -o $@ -c $< $(CC) -MMD $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)/%.rel: %.asm | create_build_dir $(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtstart.rel $(BUILDDIR)/crc16.rel $(BUILDDIR)/crypto/chacha_8051.rel
${ASM} ${AFLAGS} -o $@ $<
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^ $(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx $(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
objcopy --input-target=ihex -O binary $< $@ objcopy --input-target=ihex -O binary $< $@
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img | tools $(BUILDDIR)/rtlplayground.bin: $(BUILDDIR)/rtlplayground.img
if [ -e $@ ]; then rm $@; fi if [ -e $@ ]; then rm $@; fi
tools/output/imagebuilder -i $^ $@ tools/$(BUILDDIR)/imagebuilder -i $^ $@
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ tools/$(BUILDDIR)/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ tools/$(BUILDDIR)/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data -b BANK1 $@ tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data -b BANK1 $@
tools/output/crc_calculator -u $@ tools/$(BUILDDIR)/crc_calculator -u $@
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER) create_build_dir
.PHONY: clean all $(SUBDIRS) $(VERSION_HEADER)
.PHONY: .PHONY:
machine_check: machine_check:
+54 -180
View File
@@ -52,192 +52,88 @@ devices by looking at the image using e.g. Ghidra. If you want to contribute to
design of the web-interface or get a feeling for the interface first, a standalone design of the web-interface or get a feeling for the interface first, a standalone
device simulator is provided, which runs entirely under Linux as a local webserver. device simulator is provided, which runs entirely under Linux as a local webserver.
## (0) Compiling Requirements ## Compiling
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04 Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile: still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile:
``` ```
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev
``` ```
<details>
<summary>If using Docker (click to expand)</summary>
### Prerequisites
Install Docker for your platform:
- **Linux (Debian/Ubuntu)**: `sudo apt install docker.io` then `sudo usermod -aG docker $USER` (log out and back in)
- **Linux (other distros)**: Follow the [Docker Engine install guide](https://docs.docker.com/engine/install/)
- **Windows**: Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/)
- **macOS**: Install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/)
### Usage
A Dockerfile is provided for a reproducible build environment:
```
docker build -t rtlplayground-dev .
```
Build the firmware (replace MACHINE with your target, e.g. `DEFAULT_8C_1SFP`):
```
docker run --rm -v $(pwd):/workspace rtlplayground-dev make MACHINE=DEFAULT_8C_1SFP
```
The resulting `.bin` file appears in `output/` on your host.
Build host tools only:
```
docker run --rm -v $(pwd):/workspace rtlplayground-dev make -C tools
```
Run the web-interface simulator locally:
```
docker run --rm -p 8080:8080 -v $(pwd):/workspace rtlplayground-dev \
tools/output/httpd_sim /workspace/html
```
Edit `machine.h` or `config.txt` on your host, then re-run `make` — the
source directory is mounted into the container, so changes take effect
immediately. To build for a different machine, pass `MACHINE=...`.
</details>
## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for. Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
> [!TIP]
> You can write configuration parameters in config.txt (see below) in order your switch to get
> straight at the first boot, a correct IP configuration.
Now, building the firmware image should work: Now, building the firmware image should work:
``` ```
make make
``` ```
Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy. Note, that the image generated ends in .bin, not .img, in order to make
IMSProg happy.
image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin`
for example
```
rtlplayground-v0.1.0-12c98ba-dirty-LIANGUO_ZX_SWTGW215AS.bin
```
> [!CAUTION]
> This image can be flashed directly to the chip OR through the firmware update/upgrade
> interface of RTLPlaygound interface
## (2) Compiling for OEM running device with management options (web upgrade)
Managed switches can be updated from the existing original firmware using a SPECIFIC upgrade image.
You first need to build the firmware for direct chip flashing : See below (1)
Then
```
cd installer
make
```
image location is stored in `RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin`
> [!CAUTION]
> This image must ONLY be used for original OEM firmware web interface firmware upgrade.
> You do not need this image if you are already on RTLplayground firmware.
> Unless you go back to the original OEM firmware, you would only flash this specific firmware
> only once. Future upgrades of RTLPlayground will only need to follow (1)
example of compilation console output
Managed switches can be updated from the existing original firmware using an upgrade image.
In the `installer`folder of the source code you will need to run `make` which will build
an image out of `rtlplayground.bin` built in the previous step:
``` ```
RTLPlayground/installer$ make RTLPlayground/installer$ make
mkdir -p output mkdir -p output/
gcc updatebuilder.c -o output/updatebuilder gcc updatebuilder.c -o output/updatebuilder
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
./output/updatebuilder -i output/rtlinstaller.ihx -o output/rtlplayground_oem_upgrade.bin ../output/rtlplayground.bin cp ../output//rtlplayground.bin output/
./output//updatebuilder -i output/rtlinstaller.ihx output/rtlplayground.bin
Input file size: 524288 Input file size: 524288
Bytes read: 524288 Bytes read: 524288
EOF EOF
Payload sum 1 is: 0x25100 Payload sum 1 is: 0x29d10
Payload sum 2 is: 0x25100 Payload sum 2 is: 0x29d10
Payload sum with header is: 0x264ec Payload sum with header is: 0x2b0fc
Payload sum is: 0xf8fe94 Payload sum is: 0xad8a75
Header checksum is: 0x5a1 Header checksum is: 0x4c3
``` ```
The resulting image can be found in `RTLPlayground/installer/output/rtlplayground.bin`
> [!CAUTION]
> DO NOT UPLOAD THE UPGADE IMAGE UNLESS YOU CAN MAKE A BACKUP USING A SOIC CLAMP OF THE
> ORIGINAL FIRMWARE!
## (3) Sandbox Usage with Ghidra (optional) ## Installation
You can play with the image using ghidra or flash real Switch Hardware. For You can play with the image using ghidra or flash real Switch Hardware. For
ghidra see this information about [Ghidra images](ghidra.md). ghidra see this information about [Ghidra images](ghidra.md).
## (4) Installation through the Web interface (software way)
Managed switches (OEM firmware of RTLplaygroud firmware) can be upgraded via the web interface.
Unmanaged switch cannot be flashed this way (see 5).
Go to "Firmware update" tab, select the correct file.
> [!IMPORTANT]
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin
> [!CAUTION] > [!CAUTION]
> Check one more time that your device matches the machine type before flashing. > NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung. > ABSOLUTELY NO GUARANTY CAN BE GIVEN THAT YOU WILL NOT DESTROY YOUR SWITCH,
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
Finally, push the Upload File Button and you're done ! You can upload the upgrade image of managed switches via the web interface of the
original firmware just as if you were installing a firmware upgrade. However,
this is strongly discouraged, as you may brick your device, unless you can make
firmware backups via a SOIC clamp or soldered flash socket, first!
For unmanaged devices, the only way to install RTLPlayground is by flashing the
Flash memory directly.
## (5) Flashing the ROM directly (hardware way, but also only way to rescue) You will need to open your switch to flash the image directly onto the flash chip,
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
flash chip and install a SOIC adapter):
- Disconnect power from switch
- Attach the clip onto the flash chip
- Connect USB of flash programmer, the power LED on the switch will light
up, check cabling if not. Don't panic, mixing up GND and 3.3V does not
seem to destroy the switch (at leasts the on I did this to).
- Use IMSProg (flashrom should work, too) to detect the clip
- MAKE A BACKUP OF THE EXISTING FIRMWARE!
- then load the firmware into IMSProg
- and program flash
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough. Now you can connect a serial cable to the UART port found on all the
This is also the only way to unbrick your device if something went wroong. devices, set 8N1 @ 115200 baud and power up the switch.
> [!IMPORTANT] The device will perform some examples and provide a minimal console, the
> You need a SOIC-8 clip to flash the ROM chip directly onboard. documentation of which can be found in the source code rtlplayground.c`.
> Alternatively you can de-solder the flash chip and install a SOIC adapter).
> For flashing the chip directly, you must use the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
> [!CAUTION] ## The web-interface
> As you need to open your switch case, consider that the warranty is gone. The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247).
The default password is `1234`.
- Disconnect power from switch.
- Open the switch.
- Attach the clip onto the flash chip (Red line on Pin 1, Pin 1 has a point marker).
- Connect USB of flash programmer, the power LED on the switch will light up, check cabling if not.
- Don't panic, mixing up GND and 3.3V usually does not destroy the switch.
- Use IMSProg, Flashrom, or whatever Programmer to detect the chip.
- MAKE A BACKUP (DUMP) OF THE EXISTING FIRMWARE !
- ERASE THE ROM (BLANK) !
- Load the firmware into IMSProg.
- Flash is to the ROM chip.
- Disconect the clip from the ROM chip.
- You're done, ready for the first boot.
## (6) Connecting a serial interface (optional)
You can connect a serial cable to the UART port found on all the devices, set 8N1 @ 115200 baud.
## (7) Power Up
When you power up the switch, the device will perform some examples and provide a minimal console
(if wired to a serial interface), the documentation of which can be found in the source code rtlplayground.c`.
## (8) The web-interface
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
specified an IP adress in the config.txt before compilation.
> [!TIP]
> The default password is `1234`.
## (9) The command line
## The command line
The command line is very rudimentary and mostly for testing purposes. The command line is very rudimentary and mostly for testing purposes.
The following is a boot-log with some examples: The following is a boot-log with some examples:
``` ```
@@ -302,6 +198,7 @@ PORT 04 1G
<MODULE INSERTED> Rate: 67 Encoding: 01 <MODULE INSERTED> Rate: 67 Encoding: 01
Lightron Inc. WSPXG-ES3LC-IHA 0000 Lightron Inc. WSPXG-ES3LC-IHA 0000
> stat > stat
CMD: stat CMD: stat
Port State Link TxGood TxBad RxGood RxBad Port State Link TxGood TxBad RxGood RxBad
@@ -319,40 +216,17 @@ Lightron Inc. WSPXG-ES3LC-IHA 0000
CMD: sfp CMD: sfp
Rate: 67 Encoding: 01 Rate: 67 Encoding: 01
Lightron Inc. WSPXG-ES3LC-IHA 0000 Lightron Inc. WSPXG-ES3LC-IHA 0000
```
## (10) Advanced configuration
You can configure more deeply the switch without the need of the console mode.
While in compilation part, you might write directly to config.txt file before making the binary firmware
``` ```
nano config.txt
```
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
<img width="1085" height="646" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
```
ip xxx.xxx.xxx.xxx = IP adress of the switch
gw yyy.yyy.yyy.yyy = IP adress of the gateway
netmask zzz.zzz.zzz.zzz = Network mask of the switch
port x name xxx = Name xxx the port number x
port z 1g = Set 1g speed for port z
igmp on/off = Turn IGMP on or off
```
[To be continue]
Enjoy playing! Enjoy playing!
## (11) Other documents ## Other documents
The following documents give further documentation on specific features of
The following documents give further documentation on specific features of the RTL837x SoCs: the RTL837x SoCs:
- [RTL8372/3 Feature support](doc/hardware.md) - [RTL8372/3 Feature support](doc/hardware.md)
- [CPU Port](doc/CpuPort.md) - [CPU Port](doc/CpuPort.md)
- [L2 learning](doc/l2.md) - [L2 learning](doc/l2.md)
- [CPU Port](doc/CpuPort.md)
- [IGMP (IP-MC streaming)](doc/igmp.md) - [IGMP (IP-MC streaming)](doc/igmp.md)
- [SFP+ ports](doc/sfp.md) - [SFP+ ports](doc/sfp.md)
- [Trunking aka. port aggregation](doc/trunking.md) - [Trunking aka. port aggregation](doc/trunking.md)
+16 -19
View File
@@ -40,24 +40,21 @@ void cmd_edit(void) __banked
{ {
while (l != sbuf_ptr) { while (l != sbuf_ptr) {
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
// Reserve one byte for the terminating NUL written on Enter. When the if (cmd_line_len >= CMD_BUF_SIZE)
// line is full, drop the character but still fall through to advance the continue;
// serial-ring read pointer below; a 'continue' here would spin forever. write_char(sbuf[l]);
if (cmd_line_len < CMD_BUF_SIZE - 1) { // Shift buffer to right
write_char(sbuf[l]); for (uint8_t i = cmd_line_len; i > cursor; i--)
// Shift buffer to right cmd_buffer[i] = cmd_buffer[i-1];
for (uint8_t i = cmd_line_len; i > cursor; i--) // Insert char in comand buffer
cmd_buffer[i] = cmd_buffer[i-1]; cmd_buffer[cursor++] = sbuf[l];
// Insert char in comand buffer cmd_line_len++;
cmd_buffer[cursor++] = sbuf[l]; // Print rest of line
cmd_line_len++; for (uint8_t i = cursor; i < cmd_line_len; i++)
// Print rest of line write_char(cmd_buffer[i]);
for (uint8_t i = cursor; i < cmd_line_len; i++) // Move backwards
write_char(cmd_buffer[i]); for (uint8_t i = cursor; i < cmd_line_len; i++)
// Move backwards write_char('\010'); // BS works like cursor-left
for (uint8_t i = cursor; i < cmd_line_len; i++)
write_char('\010'); // BS works like cursor-left
}
} else if (sbuf[l] == '\033') { // ESC-Sequence } else if (sbuf[l] == '\033') { // ESC-Sequence
// Wait until we have at least 3 characters including the ESC character in the serial buffer // Wait until we have at least 3 characters including the ESC character in the serial buffer
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3) if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
@@ -200,7 +197,7 @@ void cmd_edit(void) __banked
if (cmd_line_len) if (cmd_line_len)
cmd_available = 1; cmd_available = 1;
else else
print_cmd_prompt(); print_string("\n> ");
cursor = 0; cursor = 0;
cmd_line_len = 0; cmd_line_len = 0;
history_editptr = 0xffff; history_editptr = 0xffff;
+43 -237
View File
@@ -15,7 +15,6 @@
#include "rtl837x_igmp.h" #include "rtl837x_igmp.h"
#include "rtl837x_bandwidth.h" #include "rtl837x_bandwidth.h"
#include "dhcp.h" #include "dhcp.h"
#include "syslog.h"
#include "uip/uip.h" #include "uip/uip.h"
#include "version.h" #include "version.h"
@@ -48,9 +47,6 @@ __xdata uint16_t vlan_ptr;
__xdata char port_names[9][PORT_NAME_SIZE]; __xdata char port_names[9][PORT_NAME_SIZE];
extern __xdata uint16_t management_vlan; extern __xdata uint16_t management_vlan;
extern __xdata uint8_t sfp_speed[2];
extern __xdata uint8_t sfp_pins_last;
extern __xdata uint8_t sfp_options[2];
__xdata uint8_t gpio_last_value[8] = { 0 }; __xdata uint8_t gpio_last_value[8] = { 0 };
// Temporatly for str to hex convertion value. // Temporatly for str to hex convertion value.
@@ -191,11 +187,8 @@ uint8_t atoi_byte(__xdata uint8_t *out, uint8_t idx)
uint8_t num = 0; uint8_t num = 0;
while (isnumber(cmd_buffer[idx])) { while (isnumber(cmd_buffer[idx])) {
uint8_t val = cmd_buffer[idx] - '0';
err = 0; err = 0;
if (num > 25 || (num == 25 && val > 5)) num = (num * 10) + cmd_buffer[idx] - '0';
return 1;
num = (num * 10) + val;
idx++; idx++;
} }
@@ -212,8 +205,6 @@ uint8_t atoi_short(__xdata uint16_t *vlan, uint8_t idx)
while (isnumber(cmd_buffer[idx])) { while (isnumber(cmd_buffer[idx])) {
err = 0; err = 0;
uint8_t val = cmd_buffer[idx] - '0'; uint8_t val = cmd_buffer[idx] - '0';
if (*vlan > 6553 || (*vlan == 6553 && val > 5))
return 1;
*vlan = (*vlan * 10) + val; *vlan = (*vlan * 10) + val;
idx++; idx++;
} }
@@ -250,7 +241,8 @@ void parse_lag(void)
print_string("LAG status:\n"); print_string("LAG status:\n");
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
write_char(' '); write_char('1' + i); write_char(' '); write_char('1' + i);
members = port_lag_members_get(i); reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (i << 2));
members = ((uint16_t)sfr_data[2]) << 8 | sfr_data[3];
if (!members) { if (!members) {
print_string(" disabled\n"); print_string(" disabled\n");
continue; continue;
@@ -273,9 +265,7 @@ void parse_lag(void)
if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]])) if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]]))
goto err; goto err;
group = cmd_buffer[cmd_words_b[1]] - '1'; group = cmd_buffer[cmd_words_b[1]] - '0';
if (group > 3) /* '0' wraps well past three, so one test does both ends */
goto err;
uint8_t w = 2; uint8_t w = 2;
while (w < cmd_words_len) { while (w < cmd_words_len) {
@@ -285,9 +275,7 @@ void parse_lag(void)
port = cmd_buffer[cmd_words_b[w]] - '1'; port = cmd_buffer[cmd_words_b[w]] - '1';
if (isnumber(cmd_buffer[cmd_words_b[w] + 1])) if (isnumber(cmd_buffer[cmd_words_b[w] + 1]))
port = (port + 1) * 10 + cmd_buffer[cmd_words_b[w] + 1] - '1'; port = (port + 1) * 10 + cmd_buffer[cmd_words_b[w] + 1] - '1';
if (port > 8) /* phys_to_log_port holds nine entries */ port = machine.phys_to_log_port[port];
goto err;
port = machine.phys_to_log_port[port];
} else { } else {
goto err; goto err;
} }
@@ -299,7 +287,7 @@ void parse_lag(void)
port_lag_members_set(group, members); port_lag_members_set(group, members);
return; return;
err: err:
print_string("Error: lag <1-4> [port]...\n"); print_string("Error: lag <lag> [port]...\n");
} }
@@ -308,11 +296,7 @@ void parse_lag_hash(void)
__xdata uint8_t group; __xdata uint8_t group;
__xdata uint8_t hash = 0; __xdata uint8_t hash = 0;
if (cmd_words_len < 2 || !isnumber(cmd_buffer[cmd_words_b[1]])) group = cmd_buffer[cmd_words_b[1]] - '0';
goto err;
group = cmd_buffer[cmd_words_b[1]] - '1';
if (group > 3) /* '0' wraps well past three, so one test does both ends */
goto err;
uint8_t w = 2; uint8_t w = 2;
while (w < cmd_words_len) { while (w < cmd_words_len) {
@@ -338,9 +322,6 @@ void parse_lag_hash(void)
w++; w++;
} }
port_lag_hash_set(group, hash); port_lag_hash_set(group, hash);
return;
err:
print_string("Error: lag hash <1-4> [type]...\n");
} }
@@ -349,16 +330,12 @@ void parse_vlan(void)
vlan_settings.vlan = 0; vlan_settings.vlan = 0;
vlan_settings.members = 0; vlan_settings.members = 0;
vlan_settings.tagged = 0; vlan_settings.tagged = 0;
if (cmd_words_len < 2)
goto err;
if (!atoi_short(&vlan_settings.vlan, cmd_words_b[1])) { if (!atoi_short(&vlan_settings.vlan, cmd_words_b[1])) {
if (cmd_words_len == 3 && cmd_buffer[cmd_words_b[2]] == 'd') { if (cmd_words_len == 3 && cmd_buffer[cmd_words_b[2]] == 'd') {
vlan_delete(vlan_settings.vlan); vlan_delete(vlan_settings.vlan);
return; return;
} }
if (cmd_compare(2, "mgmt")) { if (cmd_compare(2, "mgmt")) {
if (vlan_settings.vlan > 4094)
goto err;
management_vlan = vlan_settings.vlan; management_vlan = vlan_settings.vlan;
if (!vlan_settings.vlan) if (!vlan_settings.vlan)
print_string("Management VLAN disabled\n"); print_string("Management VLAN disabled\n");
@@ -366,16 +343,13 @@ void parse_vlan(void)
print_string("Management VLAN set to "); print_short(management_vlan); write_char('\n'); print_string("Management VLAN set to "); print_short(management_vlan); write_char('\n');
return; return;
} }
if (!vlan_settings.vlan || vlan_settings.vlan > 4094)
goto err;
uint8_t w = 2; uint8_t w = 2;
if (cmd_words_len > w && isletter(cmd_buffer[cmd_words_b[w]])) { if (cmd_words_len > w && isletter(cmd_buffer[cmd_words_b[w]])) {
register uint8_t i = 0; register uint8_t i = 0;
vlan_name_remove(vlan_settings.vlan);
vlan_names[vlan_ptr++] = hex[(vlan_settings.vlan >> 8) & 0xf]; vlan_names[vlan_ptr++] = hex[(vlan_settings.vlan >> 8) & 0xf];
vlan_names[vlan_ptr++] = hex[(vlan_settings.vlan >> 4) & 0xf] ; vlan_names[vlan_ptr++] = hex[(vlan_settings.vlan >> 4) & 0xf] ;
vlan_names[vlan_ptr++] = hex[vlan_settings.vlan & 0xf]; vlan_names[vlan_ptr++] = hex[vlan_settings.vlan & 0xf];
while(cmd_buffer[cmd_words_b[w] + i] != ' ' && cmd_buffer[cmd_words_b[w] + i] != '\0') { while(cmd_buffer[cmd_words_b[w] + i] != ' ') {
write_char(cmd_buffer[cmd_words_b[w] + i]); write_char(cmd_buffer[cmd_words_b[w] + i]);
vlan_names[vlan_ptr++] = cmd_buffer[cmd_words_b[w] + i++]; vlan_names[vlan_ptr++] = cmd_buffer[cmd_words_b[w] + i++];
} }
@@ -428,11 +402,11 @@ void parse_isolate(void)
print_string("\nISOLATE "); print_string("\nISOLATE ");
if (!isnumber(cmd_buffer[cmd_words_b[1]]) || cmd_buffer[cmd_words_b[1]] == '0' __xdata int8_t port_configured = cmd_buffer[cmd_words_b[1]] - '1';
|| isnumber(cmd_buffer[cmd_words_b[1] + 1])) port_configured = machine.phys_to_log_port[port_configured];
goto err; if (isnumber(cmd_buffer[cmd_words_b[1] + 1])) // CPU-port, logical port 9
__xdata uint8_t port_configured = machine.phys_to_log_port[cmd_buffer[cmd_words_b[1]] - '1']; port_configured = (port_configured + 1) * 10 + cmd_buffer[cmd_words_b[1] + 1] - '1';
if (port_configured < machine.min_port || port_configured > machine.max_port) if (port_configured < 0 || port_configured > 9)
goto err; goto err;
print_byte(port_configured); write_char('\n'); print_byte(port_configured); write_char('\n');
@@ -529,7 +503,7 @@ void parse_ingress(void)
if (!isnumber(p)) { if (!isnumber(p)) {
continue; continue;
} }
if (p < '1') { if (p - '1' > 9) {
print_string("Invalid physical port number: "); write_char(p); write_char('\n'); print_string("Invalid physical port number: "); write_char(p); write_char('\n');
continue; continue;
} }
@@ -687,14 +661,6 @@ void parse_port(void)
else if (cmd_compare(3, "full")) else if (cmd_compare(3, "full"))
phy_settings.duplex = PHY_DUPLEX_FULL; phy_settings.duplex = PHY_DUPLEX_FULL;
phy_set_speed(); phy_set_speed();
} else if (cmd_compare(2, "10g")) {
print_string(" 10G\n");
phy_settings.speed = PHY_SPEED_10G;
phy_set_speed();
} else if (cmd_compare(2, "5g")) {
print_string(" 5G\n");
phy_settings.speed = PHY_SPEED_5G;
phy_set_speed();
} else if (cmd_compare(2, "2g5")) { } else if (cmd_compare(2, "2g5")) {
print_string(" 2.5G\n"); print_string(" 2.5G\n");
phy_settings.speed = PHY_SPEED_2G5; phy_settings.speed = PHY_SPEED_2G5;
@@ -718,9 +684,9 @@ void parse_port(void)
} else if (cmd_compare(2, "duplex")) { } else if (cmd_compare(2, "duplex")) {
print_string(" DUPLEX\n"); print_string(" DUPLEX\n");
if (cmd_compare(3, "full")) if (cmd_compare(3, "full"))
phy_settings.duplex = PHY_DUPLEX_FULL; phy_settings.speed = PHY_DUPLEX_FULL;
else else
phy_settings.duplex = PHY_DUPLEX_HALF; phy_settings.speed = PHY_DUPLEX_HALF;
phy_set_duplex(); phy_set_duplex();
} else { } else {
print_string("Unknown port command\n"); print_string("Unknown port command\n");
@@ -740,18 +706,17 @@ void parse_mtu(void)
print_string("Port "); print_byte(machine.log_to_phys_port[p]); print_string("Port "); print_byte(machine.log_to_phys_port[p]);
write_char(' '); print_short(mtu); write_char('\n'); write_char(' '); print_short(mtu); write_char('\n');
} }
return;
} }
if (cmd_words_len != 3 || cmd_buffer[cmd_words_b[1]] < '1' p = cmd_buffer[cmd_words_b[1]] - '1';
|| cmd_buffer[cmd_words_b[1]] > '9' p = machine.phys_to_log_port[p];
|| cmd_buffer[cmd_words_b[1] + 1] > ' ') { print_byte(p);
if (cmd_words_len != 3) {
print_string("mtu [port] [size]\n"); print_string("mtu [port] [size]\n");
return; return;
} }
p = machine.phys_to_log_port[cmd_buffer[cmd_words_b[1]] - '1']; atoi_short(&mtu, cmd_words_b[2]);
print_byte(p); if (mtu > 0x3fff) {
if (atoi_short(&mtu, cmd_words_b[2]) || mtu < 64 || mtu > 0x3fff) { print_string("Maximum MTU is 16383\n");
print_string("MTU must be 64..16383\n");
return; return;
} }
REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (mtu >> 10) & 0xf, (mtu >> 2) & 0xff, REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (mtu >> 10) & 0xf, (mtu >> 2) & 0xff,
@@ -762,7 +727,7 @@ void parse_mtu(void)
void sfp_print_measurements(uint8_t sfp) void sfp_print_measurements(uint8_t sfp)
{ {
print_string("Options: "); print_byte(sfp_read_reg(sfp, 92)); write_char('\n'); print_string("Options: "); print_byte(sfp_read_reg(sfp, 92)); write_char('\n');
if (!(sfp_options[sfp] & 0x40)) if (!(sfp_read_reg(sfp, 92) & 0x40))
return; return;
print_string("Temp: "); print_byte(sfp_read_reg(sfp, 224)); print_byte(sfp_read_reg(sfp, 225)); write_char('\n'); print_string("Temp: "); print_byte(sfp_read_reg(sfp, 224)); print_byte(sfp_read_reg(sfp, 225)); write_char('\n');
print_string("Vcc: "); print_byte(sfp_read_reg(sfp, 226)); print_byte(sfp_read_reg(sfp, 227)); write_char('\n'); print_string("Vcc: "); print_byte(sfp_read_reg(sfp, 226)); print_byte(sfp_read_reg(sfp, 227)); write_char('\n');
@@ -774,64 +739,6 @@ void sfp_print_measurements(uint8_t sfp)
} }
void parse_sfp(void)
{
uint8_t slot;
if (cmd_words_len != 1 && cmd_words_len != 3)
goto err;
if (cmd_words_len == 1) {
for (slot = 0; slot < machine.n_sfp; slot++) {
print_string("\nSlot "); write_char('1' + slot);
if (gpio_pin_test(machine.sfp_port[slot].pin_detect)) {
print_string(" - empty\n");
continue;
}
print_string(" - Rate: "); print_byte(sfp_read_reg(slot, 12));
print_string(" Encoding: "); print_byte(sfp_read_reg(slot, 11));
write_char('\n');
sfp_print_info(slot);
sfp_print_measurements(slot);
}
return;
}
if (cmd_buffer[cmd_words_b[1]] < '1' || cmd_buffer[cmd_words_b[1]] > '2' || cmd_buffer[cmd_words_b[1] + 1] != ' ' ) {
print_string("Illegal SFP slot number\n");
return;
}
slot = cmd_buffer[cmd_words_b[1]] - '1';
if (slot >= machine.n_sfp) {
print_string("SFP slot not present\n");
return;
}
if (cmd_compare(2, "10g")) {
print_string(" 10G\n");
sfp_speed[slot] = SFP_SPEED_10G;
} else if (cmd_compare(2, "2g5")) {
print_string(" 2.5G\n");
sfp_speed[slot] = SFP_SPEED_2G5;
} else if (cmd_compare(2, "1g")) {
print_string(" 1G\n");
sfp_speed[slot] = SFP_SPEED_1G;
} else if (cmd_compare(2, "100m")) {
print_string(" 100M\n");
sfp_speed[slot] = SFP_SPEED_100M;
} else if (cmd_compare(2, "auto")) {
print_string(" AUTO\n");
sfp_speed[slot] = SFP_SPEED_AUTO;
} else {
goto err;
}
sfp_pins_last |= 0x1 << (slot << 2);
handle_sfp();
return;
err:
print_string("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
}
void parse_regget(void) void parse_regget(void)
{ {
uint16_t reg = 0; uint16_t reg = 0;
@@ -871,7 +778,7 @@ void parse_regset(void)
{ {
uint16_t reg = 0; uint16_t reg = 0;
if (cmd_words_len != 3) { if (cmd_words_len != 2) {
goto err; goto err;
} }
@@ -1155,9 +1062,6 @@ void parse_eee(void)
__xdata int8_t port = -1; __xdata int8_t port = -1;
__xdata uint8_t speed = EEE_2G5; __xdata uint8_t speed = EEE_2G5;
__xdata uint8_t speed_word = 0; __xdata uint8_t speed_word = 0;
if (machine.n_10g)
speed = EEE_10G;
// Check if word 2 is a speed (contains 'g' or 'm') or a port number // Check if word 2 is a speed (contains 'g' or 'm') or a port number
if (cmd_words_len >= 3) { if (cmd_words_len >= 3) {
uint8_t idx = cmd_words_b[2]; uint8_t idx = cmd_words_b[2];
@@ -1284,52 +1188,6 @@ err:
print_string("usage: bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n"); print_string("usage: bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
} }
void parse_syslog(void)
{
if (cmd_words_len < 2) // no argument -> print status
{
print_string("Current syslog status: ");
if (syslog_state.enabled) {
print_string("enabled, sending to ");
itoa(syslog_state.server_ip[0]); write_char('.'); itoa(syslog_state.server_ip[1]); write_char('.');
itoa(syslog_state.server_ip[2]); write_char('.'); itoa(syslog_state.server_ip[3]);
write_char('\n');
} else {
print_string("disabled\n");
}
return;
}
if (cmd_compare(1, "on")) {
syslog_start();
} else if (cmd_compare(1, "off")){
syslog_stop();
} else if (cmd_compare(1, "ip")) {
if (cmd_words_len < 3) { // no additional arguemnt -> print current ip
print_string("Current syslog IP: ");
itoa(syslog_state.server_ip[0]); write_char('.'); itoa(syslog_state.server_ip[1]); write_char('.');
itoa(syslog_state.server_ip[2]); write_char('.'); itoa(syslog_state.server_ip[3]);
return;
} else if (!parse_ip(cmd_words_b[2])) {
uint8_t was_enabled = syslog_state.enabled;
if (was_enabled)
syslog_stop();
print_string("Setting new syslog IP.\n");
syslog_state.server_ip[0] = ip[0]; syslog_state.server_ip[1] = ip[1];
syslog_state.server_ip[2] = ip[2]; syslog_state.server_ip[3] = ip[3];
if (was_enabled)
syslog_start();
} else {
print_string("Invalid IP address\n");
}
}
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");
}
}
// Parse command into words // Parse command into words
// cmd_words_len contains the number of words found. // cmd_words_len contains the number of words found.
// cmd_words_b[] contains only start of a word offset. // cmd_words_b[] contains only start of a word offset.
@@ -1439,7 +1297,18 @@ void cmd_parser(void) __banked
print_string("\nRESET\n\n"); print_string("\nRESET\n\n");
reset_chip(); reset_chip();
} else if (cmd_compare(0, "sfp")) { } else if (cmd_compare(0, "sfp")) {
parse_sfp(); print_string("\nSlot 1 - Rate: "); print_byte(sfp_read_reg(0, 12));
print_string(" Encoding: "); print_byte(sfp_read_reg(0, 11));
print_string("\n");
sfp_print_info(0);
sfp_print_measurements(0);
if (machine.n_sfp == 2) {
print_string("\nSlot 2 - Rate: "); print_byte(sfp_read_reg(1, 12));
print_string(" Encoding: "); print_byte(sfp_read_reg(1, 11));
print_string("\n");
sfp_print_info(1);
sfp_print_measurements(1);
}
} else if (cmd_compare(0, "stat")) { } else if (cmd_compare(0, "stat")) {
port_stats_print(); port_stats_print();
} else if (cmd_compare(0, "flash") && cmd_words_len == 2) { } else if (cmd_compare(0, "flash") && cmd_words_len == 2) {
@@ -1470,8 +1339,6 @@ void cmd_parser(void) __banked
parse_port(); parse_port();
} else if (cmd_compare(0, "mtu")) { } else if (cmd_compare(0, "mtu")) {
parse_mtu(); parse_mtu();
} else if (cmd_compare(0, "syslog")) {
parse_syslog();
} else if (cmd_compare(0, "ip")) { } else if (cmd_compare(0, "ip")) {
if (cmd_compare(1, "dhcp")) { if (cmd_compare(1, "dhcp")) {
dhcp_start(); dhcp_start();
@@ -1540,35 +1407,10 @@ void cmd_parser(void) __banked
} else if (cmd_compare(0, "igmp")) { } else if (cmd_compare(0, "igmp")) {
if (cmd_compare(1, "on")) if (cmd_compare(1, "on"))
igmp_enable(); igmp_enable();
else if (cmd_compare(1, "off"))
igmp_setup();
else if (cmd_compare(1, "show")) else if (cmd_compare(1, "show"))
igmp_show(); igmp_show();
else else
print_string("Error: igmp on|off|show\n"); igmp_setup(); // Reverts to default with IP-MC being flooded
} else if (cmd_compare(0, "hostname")) {
/* "hostname" alone reports the current name; "hostname <text>"
* sets it, sanitized to JSON-safe printable ASCII. A name with
* spaces would tokenize into several words - reject it instead
* of silently keeping the first one. */
if (cmd_words_len == 1) {
print_string_x(hostname);
write_char('\n');
} else if (cmd_words_len == 2) {
__xdata uint8_t *hp = &cmd_buffer[cmd_words_b[1]];
__xdata char *dst = hostname;
for (uint8_t hn = 0; hn < sizeof(hostname) - 1; hn++) {
uint8_t c = *hp++;
if (c == '\0' || c == '\r' || c == '\n')
break;
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
c = '.';
*dst++ = c;
}
*dst = '\0';
} else {
print_string("Error: hostname [name] - the name must not contain spaces\n");
}
} else if (cmd_compare(0, "stp")) { } else if (cmd_compare(0, "stp")) {
if (cmd_compare(1, "on")) { if (cmd_compare(1, "on")) {
print_string("STP enabled\n"); print_string("STP enabled\n");
@@ -1581,13 +1423,11 @@ void cmd_parser(void) __banked
} }
} else if (cmd_compare(0, "pvid") && cmd_words_len == 3) { } else if (cmd_compare(0, "pvid") && cmd_words_len == 3) {
__xdata uint16_t pvid; __xdata uint16_t pvid;
if (cmd_buffer[cmd_words_b[1]] >= '1' uint8_t port;
&& cmd_buffer[cmd_words_b[1]] <= '9' port = cmd_buffer[cmd_words_b[1]] - '1';
&& cmd_buffer[cmd_words_b[1] + 1] <= ' ' port = machine.phys_to_log_port[port];
&& !atoi_short(&pvid, cmd_words_b[2]) && pvid && pvid <= 4094) if (!atoi_short(&pvid, cmd_words_b[2]))
port_pvid_set(machine.phys_to_log_port[cmd_buffer[cmd_words_b[1]] - '1'], pvid); port_pvid_set(port, pvid);
else
print_string("Error: pvid <port> <1-4094>\n");
} else if (cmd_compare(0, "vlan")) { } else if (cmd_compare(0, "vlan")) {
parse_vlan(); parse_vlan();
} else if (cmd_compare(0, "isolate")) { } else if (cmd_compare(0, "isolate")) {
@@ -1739,37 +1579,3 @@ config_done:
clear_command_history(); clear_command_history();
save_cmd = 1; save_cmd = 1;
} }
// Execute multiple commands
// If a command is too long or can't be tokenized, remaining commands are not executed
// Returns the status via `err_status`-variable.
void execute_commands(__xdata uint8_t *p) __banked {
err_status = ERR_OK;
uint8_t cmd_idx = 0;
while (1) {
if (*p == 0 || *p == '\n' || *p == '\r') {
if (cmd_idx) {
cmd_buffer[cmd_idx] = '\0';
cmd_tokenize();
if (err_status != ERR_OK)
return;
cmd_parser();
}
if (*p == 0)
return;
cmd_idx = 0;
} else {
if (cmd_idx < (CMD_BUF_SIZE - 1)) {
cmd_buffer[cmd_idx++] = *p;
} else {
cmd_buffer[CMD_BUF_SIZE - 1] = '\0';
print_string("ERROR: Command too long: ");
print_string_x(cmd_buffer);
write_char('\n');
err_status = ERR_CMD_TOO_LONG;
return;
}
}
p++;
};
}
-3
View File
@@ -7,13 +7,10 @@
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE]; extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
extern __xdata uint8_t cmd_available; extern __xdata uint8_t cmd_available;
extern __xdata uint8_t err_status;
void cmd_tokenize(void) __banked; void cmd_tokenize(void) __banked;
void cmd_parser(void) __banked; void cmd_parser(void) __banked;
void execute_config(void) __banked; void execute_config(void) __banked;
void execute_commands(__xdata uint8_t *p) __banked;
void print_sw_version(void) __banked; void print_sw_version(void) __banked;
void clear_command_history(void) __banked; void clear_command_history(void) __banked;
#endif #endif
-29
View File
@@ -1,29 +0,0 @@
.area HOME (CODE)
.area GSINIT0 (CODE)
.area GSINIT1 (CODE)
.area GSINIT2 (CODE)
.area GSINIT3 (CODE)
.area GSINIT4 (CODE)
.area GSINIT5 (CODE)
.area GSINIT (CODE)
.area GSFINAL (CODE)
.area CSEG (CODE)
.area HOME (CODE)
__sdcc_banked_call::
push _PSBANK
xch a,r0
push a
mov a,r1
push a
mov a,r2
anl a,#0x1f
mov _PSBANK, a
xch a, r0
ret
__sdcc_banked_ret::
pop _PSBANK
ret
+17
View File
@@ -0,0 +1,17 @@
.area GSFINAL (CODE)
__sdcc_banked_call::
push _PSBANK
xch a,r0
push a
mov a,r1
push a
mov a,r2
anl a,#0x1f
mov _PSBANK, a
xch a, r0
ret
__sdcc_banked_ret::
pop _PSBANK
ret
+23
View File
@@ -0,0 +1,23 @@
#ifndef _CHACHA_H_
#define _CHACHA_H_
#include <stdint.h>
struct chacha20_t {
uint8_t wstate[64]; // 64 bytes written here
uint8_t constant[16]; // 128 bit constant
uint8_t key[32]; // 256-bit secret key
uint32_t cnt; // 32-bit block counter 1, 2.. Big Endian!
uint8_t nonce[12]; // 96-bit nonce
__xdata uint8_t *plaintext;
uint16_t length;
__xdata uint8_t *cyphertext;
};
// Encrypt a plaintext with ChaCha20 as per RFC7539
void chacha20_encrypt(void);
// Test ChaCha20 using the example from RFC7539
void chacha20_test(void);
#endif
+98
View File
@@ -0,0 +1,98 @@
#include "rtl837x_common.h"
#include "chacha.h"
void chacha_20(void);
void chacha_update(void);
void chacha_count(void);
// generate a block of ChaCha20 keystream as per RFC7539
__xdata struct chacha20_t __at(0x7000) chacha20;
__xdata uint8_t plaintext[256];
__xdata uint8_t cyphertext[256];
void chacha20_print_block(void)
{
for (uint8_t i=0; i < 64; i++) {
print_byte(*(uint8_t * __xdata)(chacha20.wstate + i));
if (i%4 == 3)
write_char(' ');
}
}
void chacha20_encrypt(void)
{
__xdata uint8_t *p = chacha20.plaintext;
while (chacha20.length) {
register uint8_t i;
chacha_count();
memcpy(chacha20.wstate, chacha20.wstate + 64, 64);
#ifdef DEBUG
chacha20_print_block(); write_char('\n');
#endif
chacha_20();
chacha_update();
#ifdef DEBUG
chacha20_print_block(); write_char('\n');
#endif
for (i = 0; i < ((chacha20.length > 64) ? 64 : chacha20.length); i++)
*chacha20.cyphertext++ = *p++ ^ chacha20.wstate[i];
chacha20.length -= chacha20.length > 64 ? 64 : chacha20.length;
#ifdef DEBUG
print_string("\n round done\n");
#endif
};
}
// Test the example of RFC 7539 Section 2.4.2
void chacha20_test(void)
{
__code uint8_t chacha_c[16] =
{ 0x61, 0x70, 0x78, 0x65, 0x33, 0x20, 0x64, 0x6e,
0x79, 0x62, 0x2d, 0x32, 0x6b, 0x20, 0x65, 0x74 };
__code uint8_t key[32] =
{ 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04,
0x0b, 0x0a, 0x09, 0x08, 0x0f, 0x0e, 0x0d, 0x0c,
0x13, 0x12, 0x11, 0x10, 0x17, 0x16, 0x15, 0x14,
0x1b, 0x1a, 0x19, 0x18, 0x1f, 0x1e, 0x1d, 0x1c };
__code uint8_t nonce[12] = {
0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
__code uint8_t sunscreen[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for " \
"the future, sunscreen would be it.";
/*
Ciphertext Sunscreen (from RFC 7539 Section 2.4.2):
000 6e 2e 35 9a 25 68 f9 80 41 ba 07 28 dd 0d 69 81 n.5.%h..A..(..i.
016 e9 7e 7a ec 1d 43 60 c2 0a 27 af cc fd 9f ae 0b .~z..C`..'......
032 f9 1b 65 c5 52 47 33 ab 8f 59 3d ab cd 62 b3 57 ..e.RG3..Y=..b.W
048 16 39 d6 24 e6 51 52 ab 8f 53 0c 35 9f 08 61 d8 .9.$.QR..S.5..a.
064 07 ca 0d bf 50 0d 6a 61 56 a3 8e 08 8a 22 b6 5e ....P.jaV....".^
080 52 bc 51 4d 16 cc f8 06 81 8c e9 1a b7 79 37 36 R.QM.........y76
096 5a f9 0b bf 74 a3 5b e6 b4 0b 8e ed f2 78 5e 42 Z...t.[......x^B
112 87 4d
*/
strcpy(plaintext, sunscreen);
memcpyc(chacha20.constant, chacha_c, 16);
memcpyc(chacha20.key, key, 32);
chacha20.cnt = 0;
memcpyc(chacha20.nonce, nonce, 12);
chacha20.plaintext = plaintext;
chacha20.length = strlen_x(plaintext);
chacha20.cyphertext = cyphertext;
print_string("Encrypting...\n");
chacha20_encrypt();
print_string("Cypertext:\n");
uint16_t len = strlen_x(plaintext);
for (uint8_t i = 0; i < len; i++) {
print_byte(cyphertext[i]); write_char(' ');
}
}
+489
View File
@@ -0,0 +1,489 @@
; ChaCha Quater-Round implementation in Assembler
.module chacha_8051
; Global variables:
.globl _chacha_20
.globl _chacha_test_1
.globl _chacha_qr_r
.globl _chacha_update
.globl _chacha_count
;#define CHACHA_QR(A, B, C, D) { \
; A += B; D ^= A; D = ROTL32(D, 16); \
; C += D; B ^= C; B = ROTL32(B, 12); \
; A += B; D ^= A; D = ROTL32(D, 8); \
; C += D; B ^= C; B = ROTL32(B, 7); \
;}
; r0 r1 r2 r3
; CHACHA_QR( v[ 0], v[ 4], v[ 8], v[12] );
.area HOME (CODE)
store_32:
ar7 = 0x07
ar6 = 0x06
ar5 = 0x05
ar4 = 0x04
ar3 = 0x03
ar2 = 0x02
ar1 = 0x01
ar0 = 0x00
mov a, r7
movx @dptr, a
dec dpl
mov a, r6
movx @dptr, a
dec dpl
mov a, r5
movx @dptr, a
dec dpl
mov a, r4
movx @dptr, a
ret
rol_b:
clr c
mov a, r7
rlc a
mov r7, a
mov a, r6
rlc a
mov r6, a
mov a, r5
rlc a
mov r5, a
mov a, r4
rlc a
mov r4, a
clr a
addc a, r7
mov r7, a
djnz dpl, rol_b
ret
print_regs:
push a
push ar6
push ar7
push dpl
mov dpl, a
lcall _print_byte
pop dpl
pop ar7
pop ar6
pop a
chacha_plus_xor:
; Load A into registers r4-r7, A pointed to by r0
mov dptr, #_chacha20
mov dpl, r0
movx a, @dptr
mov r7, a
dec dpl
movx a, @dptr
mov r6, a
dec dpl
movx a, @dptr
mov r5, a
dec dpl
movx a, @dptr
mov r4, a
; A += B, B pointed to by r1
mov dpl, r1
movx a, @dptr
add a, r7
mov r7, a
dec dpl
movx a, @dptr
addc a, r6
mov r6, a
dec dpl
movx a, @dptr
addc a, r5
mov r5, a
dec dpl
movx a, @dptr
addc a, r4
mov r4, a
mov dpl, r0 ; Store A back
mov a, r7
movx @dptr, a
dec dpl
mov a, r6
movx @dptr, a
dec dpl
mov a, r5
movx @dptr, a
dec dpl
mov a, r4
movx @dptr, a
; D ^= A
mov dpl, r3
movx a, @dptr
xrl a, r7
mov r7, a
dec dpl
movx a, @dptr
xrl a, r6
mov r6, a
dec dpl
movx a, @dptr
xrl a, r5
mov r5, a
dec dpl
movx a, @dptr
xrl a, r4
mov r4, a
dec dpl
ret
chacha_qr:
; QR Part: A += B; D ^= A; D = ROTL32(D, 16);
acall chacha_plus_xor
; rotate left 16. D is r4, r5, r6, r7 -> r6, r7, r4, r5
mov a, r6
xch a, r4
mov r6, a
mov a, r7
xch a, r5
mov r7, a
mov dpl, r3 ; Store D
acall store_32
;QR Part: C += D; B ^= C; B = ROTL32(B, 12);
; Swap A <-> C and D <-> B
mov a, r0
xch a, r2
mov r0, a
mov a, r1
xch a, r3
mov r1, a
acall chacha_plus_xor
; rotate left 12. D is r4, r5, r6, r7 -> r5, r6, r7, r4
mov a, r4
xch a, r7
xch a, r6
xch a, r5
mov r4, a
mov dpl, #4
acall rol_b
mov dpl, r3 ; Store D (being B)
acall store_32
; Swap A <-> C and D <-> B
mov a, r0
xch a, r2
mov r0, a
mov a, r1
xch a, r3
mov r1, a
mov dpl, r1 ; Store B
acall store_32
; QR Part A += B; D ^= A; D = ROTL32(D, 8);
acall chacha_plus_xor
mov a, r4
xch a, r7
xch a, r6
xch a, r5
mov r4, a
mov dpl, r3 ; Store D
acall store_32
; QR Part
; C += D; B ^= C; B = ROTL32(B, 7);
line4:
; Swap A <-> C and D <-> B
mov a, r0
xch a, r2
mov r0, a
mov a, r1
xch a, r3
mov r1, a
acall chacha_plus_xor
; Roll left 7 bits, start by rolling 8 bits left, then roll 1 to the right
mov a, r4
xch a, r7
xch a, r6
xch a, r5
mov r4, a
clr c
mov a, r4
rrc a
mov r4, a
mov a, r5
rrc a
mov r5, a
mov a, r6
rrc a
mov r6, a
mov a, r7
rrc a
mov r7, a
clr a
rrc a
add a, r4
mov r4, a
; Swap A <-> C and D <-> B
mov a, r0
xch a, r2
mov r0, a
mov a, r1
xch a, r3
mov r1, a
mov dpl, r1 ; Store B
acall store_32
ret
_chacha_test_1:
mov r0, #3
mov r1, #7
mov r2, #11
mov r3, #15
acall line4
ret
; QUARTERROUND(2,7,8,13)
_chacha_qr_r:
mov r0, #11
mov r1, #31
mov r2, #35
mov r3, #55
acall chacha_qr
ret
;
; Implementation of 20 ChaCha Rounds (10 Double Rounds)
;
_chacha_20:
push acc
push b
push dpl
push dph
push ar7
push ar6
push ar5
push ar4
push ar3
push ar2
push ar1
push ar0
push psw
mov b, #10 ; 10 Double rounds
chacha_20_loop:
; CHACHA_QR( v[ 0], v[ 4], v[ 8], v[12] );
mov r0, #3
mov r1, #19
mov r2, #35
mov r3, #51
acall chacha_qr
; CHACHA_QR( v[ 1], v[ 5], v[ 9], v[13] ); 7 23 39 55
mov r0, #7
mov r1, #23
mov r2, #39
mov r3, #55
acall chacha_qr
; CHACHA_QR( v[ 2], v[ 6], v[10], v[14] ); 11 27 43 59
mov r0, #11
mov r1, #27
mov r2, #43
mov r3, #59
acall chacha_qr
; CHACHA_QR( v[ 3], v[ 7], v[11], v[15] ); 15 31 47 63
mov r0, #15
mov r1, #31
mov r2, #47
mov r3, #63
acall chacha_qr
; CHACHA_QR( v[ 0], v[ 5], v[10], v[15] ); 3 23 43 63
mov r0, #3
mov r1, #23
mov r2, #43
mov r3, #63
acall chacha_qr
; CHACHA_QR( v[ 1], v[ 6], v[11], v[12] ); 7 27 47 51
mov r0, #7
mov r1, #27
mov r2, #47
mov r3, #51
acall chacha_qr
; CHACHA_QR( v[ 2], v[ 7], v[ 8], v[13] ); 11 31 35 55
mov r0, #11
mov r1, #31
mov r2, #35
mov r3, #55
acall chacha_qr
; CHACHA_QR( v[ 3], v[ 4], v[ 9], v[14] ); 15 19 39 59
mov r0, #15
mov r1, #19
mov r2, #39
mov r3, #59
acall chacha_qr
djnz b, chacha_20_loop
pop psw
pop ar0
pop ar1
pop ar2
pop ar3
pop ar4
pop ar5
pop ar6
pop ar7
pop dph
pop dpl
pop b
pop acc
ret
;
; Update ChaCHa state
;
_chacha_update:
push acc
push b
push dpl
push dph
push ar4
push ar3
push ar2
push ar1
push ar0
push psw
mov dptr, #_chacha20
mov b, #16 ; 16 uint32
update_loop:
mov a, b ; multiply by 4 and subtract 1
rl a
rl a
dec a
; Load Working State variable into registers r0-r3
mov dpl, a
orl a, #64 ; Save pointer to state
mov r4, a
movx a, @dptr
mov r3, a
dec dpl
movx a, @dptr
mov r2, a
dec dpl
movx a, @dptr
mov r1, a
dec dpl
movx a, @dptr
mov r0, a
; Add to State variable
mov a, r4
mov dpl, a
movx a, @dptr
add a, r3
mov r3, a
dec dpl
movx a, @dptr
addc a, r2
mov r2, a
dec dpl
movx a, @dptr
addc a, r1
mov r1, a
dec dpl
movx a, @dptr
addc a, r0
mov r0, a
; Store back state variable in LSB, first sequence (serialized)
mov a, r4
xrl a, #64 ; Save pointer to working state
mov dpl, a
mov a, r0
movx @dptr, a
dec dpl
mov a, r1
movx @dptr, a
dec dpl
mov a, r2
movx @dptr, a
dec dpl
mov a, r3
movx @dptr, a
djnz b, update_loop
pop psw
pop ar0
pop ar1
pop ar2
pop ar3
pop ar4
pop dph
pop dpl
pop b
pop acc
ret
;
; Increase counter in state
;
_chacha_count:
push acc
push dpl
push dph
mov dptr, #_chacha20
mov dpl, #112 + 3
movx a, @dptr
inc a
movx @dptr, a
jnc chacha_count_done
dec dpl
movx a, @dptr
inc a
movx @dptr, a
jnc chacha_count_done
dec dpl
movx a, @dptr
inc a
movx @dptr, a
jnc chacha_count_done
dec dpl
movx a, @dptr
inc a
movx @dptr, a
chacha_count_done:
pop dph
pop dpl
pop acc
ret
+1 -20
View File
@@ -41,7 +41,6 @@ __xdata uip_ipaddr_t server;
#define DHCP_REBIND_LEN 4 #define DHCP_REBIND_LEN 4
#define DHCP_CLIENT_ID 61 #define DHCP_CLIENT_ID 61
#define DHCP_CLIENT_ID_LEN 7 #define DHCP_CLIENT_ID_LEN 7
#define DHCP_HOSTNAME 12
#define DHCP_REQUEST_IP 50 #define DHCP_REQUEST_IP 50
#define DHCP_REQUEST_IP_LEN 4 #define DHCP_REQUEST_IP_LEN 4
#define DHCP_PARAMS 55 #define DHCP_PARAMS 55
@@ -117,20 +116,6 @@ void dhcp_addopt_client_id(void)
} }
void dhcp_addopt_hostname(void)
{
uint8_t len = 0;
while (hostname[len])
len++;
if (!len)
return;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HOSTNAME;
DHCP_OPT[dhcp_state.opt_ptr++] = len;
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], hostname, len);
dhcp_state.opt_ptr += len;
}
void dhcp_addopt_request_ip(void) void dhcp_addopt_request_ip(void)
{ {
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP; DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
@@ -167,7 +152,6 @@ void dhcp_send_discover(void)
dhcp_addopt_client_id(); dhcp_addopt_client_id();
dhcp_addopt_request_ip(); dhcp_addopt_request_ip();
dhcp_addopt_hostname();
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS; DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
DHCP_OPT[dhcp_state.opt_ptr++] = 3; DHCP_OPT[dhcp_state.opt_ptr++] = 3;
@@ -204,7 +188,6 @@ void dhcp_send_request(void)
dhcp_addopt_client_id(); dhcp_addopt_client_id();
dhcp_addopt_request_ip(); dhcp_addopt_request_ip();
dhcp_addopt_server_id(); dhcp_addopt_server_id();
dhcp_addopt_hostname();
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS; DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
DHCP_OPT[dhcp_state.opt_ptr++] = 3; DHCP_OPT[dhcp_state.opt_ptr++] = 3;
@@ -365,10 +348,8 @@ void dhcp_stop(void) __banked
} }
void dhcp_callback(uint16_t lport) __banked void dhcp_callback(void) __banked
{ {
if (lport != HTONS(DHCPC_CLIENT_PORT)) // Is this call for us? If not, ignore it
return;
if (!dhcp_state.state) if (!dhcp_state.state)
return; return;
if (uip_closed()) { if (uip_closed()) {
+6 -1
View File
@@ -16,7 +16,7 @@
void dhcp_start(void) __banked; void dhcp_start(void) __banked;
void dhcp_stop(void) __banked; void dhcp_stop(void) __banked;
// void dhcp_periodic(void) __banked; // void dhcp_periodic(void) __banked;
void dhcp_callback(uint16_t lport) __banked; void dhcp_callback(void) __banked;
struct dhcp_state { struct dhcp_state {
@@ -40,4 +40,9 @@ struct dhcp_state {
typedef struct dhcp_state uip_udp_appstate_t; typedef struct dhcp_state uip_udp_appstate_t;
/* Finally we define the application function to be called by uIP. */
#ifndef UIP_UDP_APPCALL
#define UIP_UDP_APPCALL dhcp_callback
#endif /* UIP_APPCALL */
#endif #endif
-55
View File
@@ -1,55 +0,0 @@
# 2G040210GSM
The following is a documentation for the managed switch marked as `2G040210GSM`
and sold by Mokerlink.
### Label specifications
- **Name**: 4-port 2.5G Web Managed Switch
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 1A barrel connector
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware (use KP_9000_6XHML_X2 in machine.h if building yourself or the corresponding pre-compiled binary)
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview
Front
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-front.jpeg" width="300" />
Label
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-label.jpeg" width="300" />
### PCB overview
**Board markings**
- Top silkscreen: 2M-PCB43-V1.1
Top side
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-top.jpeg" width="300" />
Bottom
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-bottom.jpeg" width="300" />
### J1, serial console
| `J8` pin | Signal |
| -------- | ----------- |
| 1 | RX (Input) |
| 2 | TX (Output) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-39
View File
@@ -1,39 +0,0 @@
# FG-4GT-2SX_V2.0
Following is documentation for unmanaged switch marked as `FG-4GT-2SX_V2.0`.
Original software is running UART on 9600 baud rate.
## Brands
* Ruiying RY-4GT-2SX
<img src="photos/FG-4GT-2SX_V2.0/RY-4GT-2SX_label.jpg" width="300" />
## What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
## PCB overview
**Board markings**
- Top silkscreen: FG-4GT-2SX_V2.0
Front panel
<img src="photos/FG-4GT-2SX_V2.0/chassis-front.jpg" width="300" />
Top side
<img src="photos/FG-4GT-2SX_V2.0/PCB-top.jpg" width="300" />
Bottom
<img src="photos/FG-4GT-2SX_V2.0/PCB-bottom.jpg" width="300" />
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-93
View File
@@ -1,93 +0,0 @@
# FOXNEO FNS-1200P
RTL8372-based 4×2.5G PoE+ + 2×SFP+ unmanaged switch.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Manufacturer**: FOXNEO
- **Model**: FNS-1200P
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps with PoE+
- 2 × SFP+: 1G / 2.5G / 10G
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE+ is not configurable via RTLPlayground)
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
- LEDs: amber (2.5G) and green (1G/100M/10M) per copper port; combined link/act on SFP ports
### PCB overview
**Board markings**
- Top silkscreen: PCB-K0402W-U13-V2.0 / DIP-K0402WB-V2.0
**Key components**
- U3: SPI NOR flash, 2 MiB
- U7: unpopulated SOP8 footprint — I2C bus (RTL8372 slave at 0x5c) is accessible from its pads, useful for register dumps
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
Front panel
<img src="photos/FNS-1200P/chassis-front.jpg" width="400" />
Top side (PCB)
<img src="photos/FNS-1200P/PCB-top.jpg" width="300" />
### Port layout
| Front panel position | Logical port | Physical port | Type |
|----------------------|--------------|---------------|---------|
| SFP left | 8 | 5 | SFP+ |
| RJ45 1 | 4 | 1 | Copper |
| RJ45 2 | 5 | 2 | Copper |
| RJ45 3 | 6 | 3 | Copper |
| RJ45 4 | 7 | 4 | Copper |
| SFP right | 3 | 6 | SFP+ |
### Serial console
The PCB has three unpopulated through-holes intended for a slide switch, directly connected to UART0.
Numbered from the left (SFP port side), the pinout is:
| Position (left→right) | Signal | GPIO |
|-----------------------|--------|--------------------------|
| 1 (leftmost) | RX | GPIO32\_UART0\_RX (32) |
| 2 (middle) | GND | GND |
| 3 (rightmost) | TX | GPIO31\_UART0\_TX (31) |
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
- Connect a USB-TTL adapter: adapter TX → pin 1, GND → pin 2, adapter RX → pin 3
### LED configuration
Copper ports use LED SET0, SFP ports use LED SET1.
| SET | LED0 | LED2 |
|------|--------------------------------------------------|---------------------------------------------------|
| SET0 | Amber — lights on 2.5G link | Green — lights on 1G / 100M / 10M link |
| SET1 | All speeds — lights on any link with activity | — |
LED pad to physical port mapping:
| GPIO pads | Port |
|-----------|-------------------------|
| GPIO811 | Physical port 5 (left SFP) |
| GPIO1214 | Physical port 1 (RJ45 1) |
| GPIO1517 | Physical port 2 (RJ45 2) |
| GPIO1820 | Physical port 3 (RJ45 3) |
| GPIO2123 | Physical port 4 (RJ45 4) |
| GPIO2427 | Physical port 6 (right SFP) |
### SFP GPIO assignments
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|------------------|-----------------------------|------------------------|--------|----------------------|--------------------------|
| Left (logical 8) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
| Right (logical 3)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO51\_I2C\_SDA2\_UART1\_RX | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
GPIO assignments were verified by observing GPIO state changes during SFP module insertion/removal
and cross-checked against an original firmware register dump.
`pin_tx_disable` is GPIO\_NA on both ports (original firmware keeps all GPIOs as inputs).
+62
View File
@@ -0,0 +1,62 @@
# Hisource Hi-K0402WS
Following is documentation for unmanaged switch marked as `Hi-K0402WS`.
Original software is running UART on 9600 baud rate.
Using SPI clamp in-board is the only method for initial installation.
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: Hi-K0402WS
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
Top side
<img src="photos/K0402W-V3.0-unmanaged\PCB-top.jpg" width="300" />
Bottom
<img src="photos/K0402W-V3.0-unmanaged\PCB-bottom.jpg" width="300" />
### T2, serial console
| `J2` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | RX (Input) |
| 3 | TX (Output) |
| 4 | GND |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Board has two supply rails. `0.95` and `3.3` volt.
### `0.95` Core Voltage
Voltage is made by a `Techcode TD1720` .
### `3.3` Voltage
Voltage is created by chip marked as `Techcode TD1720`.
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
-36
View File
@@ -1,36 +0,0 @@
# Hisource Hi-K0801WS
Following is documentation for unmanaged switch marked as `Hi-K0801WS`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: Hi-K0801WS
- **Ports**:
- 8 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO801W-V2.0 / DIP-KO801WS-V2.0
Top side
<img src="photos/K0801W-V2.0-unmanaged\PCB-top.jpg" width="300" />
Bottom
<img src="photos/K0801W-V2.0-unmanaged\PCB-bottom.jpg" width="300" />
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-57
View File
@@ -1,57 +0,0 @@
# Keeplink KP-9000-6XH-X2
Following is documentation for unmanaged switch marked as `KP-9000-6XH-X2`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 4X 2.5G RJ45 Port + 2 X 10G SFP+ Port
- **Model**: KP-9000-6XH-X2
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port with 10G modules
- LEDs
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview
Front side:
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-front.jpg" width="600" />
Label:
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-label.jpg" width="600" />
### PCB overview
**Board markings**
- Top silkscreen: 2M-PCB43-V2.1
Top side
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-top.jpg" width="600" />
Bottom
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-bottom.jpg" width="600" />
## Reset Button
There's an unpopulated Reset button on the front left side of the PCB.
It can easily be soldered, you'll need an 4.5mmx4.5mm 90° button switch with a 3-pin footprint.
I got mine here: https://de.aliexpress.com/item/1005007295346702.html
The front case has already the hole in the metal case, you just have to punch a hole through the foil.
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-76
View File
@@ -1,76 +0,0 @@
# PCB-K0402WS-V3.0
Following is documentation for a variety of unmanaged switch internally marked as `PCB-K0402WS-V3.0`. They are sold under many brands.
Original software is running UART on 9600 baud rate.
Note during opening the device: there might be a hidden 5th screw on the back
of the device just above the big label, might be covered by a QC sticker.
### Brands
* Hisource Hi-K0402WS
<img src="photos/PCB-K0402WS-V3.0/HiSource_HI-K0402WS.jpg" width="300" />
* Ztyuav Z-QWYT0402
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402.jpg" width="300" />
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
### Programming
Using SPI clamp in-board is the only method for initial installation.
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
The switch actually controls the HOLD line of each flash chip, and toggling the switch results in a reboot.
If the programming clip keeps HOLD not connected, the flashing will commence on whatever the switch selected, regardless on which chip was clipped.
For the initial flash (at least with flashrom), the bin file produced by the build is much smaller than the flash chip, it is suggested to pad the file to keep flashrom happy: `truncate -s 2097152 rtlplayground-*-PCB_K0402WS_V3.bin`. Note: do not then proceed to use this resulting padded file for the web flashing (as it bricks the device), use the original unpadded .bin.
### What works (expected from label + similar devices)
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
Top side
<img src="photos/PCB-K0402WS-V3.0/PCB-top.jpg" width="300" />
Bottom
<img src="photos/PCB-K0402WS-V3.0/PCB-bottom.jpg" width="300" />
### T2, serial console
| `J2` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | RX (Input) |
| 3 | TX (Output) |
| 4 | GND |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Board has two supply rails. `0.95` and `3.3` volt.
### `0.95` Core Voltage
Voltage is made by a `Techcode TD1720` .
### `3.3` Voltage
Voltage is created by chip marked as `Techcode TD1720`.
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
-43
View File
@@ -1,43 +0,0 @@
# Steamemo IG204-V1
Following is documentation for unmanaged switch marked as `IG204-V1`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: IG204 V1
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- Four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Two SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PB-2131
Top side
<img src="photos/STEAMEMO_IG204_V1/PCB-top.jpg" width="600" />
### Connectors
### T7, serial console
| `T7` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | GND |
| 3 | RX (Input) |
| 4 | 3V3 |
### Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-6
View File
@@ -1,10 +1,4 @@
# SWTG018AS-A V2.0 # SWTG018AS-A V2.0
## Brands
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|--------|------------------|-------|------------------|-----------------|---------------|
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`. The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
It is e.g. sold under the Ampcom brand, but no branh-markings are found on the device. It is e.g. sold under the Ampcom brand, but no branh-markings are found on the device.
-43
View File
@@ -1,43 +0,0 @@
### SWTG024AS-A-V2.0.1_4C_2SFP
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Horaco | ZX-SG4T2 | | PCB-SWTG024AS-A-V2.0.1_19650 | P25D40SH | ??? |
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-label.jpg" width="300" />
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
### PCB overview
**Board markings**
- Top silkscreen: PCB-SWTG024AS-A-V2.0.1_19650
Top side
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-top.jpg" width="300" />
Bottom
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | GND |
| 3 | RX (Input) |
| 4 | TX (Output) |
-44
View File
@@ -1,44 +0,0 @@
### SWTG024AS-A-V2.0.1_5C_1SFP
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Horaco | HC-SWTGW215AS | | PCB-SWTG024AS-A-V2.0.1_19650 | W25Q16JV | 8272N |
### Label specifications
- **Name**:
- **Ports**:
- 5 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
<!-- <img src="" width="300" /> -->
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SWTG024AS-A-V2.0.1_19650
Top side
<!-- <img src="" width="300" /> -->
Bottom
<!-- <img src="" width="300" /> -->
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | GND |
| 3 | RX (Input) |
| 4 | TX (Output) |
-49
View File
@@ -1,49 +0,0 @@
### SWTG024AS-V2.0
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| hongyavision | LG-SG5T1 | No | PCB-SWTG024AS-V2.0_16895 | 25Q40 | 8272 |
### Label specifications
- **Name**:
- **Ports**:
- 5 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 1A 5525 connector
<img src="photos/SWTG024AS-V2.0/label.jpg" width="300" />
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
- Online update does not work with 512KiB flash.
### PCB overview
**Board markings**
- Top silkscreen: PCB-SWTG024AS-V2.0
Top side
<img src="photos/SWTG024AS-V2.0/pcb_top.jpg" width="300" />
Bottom
<img src="photos/SWTG024AS-V2.0/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | GND |
| 2 | RX (Input) |
| 3 | TX (Output) |
Note,`R52``R53`may not be installed.You need to bridge them using either solder or resistors.
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
+2 -2
View File
@@ -9,8 +9,8 @@ Also the RJ45 connectors can be all plastic/non-shielded or with metal shielding
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL| |Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|
| LIANGUO |SWTG024AS |No| SWTG024AS-v2.0-17452 | CM-23-11-2336 023-17453| 512 KiB | 8272 | | LIANGUO |SWTG024AS |No| SWTG024AS-v2.0-17452 | CM-23-11-2336 023-17453| 512 KiB | 8272 |
| Horaco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 8272 | | Haraco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 8272 |
| Xikestore |SKS3200M-4GPY2XF | Yes | SWTG024AS-v1.0 | CM-23-08-2043 023-16721 | 2048 KiB | 8272 | | Xikestore |SKS3200M-4GPY2XF | Yes | SWTG024AS-v1.0 | CM-23-08-2043 023-16721 | ??? | 8272 |
| Sodola | SL-SWTG124AS-D | Yes | SWTG024AS-v2.0-17452 | ??? | 2048 KiB | 8272 | | Sodola | SL-SWTG124AS-D | Yes | SWTG024AS-v2.0-17452 | ??? | 2048 KiB | 8272 |
## PCB ## PCB
-1
View File
@@ -6,7 +6,6 @@
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N | | Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
| Sodola | | | | | | | Sodola | | | | | |
| Horaco | | | | | | | Horaco | | | | | |
| XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | |
## Photos ## Photos
-59
View File
@@ -1,59 +0,0 @@
# ZX310S-4T2XH/
The following is a documentation for the managed switch marked as `ZX310S-4T2XH`
and sold by Horaco.
The original software is running UART on 57600 baud rate. The solder holes
of the UART header are filled in. In order to install a UART header, they
need to be cleared first. A 1.2mm drill can be used, alternatively a
de-soldering wick.
The original firmware uses 57600 baud 8N1
CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY RTL8261BE
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 1 x RJ45: 10/100/1000/2500/5000/10000 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 2A barrel connector
<img src="photos/ZX310S-4T2XH/label.jpg" width="300" />
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The 10GBit port works. TODO: Fix EEE, speed selection
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SL310S-4T1T1X-V1.0.1-24107
Top side
<img src="photos/ZX310S-4T2XH/pcb_top.jpg" width="300" />
Bottom
<img src="photos/ZX310S-4T2XH/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | RX (Input) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 2A` adapter was provided.
-53
View File
@@ -1,53 +0,0 @@
# ZX310S-4T2XT
The following is a documentation for the managed switch marked as
`ZX310S-4T2XT` and sold by Horaco.
The original software is running UART on 57600 baud rate 8N1.
CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY 2x RTL8261BE
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 x RJ45: 10/100/1000/2500/5000/10000 Mbps
- **Power**: 12V DC, 2A barrel connector
<img src="photos/ZX310S-4T2XT/label.jpg" width="300" />
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps, including EEE
- The 10GBit ports works, including EEE.
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SL310S-4T2XT-V1.0.0-22273
Top side
<img src="photos/ZX310S-4T2XT/pcb_top.jpg" width="300" />
Bottom
<img src="photos/ZX310S-4T2XT/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | RX (Input) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 2A` adapter was provided.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Before

Width:  |  Height:  |  Size: 521 KiB

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 710 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

+1 -1
View File
@@ -92,7 +92,7 @@ The following shows the network configuration
On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes
source and destination ports into account, e.g. just use the default: source and destination ports into account, e.g. just use the default:
``` ```
> lag 1 1 2 > lag 0 1 2
``` ```
+1 -2
View File
@@ -37,13 +37,12 @@ This list is incomplete.
| Brand | Partnumber | | Brand | Partnumber |
| ---------- |----------- | | ---------- |----------- |
| GigaDevice | GD25Q32E | | GigaDevice | GD25Q32E |
| Fundan | FM25Q16A |
| Puya | P25D40SH |
| Winbond | W25Q16JV | | Winbond | W25Q16JV |
| Winbond | W25Q32FV | | Winbond | W25Q32FV |
| Winbond | W25Q32JV | | Winbond | W25Q32JV |
| Winbond | W25Q16JL | | Winbond | W25Q16JL |
| Winbond | W25Q16DV | | Winbond | W25Q16DV |
| Winbond | W25Q80DV | | Winbond | W25Q80DV |
| Fundan | FM25Q16A |
*NOTE*: Part numbers are incomplete. Part numbers may contain additional information such as package, temperature specifications, and even the number of devices on a reel. So always check the datasheet so that you have the right orderable partnumber. *NOTE*: Part numbers are incomplete. Part numbers may contain additional information such as package, temperature specifications, and even the number of devices on a reel. So always check the datasheet so that you have the right orderable partnumber.
-135
View File
@@ -1,135 +0,0 @@
# Supporting Multiple Languages in the Web UI
The firmware uses a client-side i18n approach
all translations are stored in a single JavaScript dictionary embedded in the firmware.
No server-side changes are needed.
## Architecture
All translation logic lives in `html/i18n.js`. The file contains:
- A `LANG` object with one sub-object per language (`en`, `ja`, ...)
- Language auto-detection (browser language → `localStorage` override)
- `t(key)` — look up a translated string
- `setLang(lang)` — switch language and update the page
- `applyTranslation(el)` — apply translation to one DOM element
Translation keys are **flat strings** (no nesting). The English keys in `LANG.en` also serve as the fallback when a key is missing in another language.
## How to Add a New Language
### 1. Add a dictionary entry in `html/i18n.js`
Append a new sub-object to the `LANG` object. Every key from `LANG.en` must be present:
```js
var LANG = {
en: {
nav_overview: 'Overview',
nav_port_config: 'Port Configuration',
// ... all keys for English
},
ja: {
nav_overview: '概要',
nav_port_config: 'ポート設定',
// ... all keys for Japanese
},
LANGCODE: { // ← add your language here
nav_overview: '...',
nav_port_config: '...',
// ... translate every key
},
};
```
### 2. Add the language to the navigation sidebar
In `html/navigation.js`, add an `<option>` to the language selector:
```js
+ "<option value='en'>English</option><option value='ja'>日本語</option>"
```
Replace with:
```js
+ "<option value='en'>English</option><option value='ja'>日本語</option><option value='LANGCODE'>Native Name</option>"
```
### 3. Verify auto-detection
The language detection code in `i18n.js` reads `navigator.language` and normalises it to the first two characters:
```js
var browser = (navigator.language || navigator.userLanguage || 'en').substring(0, 2);
return LANG[browser] ? browser : 'en';
```
If the two-letter code matches a key in `LANG`, it will be auto-selected. No changes needed here.
## Two Translation Mechanisms
### (A) `data-i18n` attribute (declarative — for HTML)
Add `data-i18n="key_name"` to any HTML element. The English text goes in the element content as a fallback:
```html
<h1 data-i18n="port_heading">Port Configuration</h1>
<input type="button" data-i18n="port_apply" value="Apply">
<option data-i18n="port_auto">Auto</option>
<title data-i18n="port_title">Port Configuration</title>
```
On page load, `applyTranslation()` sets:
- `el.value` for `<input type="submit|button">`
- `el.textContent` for `<option>`, `<title>`
- `el.innerHTML` for everything else
### (B) `t('key')` call (imperative — for JavaScript strings)
When generating HTML or text in JavaScript, wrap translatable strings with `t()`:
```js
td.appendChild(document.createTextNode(t('common_port') + i));
td.innerHTML = t('port_auto');
iHTML += "<tr><td>" + t('port_vendor') + "</td></tr>";
```
### Special Case: Link Speed Display
The `linkS` array in `html/main.js` maps numeric link states to display strings. The first two entries (`speed_disabled`, `speed_down`) use `t()` for translation; the remaining entries are static literals (they are the same in all languages):
```js
const linkS = [
function(){return t('speed_disabled')},
function(){return t('speed_down')},
"10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"
];
function linkText(idx) { var v = linkS[idx]; return typeof v === 'function' ? v() : v; }
```
Always use `linkText(idx)` (not `linkS[idx]`) to read these values.
## Size Considerations
- `html/i18n.js` is embedded in the firmware filesystem (~14 KB for two languages)
- Each new language adds roughly the same number of bytes as the English dictionary (~34 KB)
- The firmware binary is padded to 512 KiB, so a few extra KB do not change the flash footprint
- Values that are identical in all languages should be inlined as literals rather than added to the dictionary (e.g., `"10M"`, `"2.5G"`, `"MAC"`, `"VLAN"`, `"CPU"`)
## Build
No special flags are needed. The `html/` directory is embedded by `fileadder` during the build.
## Script Load Order
`i18n.js` must be loaded after `main.js` (which defines `t()`'s dependencies like `LANG`) but before any page-specific JS that calls `t()`:
```html
<script src="/main.js"></script>
<script src="/i18n.js"></script>
<script src="/eee.js"></script> <!-- uses t() -->
```
The `navigation.js` script is loaded last (bottom of `<body>`).
+11 -29
View File
@@ -1,35 +1,17 @@
# Supported Hardware # Supported Hardware
The following devices have been tested and are fully working: The following devices have been tested and are fully working:
- Horaco ZX_SG4T2
- keepLINK kp-9000-6hx-x2 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
- keepLINK KP-9000-6XHML-X2, same as above, but Managed
- keepLINK kp-9000-6hx-x (RTL8372 + RTL8221B 2.5GBit PHY: 5 x 2.5GBit + 1x 10GBit SFP+)
- keepLINK kp-9000-9xh-x-eu (1 x RTL8373 + RTL8224: 8x 2.5GBit + 1x 10GBit SFP+)
- Lianguo LG-SWTGW218AS (RTL8373 + RTL8224 PHY: 8x 2.5GBit + 1x 10GBit SFP+)
- No-Name ZX-SWTGW215AS, managed version of kp-9000-6hx-x, ordered on
AliExpress as keepLINK 5+1 port managed
- TrendNet TEG-S562 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
| Brand | Type | Managed | PCB | Flash | Ports | Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide]
|----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------| (https://github.com/up-n-atom/SWTG118AS)
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
| hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 |
| Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 |
| Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
| Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 |
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 |
| Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 |
| Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
| Keeplink | KP-9000-6XH-X2 | No | [2M-PCB43-V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0](devices/SWTGW215AS.md) | 2M | 5 + 1 |
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
| Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 |
| TrendNet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide](https://github.com/up-n-atom/SWTG118AS)
Many of the RTL8272/3 devices come in versions with PoE support. The RTLPlayground usually also Many of the RTL8272/3 devices come in versions with PoE support. The RTLPlayground usually also
works on these, however, no support for configuring PoE is provided, simply because these works on these, however, no support for configuring PoE is provided, simply because these
-6
View File
@@ -79,12 +79,6 @@ vlan <VLAN-ID> d
vlan show vlan show
Dumps the current ingress vlan settings. Dumps the current ingress vlan settings.
vlan <VLAN-ID> mgmt
Restricts network access to the switch (web UI, syslog) to the given
VLAN. Use `vlan 0 mgmt` to disable the filter. Default is `vlan 1 mgmt`.
Warning: setting this to an unreachable VLAN locks out the web UI;
recovery requires serial console.
pvid <port> <VLAN-ID> pvid <port> <VLAN-ID>
assigns PVID to a port. ports are numbered as on the casing assigns PVID to a port. ports are numbered as on the casing
+4 -5
View File
@@ -1,18 +1,17 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="bw_title">Ingress and Egress Bandwidth</title> <title>Ingress and Egress Bandwidth</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="bw_heading">Ingress and Egress Bandwidth</h1> <h1>Ingress and Egress Bandwidth</h1>
<table id="bwtable"> <table id="bwtable">
<tr> <th> </th> <th colspan="3" data-i18n="bw_ingress"> Ingress </th> <th colspan="2" data-i18n="bw_egress">Egress</th> <th></th></tr> <tr> <th> </th> <th colspan="3"> Ingress </th> <th colspan="2">Egress</th> <th></th></tr>
<tr> <th data-i18n="bw_col_port">Port</th> <th data-i18n="bw_col_limit">Limit</th> <th data-i18n="bw_col_bandwidth">Bandwidth [kBit/s]</th> <th data-i18n="bw_col_flow">Flow Control</th> <th data-i18n="bw_col_limit">Limit</th> <th data-i18n="bw_col_bandwidth">Bandwidth [kBit/s]</th> <th data-i18n="bw_col_apply">Apply</th></tr> <tr> <th>Port</th> <th>Limit</th> <th>Bandwidth [kBit/s]</th> <th>Flow Control</th> <th>Limit</th> <th>Bandwidth [kBit/s]</th> <th>Apply</th></tr>
</table> </table>
<script src="/bandwidth.js"></script> <script src="/bandwidth.js"></script>
</div> </div>
+13 -13
View File
@@ -6,18 +6,18 @@ function createBW() {
console.log("CREATING TABLE ", tbl.rows.length); console.log("CREATING TABLE ", tbl.rows.length);
for (let i = 2; i < 2 + numPorts; i++) { for (let i = 2; i < 2 + numPorts; i++) {
const tr = tbl.insertRow(); const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i-1))); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = limit.replaceAll("limit_port", "ilimit_port_" + i).replace("exec()", "iClicked(" + i + ")"); td.innerHTML = limit.replaceAll("limit_port", "ilimit_port_" + i).replace("exec()", "iClicked(" + i + ")");
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = t('bw_unlimited'); td.innerHTML = 'UNLIMITED';
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = limit.replaceAll("limit_port", "fc_port_" + i).replace("exec()", "document.getElementById('bwapply_" + i + "').disabled=false;"); td.innerHTML = limit.replaceAll("limit_port", "fc_port_" + i).replace("exec()", "document.getElementById('bwapply_" + i + "').disabled=false;");
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = limit.replaceAll("limit_port", "elimit_port_" + i).replace("exec()", "eClicked(" + i + ")"); td.innerHTML = limit.replaceAll("limit_port", "elimit_port_" + i).replace("exec()", "eClicked(" + i + ")");
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = t('bw_unlimited'); td.innerHTML = 'UNLIMITED';
var button = '<button type="button" id="bwapply_' + i + '" style="margin: 0 0 0 24px" onclick="applyBandwidth(' + i + ');">' + t('bw_col_apply') + '</button>'; var button = '<button type="button" id="bwapply_' + i + '" style="margin: 0 0 0 24px" onclick="applyBandwidth(' + i + ');">Apply</button>';
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = button; td.innerHTML = button;
document.getElementById("bwapply_" + i).disabled = true; document.getElementById("bwapply_" + i).disabled = true;
@@ -31,7 +31,7 @@ function iClicked(i)
var tbl = document.getElementById('bwtable'); var tbl = document.getElementById('bwtable');
var tr = tbl.rows[i]; var tr = tbl.rows[i];
if (!document.getElementById("ilimit_port_" + i).checked) { if (!document.getElementById("ilimit_port_" + i).checked) {
tr.cells[2].innerHTML = t('bw_unlimited'); tr.cells[2].innerHTML = "UNLIMITED";
document.getElementById("fc_port_" + i).disabled = true; document.getElementById("fc_port_" + i).disabled = true;
document.getElementById("fc_port_" + i).checked = true; document.getElementById("fc_port_" + i).checked = true;
} else { } else {
@@ -47,7 +47,7 @@ function eClicked(i)
var tbl = document.getElementById('bwtable'); var tbl = document.getElementById('bwtable');
var tr = tbl.rows[i]; var tr = tbl.rows[i];
if (!document.getElementById("elimit_port_" + i).checked) { if (!document.getElementById("elimit_port_" + i).checked) {
tr.cells[5].innerHTML = t('bw_unlimited'); tr.cells[5].innerHTML = "UNLIMITED";
} else { } else {
tr.cells[5].innerHTML = '<input id="ebw_' + i + iLayout + i + ')" value="0"/>'; tr.cells[5].innerHTML = '<input id="ebw_' + i + iLayout + i + ')" value="0"/>';
} }
@@ -110,12 +110,12 @@ function getBW() {
document.getElementById("ilimit_port_" + (n+1)).checked = p.iLimited; document.getElementById("ilimit_port_" + (n+1)).checked = p.iLimited;
document.getElementById("elimit_port_" + (n+1)).checked = p.eLimited; document.getElementById("elimit_port_" + (n+1)).checked = p.eLimited;
if (!p.iLimited) { if (!p.iLimited) {
tr.cells[2].innerHTML = t('bw_unlimited'); tr.cells[2].innerHTML = "UNLIMITED";
} else { } else {
tr.cells[2].innerHTML = '<input id="ibw_' + (n+1) + iLayout + (n+1) + ')" value="' + iBW +'"/>'; tr.cells[2].innerHTML = '<input id="ibw_' + (n+1) + iLayout + (n+1) + ')" value="' + iBW +'"/>';
} }
if (!p.eLimited) { if (!p.eLimited) {
tr.cells[5].innerHTML = t('bw_unlimited'); tr.cells[5].innerHTML = "UNLIMITED";
} else { } else {
tr.cells[5].innerHTML = '<input id="ebw_' + (n+1) + iLayout + (n+1) + ')" value="' + eBW +'"/>'; tr.cells[5].innerHTML = '<input id="ebw_' + (n+1) + iLayout + (n+1) + ')" value="' + eBW +'"/>';
} }
+21 -76
View File
@@ -1,90 +1,35 @@
var configInterval = Number(); var configInterval = Number();
var configuration = []; var configuration = [];
const conf_cmds = [ const conf_cmds = [
/^ip\s+(\d{1,3}\.){3}\d{1,3}$/, /ip\s+(\d{1,3}\.){3}\d{1,3}/, /gw\s+(\d{1,3}\.){3}\d{1,3}/, /netmask\s+(\d{1,3}\.){3}\d{1,3}/,
/^ip\s+dhcp$/, /eee(\s+\d)?\s+(on|off)/, /mirror(\s+(\d|10))(\s+(\d|10)(t|r)?)+/, /vlan\s+(\d{1,4})(\s+(\d|10)(t|u)?)+/
/^gw\s+(\d{1,3}\.){3}\d{1,3}$/,
/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
/^syslog\s+(on|off)$/,
/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,
/^passwd\s+\S+$/,
/^vlan\s+\d{1,4}\s+d$/,
/^vlan\s+\d{1,4}\s+mgmt$/,
/^vlan\s+\d{1,4}(\s+[a-zA-Z]\w*)?(\s+\d{1,2}[tu]?)+$/,
/^pvid\s+\d{1,2}\s+\d{1,4}$/,
/^ingress(\s+\d{1,2}[tua])+$/,
/^ingress\s+[tua]$/,
/^port\s+\d{1,2}\s+(10m|100m|1g|2g5|5g|10g|auto|on|off)(\s+(half|full))?$/,
/^port\s+\d{1,2}\s+name\s+\S+$/,
/^eee(\s+\d{1,2})?\s+(on|off)$/,
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,
/^lag\s+\d(\s+\d{1,2})+$/,
/^laghash\s+\d(\s+\w+)+$/,
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
/^stp\s+(on|off)$/,
/^igmp\s+(on|off)$/,
/^mtu\s+\d{1,2}\s+\d+$/,
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
/^hostname\s+.{1,23}$/,
]; ];
const conf_overwrite = [ const conf_overwrite = [
/^ip\b/, /ip/, /gw/, /netmask/, /eee\s+\w+/, /eee(\s+\w)/, /mirror/, /vlan\s+(\d{1,4})/
/^gw\b/,
/^netmask\b/,
/^syslog\s+ip\b/,
/^syslog\b/,
/^passwd\b/,
/^vlan\s+\d{1,4}\s+mgmt$/,
/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
/^pvid\s+\d{1,2}\b/,
/^ingress\b/,
/^port\s+\d{1,2}(?!\s+name\b)/,
/^port\s+\d{1,2}\s+name\b/,
/^eee\s+\d{1,2}\b/,
/^eee\b/,
/^mirror\b/,
/^lag\s+\d+\b/,
/^laghash\b/,
/^isolate\s+\d{1,2}\b/,
/^stp\b/,
/^igmp\b/,
/^mtu\s+\d{1,2}\b/,
/^bw\s+(in|out)\s+\d{1,2}\b/,
/^hostname\b/,
]; ];
function parseConf(s){ function parseConf(s){
var a = s.split(/\r\n|\n/); var a = s.split(/\r\n|\n/);
for (var l = 0; l < a.length; l++) { for (var l = 0; l < a.length; l++) {
var line = a[l].trim().replace(/\s+/g, ' '); if (!a[l].length || a[l] == "\n" || a[l] == "\r\n")
if (!line.length) continue; continue;
const deleteMatch = line.match(/^vlan\s+(\d{1,4})\s+d$/); console.log(l + ' --> ' + a[l]);
if (deleteMatch) { var ignore = true;
const prefix = "vlan " + deleteMatch[1] + " "; for (const x of conf_cmds)
configuration = configuration.filter(c => !c.startsWith(prefix)); if (x.test(a[l])) ignore = false;
continue; if (ignore) continue;
} for (const x of conf_overwrite) {
console.log(l + ' --> ' + line); if (x.test(a[l])) {
var ignore = true; console.log("Match ", x, " to ", a[l]);
for (const x of conf_cmds) m = a[l].match(x);
if (x.test(line)) { ignore = false; break; } console.log("Starts with ", m[0]);
if (ignore) continue; configuration = configuration.filter(item => !(item.startsWith(m[0])));
for (const x of conf_overwrite) { }
if (x.test(line)) {
let m = line.match(x);
let matchStr = m[0];
configuration = configuration.filter(item =>
!(item === matchStr || (item.startsWith(matchStr + " ") && !item.endsWith(" mgmt") && !item.startsWith(matchStr + " name "))));
break;
} }
configuration.push(a[l]);
} }
// Only one management VLAN can be active, so drop any previous mgmt entry console.log("Configuration now:");
if (/^vlan\s+\d{1,4}\s+mgmt$/.test(line)) for (const x of configuration) { console.log(x); }
configuration = configuration.filter(item => !/^vlan\s+\d{1,4}\s+mgmt$/.test(item));
configuration.push(line);
}
console.log("Configuration now:");
for (const x of configuration) { console.log(x); }
} }
async function fetchConfig() { async function fetchConfig() {
+6 -7
View File
@@ -1,22 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="eee_title">EEE Configuration</title> <title>EEE Configuration</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="eee_heading">EEE Status</h1> <h1>EEE Status</h1>
<table id="eeetable"> <table id="eeetable">
<tr> <th> </th> <th colspan="3" data-i18n="eee_advertising"> Advertising </th> <th colspan="3" data-i18n="eee_partner">Link-Partner advertises</th> <th></th></tr> <tr> <th> </th> <th colspan="3"> Advertising </th> <th colspan="3">Link-Partner advertises</th> <th></th></tr>
<tr> <th data-i18n="eee_port">Port</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th data-i18n="eee_active">Active?</th></tr> <tr> <th>Port</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>2.5G</th> <th>1G</th> <th>100M</th> <th>Active?</th></tr>
</table> </table>
<div> <div>
<input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 1);" type="button" data-i18n="eee_enable" value="Enable EEE"> <input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 1);" type="button" value="Enable EEE">
<input style="width:20%;" class="action" id="eee_disable" onclick="eeeSub(0, 0);" type="button" data-i18n="eee_disable" value="Disable EEE"> <input style="width:20%;" class="action" id="eee_enable" onclick="eeeSub(0, 0);" type="button" value="Disable EEE">
</div> </div>
<script src="/eee.js"></script> <script src="/eee.js"></script>
<script src="/eee_sub.js"></script> <script src="/eee_sub.js"></script>
+3 -3
View File
@@ -5,7 +5,7 @@ function createEEE() {
for (let i = 2; i < 2 + numPorts; i++) { for (let i = 2; i < 2 + numPorts; i++) {
console.log("Table row: " + i + "pState: " + pState[i-2]); console.log("Table row: " + i + "pState: " + pState[i-2]);
const tr = tbl.insertRow(); const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i-1))); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i-1}`));
for (let j = 0; j < 7; j++) { for (let j = 0; j < 7; j++) {
td = tr.insertCell(); td.appendChild(document.createTextNode(" ")); td = tr.insertCell(); td.appendChild(document.createTextNode(" "));
} }
@@ -28,8 +28,8 @@ function getEEE() {
let tr = tbl.rows[n+1]; let tr = tbl.rows[n+1];
if (!p.isSFP) { if (!p.isSFP) {
let eee = parseInt(p.eee,2); let lp = parseInt(p.eee_lp,2); let eee = parseInt(p.eee,2); let lp = parseInt(p.eee_lp,2);
tr.cells[1].innerHTML = `${eee&4?t('eee_on'):t('eee_off')}`; tr.cells[2].innerHTML = `${eee&2?t('eee_on'):t('eee_off')}`; tr.cells[3].innerHTML = `${eee&1?t('eee_on'):t('eee_off')}`; tr.cells[1].innerHTML = `${eee&4?"ON":"OFF"}`; tr.cells[2].innerHTML = `${eee&2?"ON":"OFF"}`; tr.cells[3].innerHTML = `${eee&1?"ON":"OFF"}`;
tr.cells[4].innerHTML = `${lp&4?t('eee_on'):t('eee_off')}`; tr.cells[5].innerHTML = `${lp&2?t('eee_on'):t('eee_off')}`; tr.cells[6].innerHTML = `${lp&1?t('eee_on'):t('eee_off')}`; tr.cells[4].innerHTML = `${lp&4?"ON":"OFF"}`; tr.cells[5].innerHTML = `${lp&2?"ON":"OFF"}`; tr.cells[6].innerHTML = `${lp&1?"ON":"OFF"}`;
tr.cells[7].innerHTML = `${p.active}`; tr.cells[7].innerHTML = `${p.active}`;
tr.classList.toggle('disabled', pState[i-2] < 0); tr.classList.toggle('isNOK', !p.active); tr.classList.toggle('isOK', p.active); tr.classList.toggle('disabled', pState[i-2] < 0); tr.classList.toggle('isNOK', !p.active); tr.classList.toggle('isOK', p.active);
} }
-603
View File
@@ -1,603 +0,0 @@
var LANG = {
en: {
nav_overview: 'Overview',
nav_port_config: 'Port Configuration',
nav_port_stat: 'Port Statistics',
nav_l2: 'L2 Configuration',
nav_mirror: 'Mirroring',
nav_lag: 'Link Aggregation',
nav_eee: 'EEE',
nav_bandwidth: 'Bandwidth Limits',
nav_system: 'System Settings',
nav_fw_update: 'Firmware Update',
port_name: 'Name',
port_status: 'Status',
port_not_enabled: 'Not enabled.',
port_link_speed: 'Link speed',
port_vendor: 'Vendor',
port_model: 'Model',
port_serial: 'Serial',
port_temp: 'Temp',
port_vcc: 'Vcc',
port_tx_fault: 'TX-Fault',
port_tx_disabled: 'TX-Disabled',
port_tx_bias: 'TX-Bias',
port_tx_power: 'TX-Power',
port_rx_power: 'RX-Power',
port_rx_los: 'RX-LOS',
speed_disabled: 'Disabled',
speed_down: 'Down',
port_title: 'FreeSwitchOS Port Configuration',
port_heading: 'Port Configuration',
port_col_port: 'Port',
port_col_name: 'Name',
port_col_speed: 'Current Link Speed',
port_col_set_speed: 'Set Speed',
port_col_disabled: 'Disabled',
port_col_apply: 'Apply',
port_mtu_heading: 'Configure Maximum Frame Size (MTU) forwarded at Port',
port_auto: 'Auto',
port_2500m: '2500MBit/Full',
port_1000m: '1000MBit/Full',
port_100m_f: '100MBit/Full',
port_100m_h: '100MBit/Half',
port_10m_f: '10MBit/Full',
port_10m_h: '10MBit/Half',
port_apply: 'Apply',
stat_title: 'FreeSwitchOS Port Statistics',
stat_heading: 'Port Statistics',
stat_detailed: 'Detailed Port Statistics',
stat_close: 'Close',
stat_col_port: 'Port',
stat_col_name: 'Name',
stat_col_link: 'link',
stat_col_tx_good: 'TX Good',
stat_col_tx_bad: 'TX Bad',
stat_col_rx_good: 'RX Good',
stat_col_rx_bad: 'RX Bad',
stat_col_all: 'All Counters',
stat_counter: 'Counter',
stat_value: 'Value',
stat_show: 'Show',
vlan_title: 'FreeSwitchOS VLAN Configuration',
vlan_heading: 'VLAN Configuration',
vlan_select: 'VLAN Select:',
vlan_choose: '— VLAN Choose —',
vlan_id: 'VLAN ID:',
vlan_get_config: 'Get Configuration',
vlan_name: 'VLAN Name:',
vlan_tagged: 'Tagged Ports',
vlan_untagged: 'Untagged Ports',
vlan_select_all: 'Select all',
vlan_pvid: 'Use as default VLAN for incoming traffic (PVID)',
vlan_update: 'Update / Create',
vlan_configured: 'Configured VLANs',
vlan_col_name: 'Name',
vlan_col_member: 'Member Ports',
vlan_col_tagged: 'Tagged Ports',
vlan_col_untagged: 'Untagged Ports',
vlan_col_pvid: 'PVID Ports',
vlan_col_delete: 'Delete',
vlan_set_id_first: 'Set VLAN ID first',
vlan_delete_confirm: 'Delete VLAN ',
lag_title: 'Link Aggregation Configuration',
lag_heading: 'Link Aggregation Groups Configuration',
lag_update: 'Update / Create',
mirror_title: 'Mirror Configuration',
mirror_heading: 'Mirror Configuration',
mirror_enabled: 'Enabled:',
mirror_port: 'Mirroring Port:',
mirror_tx: 'Mirrored Ports (TX)',
mirror_rx: 'Mirrored Ports (RX)',
mirror_update: 'Update / Create',
mirror_disable: 'Disable Mirroring',
mirror_set_port_first: 'Set Mirroring Port first',
mirror_select_ports: 'Select Mirrored Ports',
eee_title: 'EEE Configuration',
eee_heading: 'EEE Status',
eee_advertising: 'Advertising',
eee_partner: 'Link-Partner advertises',
eee_port: 'Port',
eee_active: 'Active?',
eee_enable: 'Enable EEE',
eee_disable: 'Disable EEE',
eee_on: 'ON',
eee_off: 'OFF',
l2_title: 'FreeSwitchOS L2 Configuration',
l2_heading: 'L2 Configuration',
l2_col_port: 'Port',
l2_col_type: 'Type',
l2_col_remove: 'Remove Entry',
l2_shown: 'Shown:',
l2_delete: 'Delete',
l2_static: 'static',
l2_learned: 'learned',
bw_title: 'Ingress and Egress Bandwidth',
bw_heading: 'Ingress and Egress Bandwidth',
bw_ingress: 'Ingress',
bw_egress: 'Egress',
bw_col_port: 'Port',
bw_col_limit: 'Limit',
bw_col_bandwidth: 'Bandwidth [kBit/s]',
bw_col_flow: 'Flow Control',
bw_col_apply: 'Apply',
bw_unlimited: 'UNLIMITED',
sys_title: 'System Settings',
sys_tab_system: 'System',
sys_tab_advanced: 'Advanced',
sys_tab_console: 'Console',
sys_heading: 'System Settings',
sys_ip: 'IP address:',
sys_model: 'Model:',
sys_hostname: 'Hostname:',
sys_apply: 'Apply',
sys_netmask: 'Netmask:',
sys_gateway: 'Gateway:',
sys_language: 'Language:',
sys_mgmt_vlan: 'Management VLAN:',
sys_mgmt_untagged: 'untagged',
sys_mgmt_confirm: 'Move switch management to VLAN ',
sys_mgmt_warn: 'The switch will start tagging its own traffic with that VLAN. If the port you are connected through does not carry it, this page becomes unreachable and the setting can only be undone over the console. Continue?',
sys_ip_note: 'When updating the above settings, remember to point your browser to the new IP afterwards:',
sys_update: 'Update Settings',
sys_save_label: 'Save all current settings to Flash:',
sys_save: 'Save Settings to Flash',
sys_advanced: 'Advanced Settings',
sys_startup_config: 'Startup configuration:',
sys_startup_warn: 'Be careful when saving the directly edited startup configuration, you can lock yourself out:',
sys_clear_config: 'Clear Startup Config',
sys_save_startup: 'Save Startup Settings to Flash',
sys_reset: 'Reset Switch',
sys_console: 'Console Command',
sys_enter_cmd: 'Enter command:',
sys_send_cmd: 'Send Command',
sys_console_warn: 'Be careful when entering console commands, you can lock yourself out!',
sys_invalid_ip: 'Invalid ip:',
sys_reset_confirm: 'Are you sure you want to reset the switch?',
sys_resetting: 'Switch is resetting. Please wait and refresh the page.',
login_title: 'RTL Switch Login',
login_heading: 'RTL Switch Login',
login_wrong: 'Wrong password!',
login_password: 'Password',
login_login: 'Login',
index_title: 'FreeSwitchOS Main Page',
index_heading: 'Switch Configuration',
index_settings: 'Settings',
update_title: 'Firmware update',
update_heading: 'Firmware Update',
update_instruction: 'Choose a firmware update file to upload:',
update_upload: 'Upload File',
common_port: 'Port ',
common_pkts: ' pkts',
},
ja: {
nav_overview: '概要',
nav_port_config: 'ポート設定',
nav_port_stat: 'ポート統計',
nav_l2: 'L2 設定',
nav_mirror: 'ミラーリング',
nav_lag: 'リンクアグリゲーション',
nav_eee: 'EEE',
nav_bandwidth: '帯域制限',
nav_system: 'システム設定',
nav_fw_update: 'ファームウェア更新',
port_name: '名前',
port_status: '状態',
port_not_enabled: '無効',
port_link_speed: 'リンク速度',
port_vendor: 'ベンダー',
port_model: 'モデル',
port_serial: 'シリアル',
port_temp: '温度',
port_vcc: '電圧',
port_tx_fault: 'TX 障害',
port_tx_disabled: 'TX 無効',
port_tx_bias: 'TX バイアス',
port_tx_power: 'TX 電力',
port_rx_power: 'RX 電力',
port_rx_los: 'RX 信号ロス',
speed_disabled: '無効',
speed_down: 'リンクダウン',
port_title: 'FreeSwitchOS ポート設定',
port_heading: 'ポート設定',
port_col_port: 'ポート',
port_col_name: '名前',
port_col_speed: '現在のリンク速度',
port_col_set_speed: '速度設定',
port_col_disabled: '無効',
port_col_apply: '適用',
port_mtu_heading: 'ポートの最大フレームサイズ (MTU) 設定',
port_auto: '自動',
port_2500m: '2500Mbps/全二重',
port_1000m: '1000Mbps/全二重',
port_100m_f: '100Mbps/全二重',
port_100m_h: '100Mbps/半二重',
port_10m_f: '10Mbps/全二重',
port_10m_h: '10Mbps/半二重',
port_apply: '適用',
stat_title: 'FreeSwitchOS ポート統計',
stat_heading: 'ポート統計',
stat_detailed: '詳細ポート統計',
stat_close: '閉じる',
stat_col_port: 'ポート',
stat_col_name: '名前',
stat_col_link: 'リンク',
stat_col_tx_good: 'TX 正常',
stat_col_tx_bad: 'TX 異常',
stat_col_rx_good: 'RX 正常',
stat_col_rx_bad: 'RX 異常',
stat_col_all: '全カウンタ',
stat_counter: 'カウンタ',
stat_value: '値',
stat_show: '表示',
vlan_title: 'FreeSwitchOS VLAN 設定',
vlan_heading: 'VLAN 設定',
vlan_select: 'VLAN 選択:',
vlan_choose: '— VLAN 選択 —',
vlan_id: 'VLAN ID:',
vlan_get_config: '設定取得',
vlan_name: 'VLAN 名:',
vlan_tagged: 'タグ付きポート',
vlan_untagged: 'タグ無しポート',
vlan_select_all: 'すべて選択',
vlan_pvid: '受信トラフィックのデフォルト VLAN (PVID)',
vlan_update: '更新 / 作成',
vlan_configured: '設定済み VLAN',
vlan_col_name: '名前',
vlan_col_member: 'メンバーポート',
vlan_col_tagged: 'タグ付きポート',
vlan_col_untagged: 'タグ無しポート',
vlan_col_pvid: 'PVID ポート',
vlan_col_delete: '削除',
vlan_set_id_first: 'VLAN ID を先に設定してください',
vlan_delete_confirm: 'VLAN 削除 ',
lag_title: 'リンクアグリゲーション設定',
lag_heading: 'リンクアグリゲーショングループ設定',
lag_update: '更新 / 作成',
mirror_title: 'ミラーリング設定',
mirror_heading: 'ミラーリング設定',
mirror_enabled: '有効:',
mirror_port: 'ミラーポート:',
mirror_tx: 'ミラー元ポート (TX)',
mirror_rx: 'ミラー元ポート (RX)',
mirror_update: '更新 / 作成',
mirror_disable: 'ミラーリング無効化',
mirror_set_port_first: 'ミラーポートを先に設定してください',
mirror_select_ports: 'ミラー元ポートを選択してください',
eee_title: 'EEE 設定',
eee_heading: 'EEE 状態',
eee_advertising: 'EEE アドバタイジング',
eee_partner: 'リンクパートナー広告',
eee_port: 'ポート',
eee_active: '有効?',
eee_enable: 'EEE 有効化',
eee_disable: 'EEE 無効化',
eee_on: 'オン',
eee_off: 'オフ',
l2_title: 'FreeSwitchOS L2 設定',
l2_heading: 'L2 設定',
l2_col_port: 'ポート',
l2_col_type: 'タイプ',
l2_col_remove: 'エントリ削除',
l2_shown: 'Shown:',
l2_delete: '削除',
l2_static: '静的',
l2_learned: '学習',
bw_title: '入力/出力帯域制限',
bw_heading: '入力/出力帯域制限',
bw_ingress: '入力',
bw_egress: '出力',
bw_col_port: 'ポート',
bw_col_limit: '制限',
bw_col_bandwidth: '帯域 [kbps]',
bw_col_flow: 'フロー制御',
bw_col_apply: '適用',
bw_unlimited: '制限無し',
sys_title: 'システム設定',
sys_tab_system: 'システム',
sys_tab_advanced: '詳細設定',
sys_tab_console: 'コンソール',
sys_heading: 'システム設定',
sys_ip: 'IP アドレス:',
sys_model: 'モデル:',
sys_hostname: 'ホスト名:',
sys_apply: '適用',
sys_netmask: 'ネットマスク:',
sys_gateway: 'ゲートウェイ:',
sys_language: '言語:',
sys_mgmt_vlan: 'Management VLAN:',
sys_mgmt_untagged: 'untagged',
sys_mgmt_confirm: 'Move switch management to VLAN ',
sys_mgmt_warn: 'The switch will start tagging its own traffic with that VLAN. If the port you are connected through does not carry it, this page becomes unreachable and the setting can only be undone over the console. Continue?',
sys_ip_note: '上記設定を変更した場合は、ブラウザで新しい IP にアクセスしてください:',
sys_update: '設定更新',
sys_save_label: '現在の設定をフラッシュに保存:',
sys_save: '設定をフラッシュに保存',
sys_advanced: '詳細設定',
sys_startup_config: '起動設定:',
sys_startup_warn: '起動設定を直接編集する際は注意してください。ロックアウトされる可能性があります:',
sys_clear_config: '起動設定クリア',
sys_save_startup: '起動設定をフラッシュに保存',
sys_reset: 'スイッチ再起動',
sys_console: 'コンソールコマンド',
sys_enter_cmd: 'コマンド入力:',
sys_send_cmd: 'コマンド送信',
sys_console_warn: 'コンソールコマンドは注意して入力してください。ロックアウトされる可能性があります!',
sys_invalid_ip: '無効な IP: ',
sys_reset_confirm: 'スイッチを再起動してもよろしいですか?',
sys_resetting: 'スイッチを再起動中です。しばらく待ってからページをリロードしてください。',
login_title: 'RTL スイッチ ログイン',
login_heading: 'RTL スイッチ ログイン',
login_wrong: 'パスワードが違います!',
login_password: 'パスワード',
login_login: 'ログイン',
index_title: 'FreeSwitchOS メインページ',
index_heading: 'スイッチ設定',
index_settings: '設定',
update_title: 'ファームウェア更新',
update_heading: 'ファームウェア更新',
update_instruction: 'アップロードするファームウェアファイルを選択:',
update_upload: 'ファイルをアップロード',
common_port: 'ポート ',
common_pkts: ' pkts',
},
zh: {
nav_overview: '概览',
nav_port_config: '端口配置',
nav_port_stat: '端口统计',
nav_l2: 'L2 配置',
nav_mirror: '端口镜像',
nav_lag: '链路聚合',
nav_eee: 'EEE',
nav_bandwidth: '带宽限制',
nav_system: '系统设置',
nav_fw_update: '固件升级',
port_name: '名称',
port_status: '状态',
port_not_enabled: '未启用。',
port_link_speed: '链路速率',
port_vendor: '厂商',
port_model: '型号',
port_serial: '序列号',
port_temp: '温度',
port_vcc: '供电电压',
port_tx_fault: 'TX 故障',
port_tx_disabled: 'TX 禁用',
port_tx_bias: 'TX 偏置电流',
port_tx_power: 'TX 光功率',
port_rx_power: 'RX 光功率',
port_rx_los: 'RX 信号丢失',
speed_disabled: '禁用',
speed_down: '未连接',
port_title: 'FreeSwitchOS 端口配置',
port_heading: '端口配置',
port_col_port: '端口',
port_col_name: '名称',
port_col_speed: '当前链路速率',
port_col_set_speed: '设置速率',
port_col_disabled: '禁用',
port_col_apply: '应用',
port_mtu_heading: '配置端口转发的最大帧大小 (MTU)',
port_auto: '自动',
port_2500m: '2500Mbps/全双工',
port_1000m: '1000Mbps/全双工',
port_100m_f: '100Mbps/全双工',
port_100m_h: '100Mbps/半双工',
port_10m_f: '10Mbps/全双工',
port_10m_h: '10Mbps/半双工',
port_apply: '应用',
stat_title: 'FreeSwitchOS 端口统计',
stat_heading: '端口统计',
stat_detailed: '详细端口统计',
stat_close: '关闭',
stat_col_port: '端口',
stat_col_name: '名称',
stat_col_link: '链路',
stat_col_tx_good: 'TX 正常包',
stat_col_tx_bad: 'TX 错误包',
stat_col_rx_good: 'RX 正常包',
stat_col_rx_bad: 'RX 错误包',
stat_col_all: '所有计数器',
stat_counter: '计数器',
stat_value: '值',
stat_show: '查看',
vlan_title: 'FreeSwitchOS VLAN 配置',
vlan_heading: 'VLAN 配置',
vlan_select: 'VLAN 选择:',
vlan_choose: '-- 请选择 VLAN --',
vlan_id: 'VLAN ID:',
vlan_get_config: '获取配置',
vlan_name: 'VLAN 名称:',
vlan_tagged: 'Tagged 端口',
vlan_untagged: 'Untagged 端口',
vlan_select_all: '全选',
vlan_pvid: '作为入方向流量的默认 VLAN (PVID)',
vlan_update: '更新 / 创建',
vlan_configured: '已配置 VLAN',
vlan_col_name: '名称',
vlan_col_member: '成员端口',
vlan_col_tagged: 'Tagged 端口',
vlan_col_untagged: 'Untagged 端口',
vlan_col_pvid: 'PVID 端口',
vlan_col_delete: '删除',
vlan_set_id_first: '请先设置 VLAN ID',
vlan_delete_confirm: '删除 VLAN ',
lag_title: '链路聚合配置',
lag_heading: '链路聚合组配置',
lag_update: '更新 / 创建',
mirror_title: '端口镜像配置',
mirror_heading: '端口镜像配置',
mirror_enabled: '启用:',
mirror_port: '镜像目的端口:',
mirror_tx: '被镜像端口 (TX)',
mirror_rx: '被镜像端口 (RX)',
mirror_update: '更新 / 创建',
mirror_disable: '禁用端口镜像',
mirror_set_port_first: '请先设置镜像目的端口',
mirror_select_ports: '请选择被镜像端口',
eee_title: 'EEE 配置',
eee_heading: 'EEE 状态',
eee_advertising: '本端通告',
eee_partner: '链路伙伴通告',
eee_port: '端口',
eee_active: '已生效?',
eee_enable: '启用 EEE',
eee_disable: '禁用 EEE',
eee_on: '开',
eee_off: '关',
l2_title: 'FreeSwitchOS L2 配置',
l2_heading: 'L2 配置',
l2_col_port: '端口',
l2_col_type: '类型',
l2_col_remove: '删除条目',
l2_shown: 'Shown:',
l2_delete: '删除',
l2_static: '静态',
l2_learned: '动态学习',
bw_title: '入方向/出方向带宽限制',
bw_heading: '入方向/出方向带宽限制',
bw_ingress: '入方向',
bw_egress: '出方向',
bw_col_port: '端口',
bw_col_limit: '限速',
bw_col_bandwidth: '带宽 [kbit/s]',
bw_col_flow: '流量控制',
bw_col_apply: '应用',
bw_unlimited: '不限速',
sys_title: '系统设置',
sys_tab_system: '系统',
sys_tab_advanced: '高级',
sys_tab_console: '控制台',
sys_heading: '系统设置',
sys_ip: 'IP 地址:',
sys_model: '型号:',
sys_hostname: '主机名:',
sys_apply: '应用',
sys_netmask: '子网掩码:',
sys_gateway: '网关:',
sys_language: '语言:',
sys_mgmt_vlan: 'Management VLAN:',
sys_mgmt_untagged: 'untagged',
sys_mgmt_confirm: 'Move switch management to VLAN ',
sys_mgmt_warn: 'The switch will start tagging its own traffic with that VLAN. If the port you are connected through does not carry it, this page becomes unreachable and the setting can only be undone over the console. Continue?',
sys_ip_note: '更新上述设置后,请使用新的 IP 地址重新访问管理界面:',
sys_update: '更新设置',
sys_save_label: '将当前全部设置保存到 Flash:',
sys_save: '保存设置到 Flash',
sys_advanced: '高级设置',
sys_startup_config: '启动配置:',
sys_startup_warn: '直接编辑启动配置时请谨慎,错误配置可能导致无法访问设备:',
sys_clear_config: '清除启动配置',
sys_save_startup: '保存启动配置到 Flash',
sys_reset: '重启交换机',
sys_console: '控制台命令',
sys_enter_cmd: '输入命令:',
sys_send_cmd: '发送命令',
sys_console_warn: '输入控制台命令时请谨慎,错误命令可能导致无法访问设备!',
sys_invalid_ip: '无效 IP: ',
sys_reset_confirm: '确定要重启交换机吗?',
sys_resetting: '交换机正在重启。请稍候并刷新页面。',
login_title: 'RTL 交换机登录',
login_heading: 'RTL 交换机登录',
login_wrong: '密码错误!',
login_password: '密码',
login_login: '登录',
index_title: 'FreeSwitchOS 主页',
index_heading: '交换机配置',
index_settings: '设置',
update_title: '固件升级',
update_heading: '固件升级',
update_instruction: '请选择要上传的固件文件:',
update_upload: '上传文件',
common_port: '端口 ',
common_pkts: ' 个包',
}
};
var rtlLang = (function() {
var saved = localStorage.getItem('rtl_lang');
if (saved && LANG[saved]) return saved;
var browser = (navigator.language || navigator.userLanguage || 'en').substring(0, 2);
return LANG[browser] ? browser : 'en';
})();
function t(key) {
return LANG[rtlLang][key] || LANG['en'][key] || key;
}
function setLang(lang) {
if (LANG[lang]) {
localStorage.setItem('rtl_lang', lang);
rtlLang = lang;
document.querySelectorAll('[data-i18n]').forEach(function(el) {
applyTranslation(el);
});
}
}
function applyTranslation(el) {
var key = el.getAttribute('data-i18n');
if (!key) return;
if (el.tagName === 'INPUT' && (el.type === 'submit' || el.type === 'button')) {
el.value = t(key);
} else if (el.tagName === 'OPTION') {
el.textContent = t(key);
} else if (el.tagName === 'TITLE') {
el.textContent = t(key);
} else {
el.innerHTML = t(key);
}
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('[data-i18n]').forEach(function(el) {
applyTranslation(el);
});
});
+3 -4
View File
@@ -2,7 +2,6 @@
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/main_info.js"></script> <script src="/main_info.js"></script>
<script src="/i18n.js"></script>
<script> <script>
window.addEventListener("load", function() { window.addEventListener("load", function() {
update( () => { update( () => {
@@ -11,17 +10,17 @@
}); });
</script> </script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="index_title">FreeSwitchOS Main Page</title> <title>FreeSwitchOS Main Page</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="index_heading">Switch Configuration</h1> <h1>Switch Configuration</h1>
<table id="infoTable"> <table id="infoTable">
<tr> <tr>
<th colspan="2" data-i18n="index_settings">Settings</th> <th colspan="2">Settings</th>
</tr> </tr>
<tbody> <tbody>
</tbody> </tbody>
+3 -14
View File
@@ -1,27 +1,16 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="l2_title">FreeSwitchOS L2 Configuration</title> <title>FreeSwitchOS L2 Configuration</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="l2_heading">L2 Configuration</h1> <h1>L2 Configuration</h1>
<p><span data-i18n="l2_shown">Shown:</span> <span id="l2count">-</span></p>
<table id="l2table"> <table id="l2table">
<tr> <tr> <th>Port</th> <th>MAC</th> <th>VLAN</th> <th>Type</th> <th>Remove Entry</th></tr>
<th><span class="l2sort" onclick="l2SortBy('port')"><span data-i18n="l2_col_port">Port</span><span id="l2a_port" class="l2arrow"></span></span><br>
<input id="l2f_port" class="l2filter" oninput="l2FilterChanged()" size="5"></th>
<th><span class="l2sort" onclick="l2SortBy('mac')">MAC<span id="l2a_mac" class="l2arrow"></span></span><br>
<input id="l2f_mac" class="l2filter" oninput="l2FilterChanged()" size="14"></th>
<th><span class="l2sort" onclick="l2SortBy('vlan')">VLAN<span id="l2a_vlan" class="l2arrow"></span></span><br>
<input id="l2f_vlan" class="l2filter" oninput="l2FilterChanged()" size="5"></th>
<th><span class="l2sort" onclick="l2SortBy('type')"><span data-i18n="l2_col_type">Type</span><span id="l2a_type" class="l2arrow"></span></span><br>
<input id="l2f_type" class="l2filter" oninput="l2FilterChanged()" size="8"></th>
<th data-i18n="l2_col_remove">Remove Entry</th></tr>
<script src="/l2.js"></script> <script src="/l2.js"></script>
</table> </table>
</div> </div>
+54 -72
View File
@@ -1,3 +1,7 @@
var l2GetInterval;
var l2Entries = [];
var l2CurrentEntry = 0;
function fillStats() { function fillStats() {
var tbl = document.getElementById('statstable'); var tbl = document.getElementById('statstable');
if (!numPorts) if (!numPorts)
@@ -5,22 +9,22 @@ function fillStats() {
if (tbl.rows.length > 1) { if (tbl.rows.length > 1) {
for (let i = 0; i < numPorts; i++) { for (let i = 0; i < numPorts; i++) {
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]); console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
tbl.rows[i+1].cells[1].innerHTML = linkText(pState[i]+1); tbl.rows[i+1].cells[1].innerHTML = `${linkS[pState[i]+1]}`;
tbl.rows[i+1].cells[2].innerHTML = `${txG[i]}` + t('common_pkts'); tbl.rows[i+1].cells[2].innerHTML = `${txG[i]} pkts`;
tbl.rows[i+1].cells[3].innerHTML = `${txB[i]}` + t('common_pkts'); tbl.rows[i+1].cells[3].innerHTML = `${txB[i]} pkts`;
tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]}` + t('common_pkts'); tbl.rows[i+1].cells[4].innerHTML = `${rxG[i]} pkts`;
tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]}` + t('common_pkts'); tbl.rows[i+1].cells[5].innerHTML = `${rxB[i]} pkts`;
} }
} else { } else {
for (let i = 0; i < numPorts; i++) { for (let i = 0; i < numPorts; i++) {
console.log("Table row: " + i); console.log("Table row: " + i);
const tr = tbl.insertRow(); const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i+1))); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`));
td = tr.insertCell(); td.appendChild(document.createTextNode(linkText(pState[i]+1))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]}` + t('common_pkts'))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]}` + t('common_pkts'))); td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]}` + t('common_pkts'))); td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]}` + t('common_pkts'))); td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
} }
} }
} }
@@ -60,51 +64,6 @@ function delL2(idx) {
xhttp.timeout = 1500; xhttp.send(); xhttp.timeout = 1500; xhttp.send();
} }
var l2All = [];
const l2Cols = ['port', 'mac', 'vlan', 'type'];
var l2SortCol = 'port';
var l2SortDir = 1;
function l2Key(e, col) {
if (col === 'port') return e.port === 'CPU' ? Number.MAX_SAFE_INTEGER : Number(e.port);
if (col === 'vlan') return Number(e.vlan);
return String(e[col]).toLowerCase();
}
function l2SortBy(col) {
l2SortDir = (col === l2SortCol) ? -l2SortDir : 1;
l2SortCol = col;
renderL2();
}
function l2FilterChanged() { renderL2(); }
function renderL2() {
var tbl = document.getElementById('l2table');
if (!tbl) return;
var f = {};
l2Cols.forEach(function(c) {
var el = document.getElementById('l2f_' + c);
f[c] = el ? el.value.trim().toLowerCase() : '';
});
var rows = l2All.filter(function(e) {
return l2Cols.every(function(c) {
return !f[c] || String(e[c]).toLowerCase().indexOf(f[c]) !== -1;
});
});
rows.sort(function(a, b) {
var x = l2Key(a, l2SortCol), y = l2Key(b, l2SortCol);
return (x < y ? -1 : x > y ? 1 : 0) * l2SortDir;
});
l2Cols.forEach(function(c) {
var a = document.getElementById('l2a_' + c);
if (a) a.textContent = (c === l2SortCol) ? (l2SortDir > 0 ? ' \u25b2' : ' \u25bc') : ' \u21c5';
});
paintL2(tbl, rows);
var cnt = document.getElementById('l2count');
if (cnt) cnt.textContent = rows.length + ' / ' + l2All.length;
}
function fillL2(s) function fillL2(s)
{ {
var tbl = document.getElementById('l2table'); var tbl = document.getElementById('l2table');
@@ -112,12 +71,7 @@ function fillL2(s)
return; return;
s.sort(l2CMP); s.sort(l2CMP);
s = uniq(s); s = uniq(s);
l2All = s; var s = s.map(function(e) { e.port = e.port != 9 ? e.port : "CPU"; return e; });
renderL2();
}
function paintL2(tbl, s)
{
console.log("L2: ", JSON.stringify(s)); console.log("L2: ", JSON.stringify(s));
for (let i = 0; i < s.length; i++) { for (let i = 0; i < s.length; i++) {
var e = s[i]; var e = s[i];
@@ -126,36 +80,64 @@ function paintL2(tbl, s)
tbl.rows[i+1].cells[0].innerHTML = `${e.port}`; tbl.rows[i+1].cells[0].innerHTML = `${e.port}`;
tbl.rows[i+1].cells[1].innerHTML = `${e.mac}`; tbl.rows[i+1].cells[1].innerHTML = `${e.mac}`;
tbl.rows[i+1].cells[2].innerHTML = `${e.vlan}`; tbl.rows[i+1].cells[2].innerHTML = `${e.vlan}`;
tbl.rows[i+1].cells[3].innerHTML = `${e.type}`; tbl.rows[i+1].cells[4].innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">Delete</button>';
tbl.rows[i+1].cells[4].innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">' + t('l2_delete') + '</button>';
} else { } else {
const tr = tbl.insertRow(); const tr = tbl.insertRow();
let td = tr.insertCell(); td.innerHTML = `${e.port}`; let td = tr.insertCell(); td.innerHTML = `${e.port}`;
td = tr.insertCell(); td.innerHTML = `${e.mac}`; td = tr.insertCell(); td.innerHTML = `${e.mac}`;
td = tr.insertCell(); td.innerHTML = `${e.vlan}`; td = tr.insertCell(); td.innerHTML = `${e.vlan}`;
td = tr.insertCell(); td.innerHTML = `${e.type}`; td = tr.insertCell(); td.innerHTML = `${e.type}`;
td = tr.insertCell(); td.innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">' + t('l2_delete') + '</button>'; td = tr.insertCell(); td.innerHTML = '<button type="button" onclick="delL2(' + e.idx + ');">Delete</button>';
} }
} }
for (let i = tbl.rows.length - 1; i > s.length; i--) for (let i = tbl.rows.length - 1; i > s.length; i--)
tbl.deleteRow(i); tbl.deleteRow(i);
l2Entries = [];
} }
function getL2() { function getL2() {
walkL2(function(entries, ok) { var xhttp = new XMLHttpRequest();
if (ok) { xhttp.onreadystatechange = function() {
for (var i = 0; i < entries.length; i++) if (this.readyState == 4 && this.status == 200) {
entries[i].type = entries[i].type == "s" ? t('l2_static') : t('l2_learned'); var s = JSON.parse(xhttp.responseText);
fillL2(entries); var s = s.map(function(e) {
e.vlan = parseInt(e.vlan, 16);
e.idx = parseInt(e.idx, 16);
e.type = e.type == "s" ? "static" : "learned";
e.port = e.port == 9 ? 9 : logToPhysPort[e.port];
return e;
});
l2Entries.push(...s);
if (l2Entries >= 4096) {
l2Entries = [];
l2CurrentEntry = 0;
clearInterval(l2GetInterval);
return;
}
var w = 0;
for (var i = l2Entries.length-1; i > 0; i--) {
if (l2Entries[0].idx == l2Entries[i].idx) {
w = 1;
break;
}
}
if (w) {
l2CurrentEntry = 0;
fillL2(l2Entries);
} else {
l2CurrentEntry = s[s.length-1].idx + 1;
}
} }
setTimeout(getL2, 1000); };
}); xhttp.open("GET", "/l2.json?idx=" + l2CurrentEntry, true);
xhttp.timeout = 1500; sendXHTTP(xhttp);
} }
window.addEventListener("load", function() { window.addEventListener("load", function() {
update( () => { update( () => {
getL2(); getL2();
const interval = setInterval(update, 2000); const interval = setInterval(update, 2000);
l2GetInterval = setInterval(getL2, 1000);
});; });;
}); });
+6 -7
View File
@@ -1,25 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="lag_title">Link Aggregation Configuration</title> <title>Link Aggregation Configuration</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="lag_heading">Link Aggregation Groups Configuration</h1> <h1>Link Aggregation Groups Configuration</h1>
<h2>LAG 1 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub0" onclick="lagSub(0);" type="button" data-i18n="lag_update" value="Update / Create"></h2> <h2>LAG 1 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub0" onclick="lagSub(0);" type="button" value="Update / Create"></h2>
<div id="mLAG0"></div> <div id="mLAG0"></div>
<br /> <br />
<h2>LAG 2 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub1" onclick="lagSub(1);" type="button" data-i18n="lag_update" value="Update / Create"></h2> <h2>LAG 2 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub1" onclick="lagSub(1);" type="button" value="Update / Create"></h2>
<div id="mLAG1"></div> <div id="mLAG1"></div>
<br /> <br />
<h2>LAG 3 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub2" onclick="lagSub(2);" type="button" data-i18n="lag_update" value="Update / Create"></h2> <h2>LAG 3 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub2" onclick="lagSub(2);" type="button" value="Update / Create"></h2>
<div id="mLAG2"></div> <div id="mLAG2"></div>
<br /> <br />
<h2>LAG 4 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub3" onclick="lagSub(3);" type="button" data-i18n="lag_update" value="Update / Create"></h2> <h2>LAG 4 <input style="width:15%;margin-left: 3em;" class="action" id="l_sub3" onclick="lagSub(3);" type="button" value="Update / Create"></h2>
<div id="mLAG3"></div> <div id="mLAG3"></div>
<script src="/lag.js"></script> <script src="/lag.js"></script>
</div> </div>
+8 -8
View File
@@ -1,30 +1,30 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<title data-i18n="login_title">RTL Switch Login</title> <title>RTL Switch Login</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script src="/i18n.js"></script>
<script> <script>
function removeNote() { function removeNote() {
document.getElementById("incorrect").innerHTML = ""; document.getElementById("incorrect").innerHTML = "";
} }
window.addEventListener("load", function() { window.addEventListener("load", function() {
if (document.referrer.endsWith("login.html")) if (document.referrer.endsWith("login.html"))
document.getElementById("incorrect").innerHTML = t('login_wrong'); document.getElementById("incorrect").innerHTML = "Wrong password!";
}); });
</script> </script>
</head> </head>
<body class="login_page"> <body class="login_page">
<div class = "center"> <div class = "center">
<h1 data-i18n="login_heading"> RTL Switch Login</h1> <h1> RTL Switch Login</h1>
<form method="post" action="login"> <form method="post" action="login">
<div class="txt_field"> <div class="txt_field">
<input name="pwd" type="password" autocomplete="current-password" onclick="removeNote()" required /> <input name="pwd" type="password" onclick="removeNote()" required />
<span></span> <span></span>
<label data-i18n="login_password">Password</label> <label>Password</label>
</div> </div>
<input type="submit" data-i18n="login_login" value="Login"/> <input type="submit" value="Login"/>
<h3 id="incorrect" style="margin-top: 5em;"></h3> <h3 id="incorrect" style="margin-top: 5em;"></h3>
</form> </form>
</body> </body>
</html> </html>
+17 -83
View File
@@ -2,12 +2,11 @@ var txG = new BigInt64Array(10);
var txB = new BigInt64Array(10); var txB = new BigInt64Array(10);
var rxG = new BigInt64Array(10); var rxG = new BigInt64Array(10);
var rxB = new BigInt64Array(10); var rxB = new BigInt64Array(10);
const linkS = [function(){return t('speed_disabled')}, function(){return t('speed_down')}, "10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"]; const linkS = ["Disabled", "Down", "10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"];
var pState = new Int8Array(10); var pState = new Int8Array(10);
var pIsSFP = new Int8Array(10); var pIsSFP = new Int8Array(10);
var pAdvertised = new Int8Array(10); var pAdvertised = new Int8Array(10);
var numPorts = 0; var numPorts = 0;
function linkText(idx) { var v = linkS[idx]; return typeof v === 'function' ? v() : v; }
var logToPhysPort = new Int8Array(10); var logToPhysPort = new Int8Array(10);
var physToLogPort = new Int8Array(10); var physToLogPort = new Int8Array(10);
var portNames = new Array(10); var portNames = new Array(10);
@@ -22,7 +21,7 @@ function drawPorts() {
d.classList.add('tooltip'); d.classList.add('tooltip');
const s = document.createElement("span"); const s = document.createElement("span");
s.classList.add("tooltiptext"); s.classList.add("tooltiptext");
s.innerHTML = t('common_port'); s.innerHTML = "Tooltip text";
s.id="tt_" + (i+1); s.id="tt_" + (i+1);
const l = document.createElement("object"); const l = document.createElement("object");
d.appendChild(l); d.appendChild(l);
@@ -153,21 +152,19 @@ function update(callback) {
continue; continue;
const portName = p.name || portNames[p.logPort] || ''; const portName = p.name || portNames[p.logPort] || '';
var iHTML = "<table border=\"0\" class=\"tt_table\">"; var iHTML = "<table border=\"0\" class=\"tt_table\">";
if (portName) iHTML += "<tr><td align=\"left\">" + t('port_name') + "</td><td>:</td><td>" + portName + "</td></tr>"; if (portName) iHTML += "<tr><td align=\"left\">Name</td><td>:</td><td>" + portName + "</td></tr>";
if (p.enabled == 0) { if (p.enabled == 0) {
pState[n] = -1; pState[n] = -1;
bgs[0].style.fill = "red"; bgs[0].style.fill = "red";
leds[0].style.fill = "black"; leds[1].style.fill = "black"; leds[0].style.fill = "black"; leds[1].style.fill = "black";
psvg.style.opacity = 0.4; psvg.style.opacity = 0.4;
iHTML += "<tr><td align=\"left\">" + t('port_status') + "</td><td>:</td><td>" + t('port_not_enabled') + "</td></tr>"; iHTML += "<tr><td align=\"left\">Status</td><td>:</td><td>Not enabled.</td></tr>";
iHTML += "</table>"; iHTML += "</table>";
tt.innerHTML = iHTML; tt.innerHTML = iHTML;
} else { } else {
psvg.style.opacity = 1.0; psvg.style.opacity = 1.0;
pState[n] = p.link; pState[n] = p.link;
if (p.link == 5 || p.link == 7) { if (p.link == 4 || p.link == 5 || p.link == 6) {
leds[0].style.fill = "green"; leds[1].style.fill = "blue";
} else if (p.link == 4 || p.link == 6) {
leds[0].style.fill = "green"; leds[1].style.fill = "orange"; leds[0].style.fill = "green"; leds[1].style.fill = "orange";
} else if (p.link == 1 || p.link == 2 || p.link == 3) { } else if (p.link == 1 || p.link == 2 || p.link == 3) {
leds[0].style.fill = "green"; leds[1].style.fill = "green"; leds[0].style.fill = "green"; leds[1].style.fill = "green";
@@ -175,31 +172,31 @@ function update(callback) {
leds[0].style.fill = "black"; leds[1].style.fill = "black"; leds[0].style.fill = "black"; leds[1].style.fill = "black";
psvg.style.opacity = 0.4 psvg.style.opacity = 0.4
} }
iHTML += "<tr><td align=\"left\">" + t('port_link_speed') + "</td><td>:</td><td>" + linkText(p.link + 1) + "</td></tr>"; iHTML += "<tr><td align=\"left\">Link speed</td><td>:</td><td>" + linkS[p.link + 1] + "</td></tr>";
if (p.isSFP) { if (p.isSFP) {
pAdvertised[n] = 0; pAdvertised[n] = 0;
const hasExtendedStatus = p.sfp_options & 0x40; const hasExtendedStatus = p.sfp_options & 0x40;
iHTML += "<tr><td>" + t('port_vendor') + "</td><td>:</td><td>" + p.sfp_vendor + "</td></tr>"; iHTML += "<tr><td>Vendor</td><td>:</td><td>" + p.sfp_vendor + "</td></tr>";
iHTML += "<tr><td>" + t('port_model') + "</td><td>:</td><td>" + p.sfp_model + "</td></tr>"; iHTML += "<tr><td>Model</td><td>:</td><td>" + p.sfp_model + "</td></tr>";
iHTML += "<tr><td>" + t('port_serial') + "</td><td>:</td><td>" + p.sfp_serial + "</td></tr>"; iHTML += "<tr><td>Serial</td><td>:</td><td>" + p.sfp_serial + "</td></tr>";
if (hasExtendedStatus) { if (hasExtendedStatus) {
let txPower = decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal); let txPower = decodeSfpTxPower(p.sfp_txpower, p.sfp_txpower_cal);
let txPowerdBm = convertPowerTodBm(txPower); let txPowerdBm = convertPowerTodBm(txPower);
let rxPower = decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal); let rxPower = decodeSfpRxPower(p.sfp_rxpower, p.sfp_rxpower_cal);
let rxPowerdBm = convertPowerTodBm(rxPower); let rxPowerdBm = convertPowerTodBm(rxPower);
iHTML += "<tr><td>" + t('port_temp') + "</td><td>:</td><td>" + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + "&#8239;&#8451;</td></tr>"; iHTML += "<tr><td>Temp</td><td>:</td><td>" + decodeSfpTemp(p.sfp_temp, p.sfp_temp_cal).toFixed(2) + "&#8239;&#8451;</td></tr>";
iHTML += "<tr><td>" + t('port_vcc') + "</td><td>:</td><td>" + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + "&#8239;V</td></tr>"; iHTML += "<tr><td>Vcc</td><td>:</td><td>" + decodeSfpVcc(p.sfp_vcc, p.sfp_vcc_cal).toFixed(2) + "&#8239;V</td></tr>";
iHTML += "<tr><td>" + t('port_tx_fault') + "</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>"; iHTML += "<tr><td>TX-Fault</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x4)) + "</td></tr>";
iHTML += "<tr><td>" + t('port_tx_disabled') + "</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>"; iHTML += "<tr><td>TX-Disabled</td><td>:</td><td>" + (Boolean(Number(p.sfp_state) & 0x80)) + "</td></tr>";
iHTML += "<tr><td>" + t('port_tx_bias') + "</td><td>:</td><td>" + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + "&#8239;mA</td></tr>"; iHTML += "<tr><td>TX-Bias</td><td>:</td><td>" + decodeSfpTxBias(p.sfp_txbias, p.sfp_txbias_cal).toFixed(1) + "&#8239;mA</td></tr>";
iHTML += "<tr><td>" + t('port_tx_power') + "</td><td>:</td><td>" + txPower.toFixed(3) + "&#8239;mW / " + txPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>"; iHTML += "<tr><td>TX-Power</td><td>:</td><td>" + txPower.toFixed(3) + "&#8239;mW / " + txPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>";
iHTML += "<tr><td>" + t('port_rx_power') + "</td><td>:</td><td>" + rxPower.toFixed(3) + "&#8239;mW / " + rxPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>"; iHTML += "<tr><td>RX-Power</td><td>:</td><td>" + rxPower.toFixed(3) + "&#8239;mW / " + rxPowerdBm.toFixed(2) + "&#8239;dBm</td></tr>";
} }
// Not all devices & modules have LOS pin... // Not all devices & modules have LOS pin...
const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null; const rx_los_pin = p.sfp_los !== null ? Boolean(Number(p.sfp_los)) : null;
const rx_los_module = hasExtendedStatus ? Boolean(Number(p.sfp_state) & 0x2) : null; const rx_los_module = hasExtendedStatus ? Boolean(Number(p.sfp_state) & 0x2) : null;
if (rx_los_module !== null || rx_los_pin !== null) { if (rx_los_module !== null || rx_los_pin !== null) {
iHTML += `<tr><td>` + t('port_rx_los') + `</td><td>:</td><td>${rxLosHTML(rx_los_pin, rx_los_module)}</td></tr>`; iHTML += `<tr><td>RX-LOS</td><td>:</td><td>${rxLosHTML(rx_los_pin, rx_los_module)}</td></tr>`;
} }
} else { } else {
pAdvertised[n] = parseInt(p.adv, 2); pAdvertised[n] = parseInt(p.adv, 2);
@@ -285,66 +282,3 @@ function sendXHTTP(x)
currentRequests.push(x); currentRequests.push(x);
} }
function walkL2(onDone)
{
var entries = [];
var idx = 0;
var tries = 0;
function retry() {
if (++tries < 3) {
setTimeout(page, 1000);
return;
}
onDone(entries, false);
}
function page() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState != 4)
return;
if (this.status != 200) {
retry();
return;
}
var s;
try {
s = JSON.parse(xhttp.responseText);
} catch (err) {
retry();
return;
}
tries = 0;
s = s.map(function(e) {
e.vlan = parseInt(e.vlan, 16);
e.idx = parseInt(e.idx, 16);
e.port = e.port == 9 ? 'CPU' : logToPhysPort[e.port];
return e;
});
if (!s.length) {
onDone(entries, true);
return;
}
entries.push(...s);
for (var i = entries.length - 1; i > 0; i--) {
if (entries[0].idx == entries[i].idx) {
onDone(entries, true);
return;
}
}
if (entries.length >= 4096) {
onDone(entries, true);
return;
}
idx = s[s.length - 1].idx + 1;
setTimeout(page, 1000);
};
xhttp.open("GET", "/l2.json?idx=" + idx, true);
xhttp.timeout = 1500;
sendXHTTP(xhttp);
}
page();
}
+8 -9
View File
@@ -1,24 +1,23 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="mirror_title">Mirror Configuration</title> <title>Mirror Configuration</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="mirror_heading">Mirror Configuration</h1> <h1>Mirror Configuration</h1>
<label class="tswitch"><span data-i18n="mirror_enabled">Enabled:</span> <input id="me" type="checkbox"></label><br/> <label class="tswitch">Enabled: <input id="me" type="checkbox"></label><br/>
<label for="mp"><span data-i18n="mirror_port">Mirroring Port:</span></label> <input type="number" id="mp" name="mp" min="1" max="9"/> <label for="mp">Mirroring Port:</label> <input type="number" id="mp" name="mp" min="1" max="9"/>
<h2 data-i18n="mirror_tx">Mirrored Ports (TX)</h2> <h2>Mirrored Ports (TX)</h2>
<div id="mPortsTX"></div> <div id="mPortsTX"></div>
<br /> <br />
<h2 data-i18n="mirror_rx">Mirrored Ports (RX)</h2> <h2>Mirrored Ports (RX)</h2>
<div id="mPortsRX"></div> <div id="mPortsRX"></div>
<br/> <input style="width:15%;" class="action" id="mirror_sub" onclick="mirrorSub();" type="button" data-i18n="mirror_update" value="Update / Create"> <br/> <input style="width:15%;" class="action" id="mirror_sub" onclick="mirrorSub();" type="button" value="Update / Create">
<input style="width:15%;" class="action" id="mirror_del" onclick="mirrorDel();" type="button" data-i18n="mirror_disable" value="Disable Mirroring"> <input style="width:15%;" class="action" id="mirror_del" onclick="mirrorDel();" type="button" value="Disable Mirroring">
<script src="/mirror.js"></script> <script src="/mirror.js"></script>
<script src="/mirror_sub.js"></script> <script src="/mirror_sub.js"></script>
</div> </div>
+2 -2
View File
@@ -2,7 +2,7 @@ async function mirrorSub() {
var cmd = "mirror "; var cmd = "mirror ";
var mp=document.getElementById('mp').value var mp=document.getElementById('mp').value
if (!mp) { if (!mp) {
alert(t('mirror_set_port_first')); alert("Set Mirroring Port first");
return; return;
} }
document.getElementById(mirrors[0]+mp).checked=false;document.getElementById(mirrors[1]+mp).checked=false; document.getElementById(mirrors[0]+mp).checked=false;document.getElementById(mirrors[1]+mp).checked=false;
@@ -16,7 +16,7 @@ async function mirrorSub() {
cmd = cmd + ` ${i}r`; cmd = cmd + ` ${i}r`;
} }
if (cmd.length < 10) { if (cmd.length < 10) {
alert(t('mirror_select_ports')); alert("Select Mirrored Ports");
return; return;
} }
try { try {
+11 -19
View File
@@ -1,20 +1,12 @@
document.getElementById('sidebar').innerHTML = document.getElementById('sidebar').innerHTML =
"<ul><li><a href='index.html' data-i18n='nav_overview'>Overview</a></li>" "<ul><li><a href='index.html'>Overview</a></li>"
+ "<li><a href='ports.html' data-i18n='nav_port_config'>Port Configuration</a></li>" + "<li><a href='ports.html'>Port Configuration</a></li>"
+ "<li><a href='stat.html' data-i18n='nav_port_stat'>Port Statistics</a></li>" + "<li><a href='stat.html'>Port Statistics</a></li>"
+ "<li><a href='vlan.html' >VLAN</a></li>" + "<li><a href='vlan.html'>VLAN</a></li>"
+ "<li><a href='l2.html' data-i18n='nav_l2'>L2 Configuration</a></li>" + "<li><a href='l2.html'>L2 Configuration</a></li>"
+ "<li><a href='mirror.html' data-i18n='nav_mirror'>Mirroring</a></li>" + "<li><a href='mirror.html'>Mirroring</a></li>"
+ "<li><a href='lag.html' data-i18n='nav_lag'>Link Aggregation</a></li>" + "<li><a href='lag.html'>Link Aggregation</a></li>"
+ "<li><a href='eee.html' data-i18n='nav_eee'>EEE</a></li>" + "<li><a href='eee.html'>EEE</a></li>"
+ "<li><a href='bandwidth.html' data-i18n='nav_bandwidth'>Bandwidth Limits</a></li>" + "<li><a href='bandwidth.html'>Bandwidth Limits</a></li>"
+ "<li><a href='system.html' data-i18n='nav_system'>System Settings</a></li>" + "<li><a href='system.html'>System Settings</a></li>"
+ "<li><a href='update.html' data-i18n='nav_fw_update'>Firmware Update</a></li></ul>"; + "<li><a href='update.html'>Firmware Update</a></li></ul>";
document.addEventListener('DOMContentLoaded', function() {
var links = document.querySelectorAll('#sidebar a[data-i18n]');
links.forEach(function(el) {
var key = el.getAttribute('data-i18n');
if (key) el.textContent = t(key);
});
});
+4 -5
View File
@@ -1,20 +1,19 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="port_title">FreeSwitchOS Port Configuration</title> <title>FreeSwitchOS Port Configuration</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="port_heading">Port Configuration</h1> <h1>Port Configuration</h1>
<form id="vform" action="/vlan.html"> <form id="vform" action="/vlan.html">
<table id="speedtable"> <table id="speedtable">
<tr> <th data-i18n="port_col_port">Port</th> <th data-i18n="port_col_name">Name</th> <th data-i18n="port_col_speed">Current Link Speed</th><th data-i18n="port_col_set_speed">Set Speed</th><th data-i18n="port_col_disabled">Disabled</th><th data-i18n="port_col_apply">Apply</th></tr> <tr> <th>Port</th> <th>Name</th> <th>Current Link Speed</th><th>Set Speed</th><th>Disabled</th><th>Apply</th></tr>
</table> </table>
<h2 style="margin-top:3em" data-i18n="port_mtu_heading">Configure Maximum Frame Size (MTU) forwarded at Port</h2> <h2 style="margin-top:3em">Configure Maximum Frame Size (MTU) forwarded at Port</h2>
<table id="mtutable" style="margin-top:1em"> <table id="mtutable" style="margin-top:1em">
</table> </table>
<script src="/ports.js"></script> <script src="/ports.js"></script>
+14 -14
View File
@@ -3,29 +3,29 @@ var clicked = new Int8Array(10);
function createPortTable() { function createPortTable() {
var tbl = document.getElementById('speedtable'); var tbl = document.getElementById('speedtable');
if (tbl.rows.length <= 2 && numPorts) { if (tbl.rows.length <= 2 && numPorts) {
const sSelect = '<select name="speed_sel" id="speed_sel">' const sSelect = '<select name="speed_sel" id="speed_sel">'
+ '<option value="auto">' + t('port_auto') + '</option>' + '<option value="auto">Auto</option>'
+ '<option value="2g5">' + t('port_2500m') + '</option>' + '<option value="2g5">2500MBit/Full</option>'
+ '<option value="1g">' + t('port_1000m') + '</option>' + '<option value="1g">1000MBit/Full</option>'
+ '<option value="100m full">' + t('port_100m_f') + '</option>' + '<option value="100m full">100MBit/Full</option>'
+ '<option value="100m half">' + t('port_100m_h') + '</option>' + '<option value="100m half">100MBit/Half</option>'
+ '<option value="10m full">' + t('port_10m_f') + '</option>' + '<option value="10m full">10MBit/Full</option>'
+ '<option value="10m half">' + t('port_10m_h') + '</option>' + '<option value="10m half">10MBit/Half</option>'
+ '</select>'; + '</select>';
const dSwitch = '<input type="checkbox" id="disable_port" onchange="portOnOff();">' const dSwitch = '<input type="checkbox" id="disable_port" onchange="portOnOff();">'
for (let i = 1; i <= numPorts; i++) { for (let i = 1; i <= numPorts; i++) {
if (pIsSFP[i-1]) if (pIsSFP[i-1])
continue; continue;
console.log("Table row: " + i + "pState: " + pState[i-2]); console.log("Table row: " + i + "pState: " + pState[i-2]);
const tr = tbl.insertRow(); const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + i)); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i}`));
let portName = portNames[physToLogPort[i-1]] || ''; let portName = portNames[physToLogPort[i-1]] || '';
td = tr.insertCell(); td.appendChild(document.createTextNode(portName)); td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
td = tr.insertCell(); td.innerHTML = linkText(pState[i] + 1); td = tr.insertCell(); td.innerHTML = linkS[pState[i] + 1];
td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i); td = tr.insertCell(); td.innerHTML = sSelect.replaceAll("speed_sel", "speed_sel_" + i);
td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i) td = tr.insertCell(); td.innerHTML = dSwitch.replaceAll("disable_port", "disable_port_" + i)
.replace("portOnOff()", "portOnOff(" + i + ")"); .replace("portOnOff()", "portOnOff(" + i + ")");
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="applySpeed(' + i + ');">' + t('port_apply') + '</button>'; var button = '<button type="button" style="margin: 0 0 0 24px" onclick="applySpeed(' + i + ');">Apply</button>';
td = tr.insertCell(); td = tr.insertCell();
td.innerHTML = button; td.innerHTML = button;
} }
@@ -55,7 +55,7 @@ function createPortTable() {
tr = tbl.insertRow(); tr = tbl.insertRow();
for (let i = 1; i <= numPorts; i++) { for (let i = 1; i <= numPorts; i++) {
let td = tr.insertCell(); let td = tr.insertCell();
td.innerHTML = '<button type="button" style="margin: 0 0 0 24px" onclick="applyMTU(' + i + ');">' + t('port_apply') + '</button>'; td.innerHTML = '<button type="button" style="margin: 0 0 0 24px" onclick="applyMTU(' + i + ');">Apply</button>';
} }
} }
} }
@@ -68,7 +68,7 @@ function updatePortTable() {
for (let i = 1; i <= numPorts ; i++) { for (let i = 1; i <= numPorts ; i++) {
if (pIsSFP[i-1]) if (pIsSFP[i-1])
continue; continue;
tbl.rows[i].cells[2].innerHTML = linkText(pState[i-1]+1); tbl.rows[i].cells[2].innerHTML = `${linkS[pState[i-1]+1]}`;
if (!clicked[i] && pState[i - 1] < 0) { if (!clicked[i] && pState[i - 1] < 0) {
document.getElementById('speed_sel_' + i).disabled = true; document.getElementById('speed_sel_' + i).disabled = true;
document.getElementById('disable_port_' + i).checked = true; document.getElementById('disable_port_' + i).checked = true;
+5 -6
View File
@@ -1,9 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="stat_title">FreeSwitchOS Port Statistics</title> <title>FreeSwitchOS Port Statistics</title>
<style> <style>
.popup { .popup {
display: none; display: none;
@@ -32,14 +31,14 @@
<div id="ports"></div> <div id="ports"></div>
<div id="popup" class="popup"> <div id="popup" class="popup">
<div class="popup-content"> <div class="popup-content">
<h2 data-i18n="stat_detailed">Detailed Port Statistics</h2> <h2>Detailed Port Statistics</h2>
<div id="popup_text"></div> <div id="popup_text"></div>
<button id="closePopup" class="action" data-i18n="stat_close">Close</button> <button id="closePopup" class="action">Close</button>
</div> </div>
</div> </div>
<h1 data-i18n="stat_heading">Port Statistics</h1> <h1>Port Statistics</h1>
<table id="statstable"> <table id="statstable">
<tr> <th data-i18n="stat_col_port">Port</th> <th data-i18n="stat_col_name">Name</th> <th data-i18n="stat_col_link">link</th> <th data-i18n="stat_col_tx_good">TX Good</th> <th data-i18n="stat_col_tx_bad">TX Bad</th> <th data-i18n="stat_col_rx_good">RX Good</th> <th data-i18n="stat_col_rx_bad">RX Bad</th> <th data-i18n="stat_col_all"> All Counters </th></tr> <tr> <th>Port</th> <th>Name</th> <th>link</th> <th>TX Good</th> <th>TX Bad</th> <th>RX Good</th> <th>RX Bad</th> <th> All Counters </th></tr>
<script src="/stat.js"></script> <script src="/stat.js"></script>
</table> </table>
</div> </div>
+19 -19
View File
@@ -114,7 +114,7 @@ function getCounters(port) {
const s = JSON.parse(xhttp.responseText); const s = JSON.parse(xhttp.responseText);
console.log("Counters: ", JSON.stringify(s)); console.log("Counters: ", JSON.stringify(s));
const ptext = document.getElementById('popup_text'); const ptext = document.getElementById('popup_text');
var tableHtml = "<table style='width:100%'> <tr> <th>" + t('stat_counter') + "</th> <th>" + t('stat_value') + "</th> <th>" + t('stat_counter') + "</th> <th>" + t('stat_value') + "</th></tr> <tr>"; var t = "<table style='width:100%'> <tr> <th>Counter</th> <th>Value</th> <th>Counter</th> <th>Value</th></tr> <tr>";
console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length); console.log("Counter 0: ", BigInt(s[0]).toString(), " length: ", s.length);
var c = 0; var c = 0;
for (i = 0; i < mib_counters.length; i += 4) { for (i = 0; i < mib_counters.length; i += 4) {
@@ -125,28 +125,28 @@ function getCounters(port) {
} }
var count = BigInt(s[i/4]); var count = BigInt(s[i/4]);
if (mib_counters[i+1] == 8) { if (mib_counters[i+1] == 8) {
tableHtml += "<td>" + mib_counters[i] + "</td><td>" + count.toString() + "</td>"; t += "<td>" + mib_counters[i] + "</td><td>" + count.toString() + "</td>";
c += 1; c += 1;
} else if (mib_counters[i+1] == 4) { } else if (mib_counters[i+1] == 4) {
if (mib_counters[i] != "") { if (mib_counters[i] != "") {
tableHtml += "<td>" + mib_counters[i] + "</td><td>" + (count >> 32n).toString() + "</td>"; t += "<td>" + mib_counters[i] + "</td><td>" + (count >> 32n).toString() + "</td>";
c += 1; c += 1;
} }
if (c == 2) { if (c == 2) {
tableHtml += "</tr> <tr>"; t += "</tr> <tr>";
c = 0; c = 0;
} }
if (mib_counters[i+2] != "") { if (mib_counters[i+2] != "") {
tableHtml += "<td>" + mib_counters[i+2] + "</td><td>" + (count & 4294967295n).toString() + "</td>"; t += "<td>" + mib_counters[i+2] + "</td><td>" + (count & 4294967295n).toString() + "</td>";
c += 1; c += 1;
} }
} }
if (c == 2) { if (c == 2) {
tableHtml += "</tr> <tr>"; t += "</tr> <tr>";
c = 0; c = 0;
} }
} }
ptext.innerHTML = tableHtml + "</tr></table>"; ptext.innerHTML = t + "</tr></table>";
popup.style.display = 'flex'; popup.style.display = 'flex';
} }
}; };
@@ -162,25 +162,25 @@ function fillStats() {
if (tbl.rows.length > 1) { if (tbl.rows.length > 1) {
for (let i = 0; i < numPorts; i++) { for (let i = 0; i < numPorts; i++) {
console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]); console.log("Table Update row: " + i + " state " + pState[i] + " is " + linkS[pState[i] +1]);
tbl.rows[i+1].cells[2].innerHTML = linkText(pState[i]+1); tbl.rows[i+1].cells[2].innerHTML = `${linkS[pState[i]+1]}`;
tbl.rows[i+1].cells[3].innerHTML = `${txG[i]}` + t('common_pkts'); tbl.rows[i+1].cells[3].innerHTML = `${txG[i]} pkts`;
tbl.rows[i+1].cells[4].innerHTML = `${txB[i]}` + t('common_pkts'); tbl.rows[i+1].cells[4].innerHTML = `${txB[i]} pkts`;
tbl.rows[i+1].cells[5].innerHTML = `${rxG[i]}` + t('common_pkts'); tbl.rows[i+1].cells[5].innerHTML = `${rxG[i]} pkts`;
tbl.rows[i+1].cells[6].innerHTML = `${rxB[i]}` + t('common_pkts'); tbl.rows[i+1].cells[6].innerHTML = `${rxB[i]} pkts`;
} }
} else { } else {
for (let i = 0; i < numPorts; i++) { for (let i = 0; i < numPorts; i++) {
console.log("Table row: " + i); console.log("Table row: " + i);
const tr = tbl.insertRow(); const tr = tbl.insertRow();
let td = tr.insertCell(); td.appendChild(document.createTextNode(t('common_port') + (i+1))); let td = tr.insertCell(); td.appendChild(document.createTextNode(`Port ${i+1}`));
let portName = portNames[physToLogPort[i]] || ''; let portName = portNames[physToLogPort[i]] || '';
td = tr.insertCell(); td.appendChild(document.createTextNode(portName)); td = tr.insertCell(); td.appendChild(document.createTextNode(portName));
td = tr.insertCell(); td.appendChild(document.createTextNode(linkText(pState[i]+1))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${linkS[pState[i]+1]}`));
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]}` + t('common_pkts'))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${txG[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]}` + t('common_pkts'))); td = tr.insertCell();td.appendChild(document.createTextNode(`${txB[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]}` + t('common_pkts'))); td = tr.insertCell();td.appendChild(document.createTextNode(`${rxG[i]} pkts`));
td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]}` + t('common_pkts'))); td = tr.insertCell();td.appendChild(document.createTextNode(`${rxB[i]} pkts`));
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + i + ');">' + t('stat_show') + '</button>'; var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + i + ');">Show</button>';
td = tr.insertCell(); td.innerHTML = button; td = tr.insertCell(); td.innerHTML = button;
} }
} }
-7
View File
@@ -82,7 +82,6 @@ object, img {
.isNOK{ color: #900;} .isNOK{ color: #900;}
.isOK{ color: #090;} .isOK{ color: #090;}
.ip{padding:8px 16px;margin-bottom: 1em;margin-left: 1em} .ip{padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
.rotext{display:inline-block;padding:8px 16px;margin-bottom: 1em;margin-left: 1em}
.row {display: flex;} .row {display: flex;}
.rcol {flex: 90%;} .rcol {flex: 90%;}
.lcol {flex: 10%;} .lcol {flex: 10%;}
@@ -164,9 +163,3 @@ margin: 30px 0;
} }
select { text-align-last: right; font-family: monospace} select { text-align-last: right; font-family: monospace}
option { direction: rtl; font-family: sans-serif} option { direction: rtl; font-family: sans-serif}
#vlanTable td { text-align: left; }
.l2sort{cursor:pointer;user-select:none}
.l2sort:hover{text-decoration:underline}
.l2arrow{opacity:0.55;font-size:0.85em}
.l2filter{width:100%;box-sizing:border-box;font-weight:normal;font-size:0.9em}
+17 -52
View File
@@ -1,9 +1,8 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="sys_title">System Settings</title> <title>System Settings</title>
<style> <style>
.tab-bar { display: flex; border-bottom: 2px solid #226; margin-bottom: 0; margin-left: 16%; padding: 1px 16px; padding-bottom: 0; } .tab-bar { display: flex; border-bottom: 2px solid #226; margin-bottom: 0; margin-left: 16%; padding: 1px 16px; padding-bottom: 0; }
.tab-btn { padding: 10px 20px; background-color: #ddf; border: none; cursor: pointer; font-size: 1em; border-radius: 8px 8px 0 0; margin-right: 4px; } .tab-btn { padding: 10px 20px; background-color: #ddf; border: none; cursor: pointer; font-size: 1em; border-radius: 8px 8px 0 0; margin-right: 4px; }
@@ -15,80 +14,46 @@
</head> </head>
<body> <body>
<div class="tab-bar"> <div class="tab-bar">
<button class="tab-btn active" onclick="openTab(event, 'system-tab')" data-i18n="sys_tab_system">System</button> <button class="tab-btn active" onclick="openTab(event, 'system-tab')">System</button>
<button class="tab-btn" onclick="openTab(event, 'advanced-tab')" data-i18n="sys_tab_advanced">Advanced</button> <button class="tab-btn" onclick="openTab(event, 'advanced-tab')">Advanced</button>
<button class="tab-btn" onclick="openTab(event, 'console-tab')" data-i18n="sys_tab_console">Console</button>
</div> </div>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<div id="system-tab" class="tab-content active"> <div id="system-tab" class="tab-content active">
<h1 data-i18n="sys_heading">System Settings</h1> <h1>System Settings</h1>
<div class="row"> <div class="row">
<div class="lcol"> <label for="hostname" data-i18n="sys_hostname">Hostname:</label></div> <div class="lcol"> <label for="ip">IP address:</label></div>
<div class="rcol"> <input id="hostname" type="text" maxlength="23" size="20"/>
<button onclick="hostSub()" data-i18n="sys_apply">Apply</button></div>
</div>
<div class="row">
<div class="lcol"> <label data-i18n="sys_model">Model:</label></div>
<div class="rcol"><span id="model" class="rotext"></span></div>
</div>
<div class="row">
<div class="lcol"> <label for="ip" data-i18n="sys_ip">IP address:</label></div>
<div class="rcol"> <input id="ip" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div> <div class="rcol"> <input id="ip" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div> </div>
<div class="row"> <div class="row">
<div class="lcol"> <label for="netmask" data-i18n="sys_netmask">Netmask:</label></div> <div class="lcol"> <label for="netmask">Netmask:</label></div>
<div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div> <div class="rcol"><input id="netmask" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div> </div>
<div class="row"> <div class="row">
<div class="lcol"> <label for="gw" data-i18n="sys_gateway">Gateway:</label></div> <div class="lcol"> <label for="gw">Gateway:</label></div>
<div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div> <div class="rcol"><input id="gw" class="ip" type="text" minlength="7" maxlength="15" size="15"/></div>
</div> </div>
<div class="row">
<div class="lcol"> <label for="mgmtvlan" data-i18n="sys_mgmt_vlan">Management VLAN:</label></div>
<div class="rcol"><select id="mgmtvlan" class="ip" onchange="mgmtVlanChanged()"></select></div>
</div>
<div class="row">
<div class="lcol"> <label data-i18n="sys_language">Language:</label></div>
<div class="rcol">
<select id="lang-select" onchange="changeLang()">
<option value="en">English</option>
<option value="ja">日本語</option>
<option value="zh">中文</option>
</select>
</div>
</div>
<br/> <br/>
<span data-i18n="sys_ip_note">When updating the above settings, remember to point your browser to the new IP afterwards:</span><br/> When updating the above settings, remember to point your browser to the new IP afterwards:<br/>
<input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" data-i18n="sys_update" value="Update Settings"><br/> <input style="width:40%;" class="action" id="ip_sub" onclick="ipSub();" type="button" value="Update Settings"><br/>
<br/> <br/>
<span data-i18n="sys_save_label">Save all current settings to Flash:</span><br/> Save all current settings to Flash:<br/>
<input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" data-i18n="sys_save" value="Save Settings to Flash"> <input style="width:40%;" class="action" id="flash_sub" onclick="flashSave();" type="button" value="Save Settings to Flash">
</div> </div>
<div id="advanced-tab" class="tab-content"> <div id="advanced-tab" class="tab-content">
<h1 data-i18n="sys_advanced">Advanced Settings</h1> <h1>Advanced Settings</h1>
<div class="lcol"> <label for="config_display" data-i18n="sys_startup_config">Startup configuration:</label></div> <div class="lcol"> <label for="config_display">Startup configuration:</label></div>
<textarea id="config_display" rows="8" cols="60"></textarea> <textarea id="config_display" rows="8" cols="60"></textarea>
<br/><br/> <br/><br/>
<span data-i18n="sys_startup_warn">Be careful when saving the directly edited startup configuration, you can lock yourself out:</span><br/> Be careful when saving the directly edited startup configuration, you can lock yourself out:<br/>
<input style="width:40%;" class="action" id="clear_config" onclick="clearConfig();" type="button" data-i18n="sys_clear_config" value="Clear Startup Config"> <input style="width:40%;" class="action" id="clear_config" onclick="clearConfig();" type="button" value="Clear Startup Config">
<br/> <br/>
<input style="width:40%;" class="action" id="flash_startup_sub" onclick="flashStartupSave();" type="button" data-i18n="sys_save_startup" value="Save Startup Settings to Flash"> <input style="width:40%;" class="action" id="flash_startup_sub" onclick="flashStartupSave();" type="button" value="Save Startup Settings to Flash">
<br/> <br/>
<input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" data-i18n="sys_reset" value="Reset Switch"> <input style="width:40%;" class="action" id="switch_reset" onclick="resetSwitch();" type="button" value="Reset Switch">
</div>
<div id="console-tab" class="tab-content">
<h1 data-i18n="sys_console">Console Command</h1>
<label for="console_command" data-i18n="sys_enter_cmd">Enter command:</label>
<input type="text" id="console_cmd" name="console_cmd" style="width:40%;">
<input style="width:20%;" class="action" id="cmd_sub" onclick="cmdSub();" type="button" data-i18n="sys_send_cmd" value="Send Command"><br/>
<br/><br/>
<span data-i18n="sys_console_warn">Be careful when entering console commands, you can lock yourself out!</span><br/>
</div> </div>
</div> </div>
+28 -106
View File
@@ -1,15 +1,9 @@
var systemInterval = Number(); var systemInterval = Number();
var isSaving = false;
const ips = ["ip", "netmask", "gw"]; const ips = ["ip", "netmask", "gw"];
function changeLang() {
var lang = document.getElementById('lang-select').value;
setLang(lang);
}
function checkIp(ip) { function checkIp(ip) {
const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/; const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/;
if (!ipv4.test(ip)) {alert(t('sys_invalid_ip') + ip); return false }; if (!ipv4.test(ip)) {alert(`Invalid ip:${ip}`); return false };
return true; return true;
} }
@@ -18,78 +12,51 @@ async function ipSub() {
if (!checkIp(document.getElementById(ips[i]).value)) if (!checkIp(document.getElementById(ips[i]).value))
return; return;
} }
var cmd = '';
for (let i=0; i<3;i++){ for (let i=0; i<3;i++){
cmd += ips[i]+' '+document.getElementById(ips[i]).value+'\n'; var cmd = ips[i]+' '+document.getElementById(ips[i]).value;
} try {
try { const response = await fetch('/cmd', {
const response = await fetch('/cmd', { method: 'POST',
method: 'POST', body: cmd
body: cmd });
}); console.log('Completed!', response);
console.log('Completed!', response); fetchIP();
fetchIP(); } catch(err) {
} catch(err) {
console.error(`Error: ${err}`);
}
}
async function cmdSub() {
var cmd = document.getElementById('console_cmd').value;
try {
const response = await fetch('/cmd', {
method: 'POST',
body: cmd
});
console.log('Completed!', response);
} catch(err) {
console.error(`Error: ${err}`); console.error(`Error: ${err}`);
}
} }
} }
async function hostSub() {
const h = document.getElementById("hostname").value;
try { await fetch('/cmd', { method: 'POST', body: "hostname " + h }); }
catch(err) { console.error(`Error: ${err}`); }
fetchIP();
}
async function sendConfig(c) { async function sendConfig(c) {
if (isSaving) return; const form = new FormData();
isSaving = true;
clearInterval(systemInterval);
const form = new FormData();
form.append("MAX_FILE_SIZE", "4096"); form.append("MAX_FILE_SIZE", "4096");
form.append("configuration", new Blob([c], {type: "application/octet-stream"}), "config.txt"); form.append("configuration", new Blob([c], {type: "application/octet-stream"}));
try { try {
const response = await fetch('/config', { const response = await fetch('/config', {
method: 'POST', method: 'POST',
body: form body: form
}); });
console.log('Completed!', response); console.log('Completed!', response);
try {
await fetch('/cmd_log_clear', { method: 'GET' });
} catch(e) {}
} catch(err) { } catch(err) {
console.error(`Error: ${err}`); console.error(`Error: ${err}`);
} finally {
isSaving = false;
systemInterval = setInterval(fetchIP, 1000);
} }
} }
async function flashSave() { async function flashSave() {
configuration = []; fetchConfig().then((s) => {
const savedConfig = await fetchConfig(); parseConf(s);
const cmdLog = await fetchCmdLog(); fetchCmdLog().then((s) => {
if (savedConfig) parseConf(savedConfig); parseConf(s);
if (cmdLog) parseConf(cmdLog); var body = "";
const body = configuration.join('\n') + '\n'; for (const x of configuration) { body = body + x + "\n"; }
console.log("CONFIGURATION to save: ", body); console.log("CONFIGURATION to save: ", body);
await sendConfig(body); sendConfig(body);
});
});
setTimeout(() => {
fetchIP();
}, 500);
} }
async function flashStartupSave() { async function flashStartupSave() {
@@ -131,9 +98,6 @@ function fetchIP() {
document.getElementById("ip").value=s.ip_address; document.getElementById("ip").value=s.ip_address;
document.getElementById("netmask").value=s.ip_netmask; document.getElementById("netmask").value=s.ip_netmask;
document.getElementById("gw").value=s.ip_gateway; document.getElementById("gw").value=s.ip_gateway;
document.getElementById("hostname").value=s.hostname;
document.getElementById("model").textContent=s.hw_ver;
loadMgmtVlan();
clearInterval(systemInterval); clearInterval(systemInterval);
// Fetch and populate the config textbox // Fetch and populate the config textbox
fetchConfig().then((configText) => { fetchConfig().then((configText) => {
@@ -152,57 +116,15 @@ function fetchIP() {
} }
function resetSwitch() { function resetSwitch() {
if (!confirm(t('sys_reset_confirm'))) { if (!confirm('Are you sure you want to reset the switch?')) {
return; return;
} }
fetch('/reset', { method: 'GET' }).catch(() => {}); fetch('/reset', { method: 'GET' }).catch(() => {});
setTimeout(() => { setTimeout(() => {
alert(t('sys_resetting')); alert('Switch is resetting. Please wait and refresh the page.');
}, 3000); }, 3000);
} }
window.addEventListener("load", function() { window.addEventListener("load", function() {
var langSel = document.getElementById('lang-select');
if (langSel) langSel.value = rtlLang;
systemInterval = setInterval(fetchIP, 1000); systemInterval = setInterval(fetchIP, 1000);
}); });
var mgmtVlanCurrent = 0;
function loadMgmtVlan() {
var sel = document.getElementById('mgmtvlan');
if (!sel) return;
fetch('/vlanlist').then(function(r) { return r.json(); }).then(function(d) {
var cur = d.mgmt || 0;
var list = d.vlan || [];
mgmtVlanCurrent = cur;
sel.innerHTML = '';
if (!cur) {
var none = document.createElement('option');
none.value = 0; none.disabled = true;
none.textContent = t('sys_mgmt_untagged');
sel.appendChild(none);
}
for (var i = 0; i < list.length; i++) {
var o = document.createElement('option');
o.value = list[i].id;
o.textContent = list[i].name ? (list[i].id + ' (' + list[i].name + ')') : list[i].id;
sel.appendChild(o);
}
sel.value = cur;
}).catch(function(err) { console.error('VLAN list failed:', err); });
}
function mgmtVlanChanged() {
var sel = document.getElementById('mgmtvlan');
var id = parseInt(sel.value, 10);
if (!id || id === mgmtVlanCurrent) return;
if (!confirm(t('sys_mgmt_confirm') + id + '.\n\n' + t('sys_mgmt_warn'))) {
sel.value = mgmtVlanCurrent;
return;
}
fetch('/cmd', { method: 'POST', body: 'vlan ' + id + ' mgmt' })
.then(function() { mgmtVlanCurrent = id; })
.catch(function(err) { console.error('Set management VLAN failed:', err); sel.value = mgmtVlanCurrent; });
}
+4 -5
View File
@@ -1,19 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="update_title">Firmware update</title> <title>Firmware update</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;width:40%;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;width:40%;">
<h1 data-i18n="update_heading">Firmware Update</h1> <h1>Firmware Update</h1>
<form enctype="multipart/form-data" action="/upload" method="POST"> <form enctype="multipart/form-data" action="/upload" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" /> <input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
<span data-i18n="update_instruction">Choose a firmware update file to upload:</span> <br/> <br/> Choose a firmware update file to upload: <br/> <br/>
<input name="uploadedfile" type="file" accept=".bin" /><br /> <input name="uploadedfile" type="file" accept=".bin" /><br />
<input style="margin-top:3em" type="submit" data-i18n="update_upload" value="Upload File" /> <input style="margin-top:3em" type="submit" value="Upload File" />
</form> </form>
<script src="/navigation.js"></script> <script src="/navigation.js"></script>
</body> </body>
+12 -36
View File
@@ -1,58 +1,34 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<script src="/main.js"></script> <script src="/main.js"></script>
<script src="/i18n.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<title data-i18n="vlan_title">FreeSwitchOS VLAN Configuration</title> <title>FreeSwitchOS VLAN Configuration</title>
</head> </head>
<body> <body>
<nav id="sidebar"></nav> <nav id="sidebar"></nav>
<div style="margin-left:16%;padding:1px 16px;height:1000px;"> <div style="margin-left:16%;padding:1px 16px;height:1000px;">
<div id="ports"></div> <div id="ports"></div>
<h1 data-i18n="vlan_heading">VLAN Configuration</h1> <h1>VLAN Configuration</h1>
<form id="vform" action="/vlan.html"> <form id="vform" action="/vlan.html">
<div> <div>
<label for="vlanSelect" data-i18n="vlan_select">VLAN Select:</label> <label for="vid">VLAN ID:</label>
<select id="vlanSelect" style="margin: 0 0 0 8px">
<option value="" disabled selected data-i18n="vlan_choose">— VLAN Choose —</option>
</select>
</div>
<br/>
<div>
<label for="vid" data-i18n="vlan_id">VLAN ID:</label>
<input type="number" min="1" max="4094" id="vid" name="vid"> <input type="number" min="1" max="4094" id="vid" name="vid">
<button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();" data-i18n="vlan_get_config">Get Configuration</button> <button type="button" style="margin: 0 0 0 24px" onclick="fetchVLAN();">Get Configuration</button>
</div> </div>
<br/><br/> <br/><br/>
<label for="vname" data-i18n="vlan_name">VLAN Name:</label> <label for="vname">VLAN Name:</label>
<input type="text" id="vname" name="vname"><br><br> <input type="text" id="vname" name="vname"><br><br>
<br/> <br/>
<h2 data-i18n="vlan_tagged">Tagged Ports</h2> <h2>Tagged Ports</h2>
<div id="tPorts"><button type="button" style="transform: translateY(-100%);margin: 0 50px 0 0" onclick="utClicked(true);" data-i18n="vlan_select_all">Select all</button></div> <div id="tPorts"><button type="button" style="transform: translateY(-100%);margin: 0 50px 0 0" onclick="utClicked(true);">Select all</button></div>
<h2 data-i18n="vlan_untagged">Untagged Ports</h2> <h2>Untagged Ports</h2>
<div id="uPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="utClicked(false);" data-i18n="vlan_select_all">Select all</button> </div> <div id="uPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="utClicked(false);">Select all</button> </div>
<h2 data-i18n="vlan_pvid">Use as default VLAN for incoming traffic (PVID)</h2> <h2>Use as default VLAN for incoming traffic (PVID)</h2>
<div id="pPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="pvClicked(true);" data-i18n="vlan_select_all">Select all</button> </div> <div id="pPorts"><button type="button" style="transform: translateY(-100%); margin: 0 50px 0 0" onclick="pvClicked(true);">Select all</button> </div>
<script src="/vlan.js"></script> <script src="/vlan.js"></script>
<br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" data-i18n="vlan_update" value="Update / Create"> <br/> <input style="width:40%;" class="action" id="vlan_sub" onclick="vlanSub();" type="button" value="Update / Create">
<script src="/vlan_sub.js"></script> <script src="/vlan_sub.js"></script>
</form> </form>
<h2 data-i18n="vlan_configured">Configured VLANs</h2>
<table id="vlanTable" style="width:90%">
<thead>
<tr>
<th>VLAN</th>
<th data-i18n="vlan_col_name">Name</th>
<th data-i18n="vlan_col_member">Member Ports</th>
<th data-i18n="vlan_col_tagged">Tagged Ports</th>
<th data-i18n="vlan_col_untagged">Untagged Ports</th>
<th data-i18n="vlan_col_pvid">PVID Ports</th>
<th data-i18n="vlan_col_delete">Delete</th>
</tr>
</thead>
<tbody id="vlanTableBody">
</tbody>
</table>
</div> </div>
<script src="/navigation.js"></script> <script src="/navigation.js"></script>
</body> </body>
+1 -121
View File
@@ -76,136 +76,16 @@ function fetchVLAN() {
}; };
var v=document.getElementById('vid').value var v=document.getElementById('vid').value
if (!v) { if (!v) {
alert(t('vlan_set_id_first')); alert("Set VLAN ID first");
return; return;
} }
xhttp.open("GET", `/vlan.json?vid=${v}`, true); xhttp.open("GET", `/vlan.json?vid=${v}`, true);
sendXHTTP(xhttp); sendXHTTP(xhttp);
} }
function portsToRange(mask, nPorts) {
var parts = [];
var start = -1, prev = -1;
for (var p = 1; p <= nPorts; p++) {
var bit = physToLogPort[p - 1];
if ((mask >> bit) & 1) {
if (start < 0) start = p;
prev = p;
} else {
if (start >= 0) {
parts.push(start === prev ? String(start) : start + '-' + prev);
start = -1; prev = -1;
}
}
}
if (start >= 0)
parts.push(start === prev ? String(start) : start + '-' + prev);
return parts.length ? parts.join(',') : '-';
}
async function loadVlanTable() {
var tbody = document.getElementById('vlanTableBody');
if (!tbody) return;
tbody.innerHTML = '';
var resp;
try { resp = await fetch('/vlanlist'); } catch(e) { return; }
if (!resp.ok) return;
var vlans = (await resp.json()).vlan || [];
for (var i = 0; i < vlans.length; i++) {
var v = vlans[i];
var vresp;
try { vresp = await fetch('/vlan.json?vid=' + v.id); } catch(e) { continue; }
if (!vresp.ok) continue;
var s = await vresp.json();
var m = parseInt(s.members, 16);
var members = m & 0x3FF;
var untag = ((m >> 10) & 0x3FF) & members;
var tagged = members & ~untag;
var pvid = parseInt(s.pvid, 16) & 0x3FF;
var tr = document.createElement('tr');
var td, a, btn;
td = document.createElement('td');
a = document.createElement('a');
a.href = '#';
a.textContent = v.id;
(function(vid) {
a.onclick = function(e) {
e.preventDefault();
document.getElementById('vid').value = vid;
fetchVLAN();
};
})(v.id);
td.appendChild(a); tr.appendChild(td);
td = document.createElement('td');
td.textContent = v.name || ''; tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(members, numPorts); tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(tagged, numPorts); tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(untag, numPorts); tr.appendChild(td);
td = document.createElement('td');
td.textContent = portsToRange(pvid, numPorts); tr.appendChild(td);
td = document.createElement('td');
if (v.id !== 1) {
btn = document.createElement('button');
btn.textContent = '✕';
(function(vid) {
btn.onclick = function() { deleteVlan(vid); };
})(v.id);
td.appendChild(btn);
}
tr.appendChild(td);
tbody.appendChild(tr);
}
}
function deleteVlan(id) {
if (!confirm(t('vlan_delete_confirm') + id + '?')) return;
fetch('/cmd', { method: 'POST', body: 'vlan ' + id + ' d' })
.then(function() { refreshVlanViews(); })
.catch(function(err) { console.error('Delete failed:', err); });
}
function refreshVlanViews() {
loadVlanList();
loadVlanTable();
}
function loadVlanList() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState !== 4) return;
var sel = document.getElementById('vlanSelect');
if (this.status !== 200) {
sel.style.display = 'none';
return;
}
var vlans = JSON.parse(this.responseText).vlan || [];
if (!vlans.length) {
sel.style.display = 'none';
return;
}
sel.options.length = 1;
for (var i = 0; i < vlans.length; i++) {
var opt = document.createElement('option');
opt.value = vlans[i].id;
opt.text = vlans[i].name ? vlans[i].id + ' — ' + vlans[i].name : String(vlans[i].id);
sel.appendChild(opt);
}
};
xhttp.open('GET', '/vlanlist', true);
sendXHTTP(xhttp);
}
window.addEventListener("load", function() { window.addEventListener("load", function() {
update( () => { update( () => {
vlanForm(); vlanForm();
refreshVlanViews();
document.getElementById('vlanSelect').onchange = function() {
document.getElementById('vid').value = this.value;
fetchVLAN();
};
const interval = setInterval(update, 2000); const interval = setInterval(update, 2000);
}); });
}); });
+1 -2
View File
@@ -3,7 +3,7 @@ async function vlanSub() {
var cmd = "vlan "; var cmd = "vlan ";
var v=document.getElementById('vid').value var v=document.getElementById('vid').value
if (!v) { if (!v) {
alert(t('vlan_set_id_first')); alert("Set VLAN ID first");
return; return;
} }
cmd = cmd + v; cmd = cmd + v;
@@ -28,7 +28,6 @@ async function vlanSub() {
}); });
console.log('Completed!', response); console.log('Completed!', response);
} }
refreshVlanViews();
} catch(err) { } catch(err) {
console.error(`Error: ${err}`); console.error(`Error: ${err}`);
} }
+104 -202
View File
@@ -14,6 +14,9 @@
#define SESSION_ID_LENGTH 12 #define SESSION_ID_LENGTH 12
#define SESSION_TIMEOUT 200 #define SESSION_TIMEOUT 200
// SPI FLASH MEMORY PAGE SIZE.
#define FLASHMEM_PAGE_SIZE 0x100
#define CMARK_S 6 #define CMARK_S 6
#pragma codeseg BANK1 #pragma codeseg BANK1
@@ -57,12 +60,11 @@ __xdata uint32_t now;
__xdata uint8_t *timeptr; __xdata uint8_t *timeptr;
__xdata uint32_t last_session_use; __xdata uint32_t last_session_use;
#define TSTATE_NONE 0 #define TSTATE_NONE 0
#define TSTATE_TX 1 #define TSTATE_TX 1
#define TSTATE_ACKED 2 #define TSTATE_ACKED 2
#define TSTATE_CLOSED 3 #define TSTATE_CLOSED 3
#define TSTATE_POST 4 #define TSTATE_POST 4
#define TSTATE_MULTIPART 5
extern __xdata uint16_t crc_value; extern __xdata uint16_t crc_value;
__xdata uint16_t crc_final; __xdata uint16_t crc_final;
@@ -101,89 +103,48 @@ uint8_t find_entry(__xdata uint8_t *e)
} }
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p) char strcmp(__xdata uint8_t *c, __code uint8_t * __xdata d)
{ {
uint8_t u, c; uint8_t i = 0;
while (1) { while (d[i] && (d[i] == c[i]))
u = *xdata_str_p++; i++;
c = *code_str_p++;
if (c == '\0') { if (c[i] < d[i])
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r') return -1;
return false; else if (c[i] > d[i])
return true; return 1;
} return 0;
if (c != u) {
return false;
}
}
} }
bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p) char is_word(__xdata uint8_t *c, __code uint8_t * __xdata d)
{ {
uint8_t u, s; uint8_t i = 0;
while(1) { while (d[i] && (d[i] == c[i]))
u = *uri_str_p++; i++;
s = *src_str_p++;
if (s == '\0') { if (d[i])
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r') return 0;
return false; if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
return true; return 0;
} return 1;
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) char is_word_x(__xdata uint8_t *c, __xdata uint8_t *d)
{ {
uint8_t u, c; register uint8_t i = 0;
while (1) { while (d[i] && (d[i] == c[i]))
u = *lhs_str_p++; i++;
c = *rhs_str_p++;
if (c == '\0') { if (d[i])
/* ';' separates cookies in a Cookie header, so it ends a value too. */ return 0;
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r' && u != ';') if (c[i] != ' ' && c[i] != '\t' && c[i] != ':' && c[i] != '?' && c[i] != '=' && c[i] != '\n' && c[i] != '\r' && c[i])
return false; return 0;
return true; return 1;
}
if (c != u) {
return false;
}
}
} }
@@ -205,28 +166,28 @@ uint8_t parse_short(__xdata uint8_t *p)
void send_not_found(void) void send_not_found(void)
{ {
slen = strtox(outbuf, "HTTP/1.1 404 Not found\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n" \ 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"); "<!DOCTYPE HTML PUBLIC>\n<title>404 Not Found</title>\n<h1>Not Found</h1>\n");
} }
void send_bad_request(void) void send_bad_request(void)
{ {
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n" \ 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"); "<!DOCTYPE HTML PUBLIC>\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n");
} }
void send_to_login(void) void send_to_login(void)
{ {
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\n" \ slen = strtox(outbuf, "HTTP/1.1 302 Found\r\n" \
"Location: login.html\r\n\r\n"); "Location: login.html\r\n\r\n");
} }
void send_unauthorized(void) void send_unauthorized(void)
{ {
slen = strtox(outbuf, "HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n"); slen = strtox(outbuf, "HTTP/1.1 401 Unauthorized\r\n\r\n");
} }
@@ -253,27 +214,14 @@ __xdata uint8_t *scan_header(__xdata uint8_t *p)
break; break;
if (is_word(p, "\nContent-Type:")) if (is_word(p, "\nContent-Type:"))
content_type = p + 15; content_type = p + 15;
else if (is_word(p, "\nCookie:")) { else if (is_word(p, "\nCookie:"))
/* Scan for the "session" key: the header may hold several session = p + 17;
* 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=" */
break;
}
c++;
}
}
} }
if (content_type && is_word(content_type, "multipart/form-data; boundary")) { if (content_type && is_word(content_type, "multipart/form-data; boundary")) {
dbg_string("\nFound multipart\n"); dbg_string("\nFound multipart\n");
content_type += 30; content_type += 30;
uint8_t i = 0; uint8_t i = 0;
while (i < (sizeof(boundary) - 5) && while (content_type[i] != '\r' && content_type[i] != '\n') {
content_type[i] != '\r' && content_type[i] != '\n') {
boundary[i + 4] = content_type[i]; boundary[i + 4] = content_type[i];
i++; i++;
} }
@@ -346,14 +294,14 @@ uint8_t stream_upload(uint16_t bptr)
if (verify_crc) { if (verify_crc) {
dbg_string("CRC16: "); dbg_short(crc_final); dbg_char('\n'); dbg_string("CRC16: "); dbg_short(crc_final); dbg_char('\n');
if (crc_final == 0xb001) { if (crc_final == 0xb001) {
print_string("Checksum OK.\nUpload to flash done, will reset!\n"); print_string("Checksum OK.");
// close connection to avoid retries by browser
uip_close();
reset_chip();
} else { } else {
print_string("Checksum incorrect! Aborting.\n"); print_string("Checksum incorrect!");
uip_close();
} }
print_string("\nUpload to flash done, will reset!\n");
// close connection to avoid retries by browser
uip_close();
reset_chip();
} }
// Make sure there is a 0 at the end of the uploaded data // Make sure there is a 0 at the end of the uploaded data
flash_buf[0] = 0; flash_buf[0] = 0;
@@ -381,22 +329,18 @@ uint8_t stream_upload(uint16_t bptr)
} }
crc16(p + bptr); crc16(p + bptr);
flash_buf[write_len++] = p[bptr++]; flash_buf[write_len++] = p[bptr++];
if (write_len >= FLASH_PAGE_SIZE) { if (write_len >= FLASHMEM_PAGE_SIZE) {
dbg_string("len: "); dbg_short(write_len); dbg_char(' '); dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n'); 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.addr = uptr;
flash_region.len = FLASH_PAGE_SIZE; flash_region.len = FLASHMEM_PAGE_SIZE;
flash_write_bytes(flash_buf); flash_write_bytes(flash_buf);
uptr += FLASH_PAGE_SIZE; uptr += FLASHMEM_PAGE_SIZE;
write_len -= FLASH_PAGE_SIZE; write_len -= FLASHMEM_PAGE_SIZE;
// Copy the remaining byte for the next page to the beginning of the buffer. // Copy the remaining byte for the next page to the beginning of the buffer.
if (write_len > 0) { if (write_len > 0) {
memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len); memcpy(flash_buf, flash_buf + FLASHMEM_PAGE_SIZE, write_len);
} }
} }
bindex = 0; bindex = 0;
@@ -411,89 +355,53 @@ void handle_post(void)
__xdata uint8_t *p = uip_appdata; __xdata uint8_t *p = uip_appdata;
__xdata uint8_t *request_path = p + 6; __xdata uint8_t *request_path = p + 6;
// Was the multipart header sent in multiple packets? dbg_string("Is POST\n");
if (s->tstate != TSTATE_MULTIPART) { p += 5; // Skip post
dbg_string("Is POST\n"); // Find end of request path
p += 5; // Skip post while (*p && !is_separator(*p))
// Find end of request path p++;
while (*p && !is_separator(*p)) *p++ = '\0';
p++;
*p++ = '\0';
// Find end of request header // Find end of request header
boundary[0] ='\0'; boundary[0] ='\0';
p = scan_header(p); p = scan_header(p);
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n"); dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
if (!*p || !content_type) { if (!*p || !content_type) {
dbg_string("Bad Request!\n"); dbg_string("Bad Request!\n");
send_not_found(); send_not_found();
return; 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")) { if (is_word(request_path, "cmd")) {
register uint8_t i = 0;
p += 4; p += 4;
if (!authenticated) { if (!authenticated) {
send_unauthorized(); send_unauthorized();
return; return;
} }
execute_commands(p); while (*p && *p != '\n' && *p != '\r')
if (err_status != ERR_OK) { cmd_buffer[i++] = *p++;
send_bad_request(); cmd_buffer[i] = '\0';
return; if (i)
} cmd_available = 1;
} else if (is_word(request_path, "login")) { } else if (is_word(request_path, "login")) {
dbg_string("POST login\n"); 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=" p += 8; // Read also over "pwd="
if (is_url_word_x(p, passwd)) { if (is_word_x(p, passwd)) {
dbg_string("Password accepted!\n"); dbg_string("Password accepted!\n");
read_reg_timer(&last_session_use); read_reg_timer(&last_session_use);
gen_random_bytes(session_id, SESSION_ID_LENGTH); gen_random_bytes(session_id, SESSION_ID_LENGTH);
session_id[SESSION_ID_LENGTH] = '\0'; session_id[SESSION_ID_LENGTH] = '\0';
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \ slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nLocation: index.html\r\n" \
"Set-Cookie: session="); "Set-Cookie: session=");
for (register uint8_t i = 0; i < SESSION_ID_LENGTH; i++) for (register uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
outbuf[slen++] = session_id[i]; outbuf[slen++] = session_id[i];
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n"); slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
} else { } else {
dbg_string("Password invalid!\n"); slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nLocation: login.html\r\n\r\n");
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: login.html\r\n\r\n");
} }
return; return;
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) { } else if (is_word(request_path, "upload") || is_word(request_path, "config")) {
dbg_string("POST upload/config request\n"); dbg_string("POST upload/config request\n");
if (!authenticated) { if (!authenticated) {
send_unauthorized(); send_unauthorized();
@@ -507,10 +415,8 @@ void handle_post(void)
// We skip the intial parts as part of the header // We skip the intial parts as part of the header
do { do {
p = skip_boundary(p); p = skip_boundary(p);
if (!*p) { if (!*p)
s->tstate = TSTATE_MULTIPART; goto bad_request;
return;
}
p = scan_header(p); p = scan_header(p);
if (!*p) if (!*p)
goto bad_request; goto bad_request;
@@ -520,6 +426,25 @@ void handle_post(void)
dbg_string("Have content octets\n"); dbg_string("Have content octets\n");
p += 4; // Skip \r\n\r\n sequence at end of preamble of part p += 4; // Skip \r\n\r\n sequence at end of preamble of part
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 {
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();
}
flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails flash_init(0); // Re-initialize flash for non-DIO operation, otherwise flashing fails
set_sys_led_state(SYS_LED_FAST); set_sys_led_state(SYS_LED_FAST);
@@ -535,7 +460,7 @@ void handle_post(void)
send_not_found(); send_not_found();
return; return;
} }
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n"); slen = strtox(outbuf, "HTTP/1.1 200 OK\r\n\r\n");
return; return;
bad_request: bad_request:
send_bad_request(); send_bad_request();
@@ -548,12 +473,6 @@ void httpd_appcall(void)
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate); __xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
dbg_char('P'); 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) { if(uip_connected() && s->tstate == TSTATE_CLOSED) {
dbg_string("Connected...\n"); dbg_string("Connected...\n");
s->tstate = TSTATE_NONE; s->tstate = TSTATE_NONE;
@@ -625,10 +544,10 @@ void httpd_appcall(void)
dbg_char('\n'); dbg_char('\n');
#endif #endif
p = uip_appdata; p = uip_appdata;
if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART) { if (is_word(p, "POST")) {
handle_post(); handle_post();
// If this is an ongoing post stream, then wait for the next packet // 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) {
uip_len = 0; uip_len = 0;
return; return;
} }
@@ -640,7 +559,7 @@ void httpd_appcall(void)
p += 4; p += 4;
scan_header(p); scan_header(p);
__xdata uint8_t *q = p; __xdata uint8_t *q = p;
while (*p && !is_separator(*p)) while (!is_separator(*p))
p++; p++;
*p = '\0'; *p = '\0';
dbg_string_x(q); dbg_string_x(q);
@@ -664,16 +583,7 @@ void httpd_appcall(void)
parse_short(q + 15); parse_short(q + 15);
send_vlan(short_parsed); send_vlan(short_parsed);
} else if (is_word(q, "/counters.json")) { } else if (is_word(q, "/counters.json")) {
/* The port is one raw character of the request line and send_counters(q[20]-'0');
* 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)
send_bad_request();
else
send_counters(cport);
} else if (is_word(q, "/eee.json")) { } else if (is_word(q, "/eee.json")) {
send_eee(); send_eee();
} else if (is_word(q, "/bandwidth.json")) { } else if (is_word(q, "/bandwidth.json")) {
@@ -690,8 +600,6 @@ void httpd_appcall(void)
send_mtu(); send_mtu();
} else if (is_word(q, "/lag.json")) { } else if (is_word(q, "/lag.json")) {
send_lag(); send_lag();
} else if (is_word(q, "/vlanlist")) {
send_vlanlist();
} else if (is_word(q, "/config")) { } else if (is_word(q, "/config")) {
send_config(); send_config();
} else if (is_word(q, "/cmd_log")) { } else if (is_word(q, "/cmd_log")) {
@@ -722,13 +630,7 @@ void httpd_appcall(void)
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nContent-Type: "); 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, mime_strings[f_data[entry].mime]);
/* 'unsafe-inline' is needed for the inline onclick handlers 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");
* and the inline <script> on login.html. Connection: close is
* required because this httpd closes the connection after every
* response; without advertising it a browser reuses the socket
* from its keep-alive pool and the next request hits the already
* closed connection (a POST is then dropped without a retry). */
slen += strtox(outbuf + slen, "; charset=UTF-8\r\nCache-Control: max-age=60, must-revalidate\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\nContent-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; form-action 'self'\r\n\r\n");
len_left = f_data[entry].len; len_left = f_data[entry].len;
if (len_left > (TCP_OUTBUF_SIZE - slen)) { if (len_left > (TCP_OUTBUF_SIZE - slen)) {
+61 -136
View File
@@ -13,11 +13,11 @@
#include "version.h" #include "version.h"
#include "machine.h" #include "machine.h"
#include "page_impl.h" #include "page_impl.h"
#include "syslog.h"
// #define DEBUG // #define DEBUG
#include "debug.h" #include "debug.h"
#define L2_MAX_TRANSFER 30 #define L2_MAX_TRANSFER 30
#pragma codeseg BANK1 #pragma codeseg BANK1
@@ -26,7 +26,6 @@
extern __code const struct machine machine; extern __code const struct machine machine;
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE]; extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
extern __xdata uint16_t slen; extern __xdata uint16_t slen;
extern __xdata uint16_t management_vlan;
extern __xdata uint16_t cont_len; extern __xdata uint16_t cont_len;
extern __xdata uint32_t cont_addr; extern __xdata uint32_t cont_addr;
extern __code uint8_t * __code hex; extern __code uint8_t * __code hex;
@@ -46,7 +45,7 @@ extern __xdata char sfp_module_model[2][17];
extern __xdata char sfp_module_serial[2][17]; extern __xdata char sfp_module_serial[2][17];
extern __xdata uint8_t sfp_options[2]; 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_JSON = "HTTP/1.1 200 OK\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\nContent-Type: text/plain\r\n\r\n";
// Convert uint8_t to ascii HEX char push on html-buffer. // Convert uint8_t to ascii HEX char push on html-buffer.
@@ -98,19 +97,6 @@ void itoa_html(uint8_t v)
char_to_html('0' + (v % 10)); char_to_html('0' + (v % 10));
} }
void itoa16_html(uint16_t v) /* sufficient for VLAN IDs (max 4094) */
{
uint8_t print_zeros = 0;
uint8_t d;
d = v / 1000;
if (d) { char_to_html('0' + d); print_zeros = 1; }
d = (v / 100) % 10;
if (d || print_zeros) { char_to_html('0' + d); print_zeros = 1; }
d = (v / 10) % 10;
if (d || print_zeros) char_to_html('0' + d);
char_to_html('0' + (v % 10));
}
void string_to_html(__code char *s) void string_to_html(__code char *s)
{ {
while (*s) char_to_html(*s++); while (*s) char_to_html(*s++);
@@ -241,11 +227,6 @@ void send_basic_info(void)
itoa_html(uip_netmask[0] >> 8); char_to_html('.'); itoa_html(uip_netmask[0] >> 8); char_to_html('.');
itoa_html(uip_netmask[1]); char_to_html('.'); itoa_html(uip_netmask[1]); char_to_html('.');
itoa_html(uip_netmask[1] >> 8); itoa_html(uip_netmask[1] >> 8);
slen += strtox(outbuf + slen, "\",\"syslog_server_ip\":\"");
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]);
slen += strtox(outbuf + slen, "\",\"mac_address\":\""); slen += strtox(outbuf + slen, "\",\"mac_address\":\"");
byte_to_html(uip_ethaddr.addr[0]); char_to_html(':'); byte_to_html(uip_ethaddr.addr[0]); char_to_html(':');
byte_to_html(uip_ethaddr.addr[1]); char_to_html(':'); byte_to_html(uip_ethaddr.addr[1]); char_to_html(':');
@@ -253,12 +234,6 @@ void send_basic_info(void)
byte_to_html(uip_ethaddr.addr[3]); char_to_html(':'); byte_to_html(uip_ethaddr.addr[3]); char_to_html(':');
byte_to_html(uip_ethaddr.addr[4]); char_to_html(':'); byte_to_html(uip_ethaddr.addr[4]); char_to_html(':');
byte_to_html(uip_ethaddr.addr[5]); byte_to_html(uip_ethaddr.addr[5]);
slen += strtox(outbuf + slen, "\",\"hostname\":\"");
{
__xdata char *hp = hostname; /* sanitized on ingest, emit verbatim */
while (*hp)
char_to_html(*hp++);
}
slen += strtox(outbuf + slen, "\",\"sw_ver\":\""); slen += strtox(outbuf + slen, "\",\"sw_ver\":\"");
slen += strtox(outbuf + slen, VERSION_SW); slen += strtox(outbuf + slen, VERSION_SW);
slen += strtox(outbuf + slen, "\",\"build_date\":\""); slen += strtox(outbuf + slen, "\",\"build_date\":\"");
@@ -268,16 +243,14 @@ void send_basic_info(void)
slen += strtox(outbuf + slen, "\",\"flash_size\":\""); slen += strtox(outbuf + slen, "\",\"flash_size\":\"");
string_to_html(get_flash_size_str()); string_to_html(get_flash_size_str());
if (machine.n_sfp) { slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\"");
slen += strtox(outbuf + slen, "\",\"sfp_slot_0\":\""); send_sfp_info(0);
send_sfp_info(0);
if (machine.n_sfp == 2) {
slen += strtox(outbuf + slen, "\",\"sfp_slot_1\":\"");
send_sfp_info(1);
}
}
char_to_html('"'); char_to_html('"');
if (machine.n_sfp == 2) {
slen += strtox(outbuf + slen, ",\"sfp_slot_1\":\"");
send_sfp_info(1);
char_to_html('"');
}
char_to_html('}'); char_to_html('}');
} }
@@ -356,7 +329,6 @@ void send_l2(uint16_t idx)
*/ */
__xdata uint16_t entry = idx & 0xfff; __xdata uint16_t entry = idx & 0xfff;
__xdata uint16_t first_entry = 0xffff; // An illegal entry index __xdata uint16_t first_entry = 0xffff; // An illegal entry index
__bit first = true;
char_to_html('['); char_to_html('[');
while (1) { while (1) {
entries_left--; entries_left--;
@@ -370,22 +342,9 @@ void send_l2(uint16_t idx)
} while (sfr_data[3] & TBL_EXECUTE); } while (sfr_data[3] & TBL_EXECUTE);
reg_read_m(RTL837x_L2_DATA_OUT_B); reg_read_m(RTL837x_L2_DATA_OUT_B);
__bit valid = (sfr_data[0] & 0x20) != 0; if ((sfr_data[0] & 0x20)) { // Check entry is valid
if (valid) {
/* separator + 74-byte worst-case entry + closing "]" */
if (slen + 76 > TCP_OUTBUF_SIZE)
break;
if (!first)
char_to_html(',');
first = false;
// VLAN, taken from the read above instead of reading the register twice
slen += strtox(outbuf + slen, "{\"vlan\":\"");
charhex_to_html(sfr_data[0] & 0x0f);
byte_to_html(sfr_data[1]);
// MAC // MAC
slen += strtox(outbuf + slen, "\",\"mac\":\""); slen += strtox(outbuf + slen, "{\"mac\":\"");
byte_to_html(sfr_data[2]); char_to_html(':'); byte_to_html(sfr_data[2]); char_to_html(':');
byte_to_html(sfr_data[3]); char_to_html(':'); byte_to_html(sfr_data[3]); char_to_html(':');
port = (sfr_data[0] >> 6) & 0x3; port = (sfr_data[0] >> 6) & 0x3;
@@ -395,35 +354,47 @@ void send_l2(uint16_t idx)
byte_to_html(sfr_data[2]); char_to_html(':'); byte_to_html(sfr_data[2]); char_to_html(':');
byte_to_html(sfr_data[3]); byte_to_html(sfr_data[3]);
// VLAN
slen += strtox(outbuf + slen, "\",\"vlan\":\"");
reg_read_m(RTL837x_L2_DATA_OUT_B);
charhex_to_html(sfr_data[0] & 0x0f);
byte_to_html(sfr_data[1]);
// type // type
reg_read_m(RTL837x_L2_DATA_OUT_C); reg_read_m(RTL837x_L2_DATA_OUT_C);
if (sfr_data[1] & 0x1) if (sfr_data[2] & 0x1)
slen += strtox(outbuf + slen, "\",\"type\":\"s\",\"port\":"); slen += strtox(outbuf + slen, "\",\"type\":\"s\",\"port\":");
else else
slen += strtox(outbuf + slen, "\",\"type\":\"l\",\"port\":"); slen += strtox(outbuf + slen, "\",\"type\":\"l\",\"port\":");
port |= (sfr_data[3] & 0x3) << 2; port |= (sfr_data[3] & 0x3) << 2;
itoa_html(port); itoa_html(port);
}
// Index // Index
reg_read_m(RTL837x_TBL_DATA_0); reg_read_m(RTL837x_TBL_DATA_0);
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3]; entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3];
if (valid) {
slen += strtox(outbuf + slen, ",\"idx\":\""); slen += strtox(outbuf + slen, ",\"idx\":\"");
byte_to_html(entry >> 8); byte_to_html(entry >> 8);
byte_to_html(entry); byte_to_html(entry);
char_to_html('"'); char_to_html('"');
char_to_html('}'); char_to_html('}');
entry += 1; // We want the next entry following after the current entry
} else {
reg_read_m(RTL837x_TBL_DATA_0);
entry = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3] + 1;
} }
entry += 1; // We want the next entry following after the current entry if (first_entry == 0xffff) {
char_to_html(',');
if (first_entry == 0xffff)
first_entry = entry; first_entry = entry;
else if (first_entry == entry || !entries_left) } else {
break; if (first_entry == entry || !entries_left) {
char_to_html(']');
break;
} else {
char_to_html(',');
}
}
} }
char_to_html(']');
} }
@@ -520,7 +491,8 @@ void send_lag(void)
slen += strtox(outbuf + slen, "{\"lagNum\":"); slen += strtox(outbuf + slen, "{\"lagNum\":");
itoa_html(l); itoa_html(l);
slen += strtox(outbuf + slen, ",\"members\":\""); slen += strtox(outbuf + slen, ",\"members\":\"");
uint16_t ports = port_lag_members_get(l); reg_read_m(RTL837X_TRK_MBR_CTRL_BASE + (l << 2));
uint16_t ports = ((uint16_t)sfr_data[2] << 8) | sfr_data[3];
for (uint8_t i = 0; i < 16; i++) { for (uint8_t i = 0; i < 16; i++) {
bool_to_html(!!(ports & 0x8000)); bool_to_html(!!(ports & 0x8000));
ports <<= 1; ports <<= 1;
@@ -668,53 +640,52 @@ void send_status(void)
slen += strtox(outbuf + slen, "\""); slen += strtox(outbuf + slen, "\"");
if (machine.is_sfp[i]) { if (machine.is_sfp[i]) {
uint8_t sfp = machine.is_sfp[i] - 1;
slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":"); slen += strtox(outbuf + slen, ",\"isSFP\":1,\"enabled\":");
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) { if (!(sfp_pins_last & (0x1 << ((machine.is_sfp[i] - 1) << 2)))) {
bool_to_html(1); bool_to_html(1);
slen += strtox(outbuf + slen,",\"sfp_options\":\"0x"); slen += strtox(outbuf + slen,",\"sfp_options\":\"0x");
byte_to_html(sfp_options[sfp]); byte_to_html(sfp_options[machine.is_sfp[i]-1]);
if (sfp_options[sfp] & 0x40) { if (sfp_options[machine.is_sfp[i]-1] & 0x40) {
slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_temp\":\"0x");
sfp_send_data(sfp, 224, 2); sfp_send_data(machine.is_sfp[i] - 1, 224, 2);
slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_vcc\":\"0x");
sfp_send_data(sfp, 226, 2); sfp_send_data(machine.is_sfp[i] - 1, 226, 2);
slen += strtox(outbuf + slen,"\",\"sfp_txbias\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_txbias\":\"0x");
sfp_send_data(sfp, 228, 2); sfp_send_data(machine.is_sfp[i] - 1, 228, 2);
slen += strtox(outbuf + slen,"\",\"sfp_txpower\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_txpower\":\"0x");
sfp_send_data(sfp, 230, 2); sfp_send_data(machine.is_sfp[i] - 1, 230, 2);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_rxpower\":\"0x");
sfp_send_data(sfp, 232, 2); sfp_send_data(machine.is_sfp[i] - 1, 232, 2);
if (sfp_options[sfp] & 0x10) { if (sfp_options[machine.is_sfp[i]-1] & 0x10) {
slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_temp_cal\":\"0x");
sfp_send_data(sfp, 212, 4); sfp_send_data(machine.is_sfp[i] - 1, 212, 4);
slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_vcc_cal\":\"0x");
sfp_send_data(sfp, 216, 4); sfp_send_data(machine.is_sfp[i] - 1, 216, 4);
slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_txbias_cal\":\"0x");
sfp_send_data(sfp, 204, 4); sfp_send_data(machine.is_sfp[i] - 1, 204, 4);
slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_txpower_cal\":\"0x");
sfp_send_data(sfp, 208, 4); sfp_send_data(machine.is_sfp[i] - 1, 208, 4);
slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_rxpower_cal\":\"0x");
sfp_send_data(sfp, 184, 16); sfp_send_data(machine.is_sfp[i] - 1, 184, 16);
sfp_send_data(sfp, 200, 4); sfp_send_data(machine.is_sfp[i] - 1, 200, 4);
} }
slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x"); slen += strtox(outbuf + slen,"\",\"sfp_state\":\"0x");
sfp_send_data(sfp, 238, 1); sfp_send_data(machine.is_sfp[i] - 1, 238, 1);
} }
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\""); slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
for (register uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++) for (register uint8_t s = 0; s < 16; s++)
outbuf[slen++] = sfp_module_vendor[sfp][s]; outbuf[slen++] = sfp_module_vendor[machine.is_sfp[i]-1][s];
slen += strtox(outbuf + slen,"\",\"sfp_model\":\""); slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
for (register uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++) for (register uint8_t s = 0; s < 16; s++)
outbuf[slen++] = sfp_module_model[sfp][s]; outbuf[slen++] = sfp_module_model[machine.is_sfp[i]-1][s];
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\""); slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
for (register uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++) for (register uint8_t s = 0; s < 16; s++)
outbuf[slen++] = sfp_module_serial[sfp][s]; outbuf[slen++] = sfp_module_serial[machine.is_sfp[i]-1][s];
slen += strtox(outbuf + slen,"\",\"sfp_los\":"); slen += strtox(outbuf + slen,"\",\"sfp_los\":");
if (machine.sfp_port[sfp].pin_los == GPIO_NA) { if (machine.sfp_port[machine.is_sfp[i]-1].pin_los == GPIO_NA) {
slen += strtox(outbuf + slen,"null"); slen += strtox(outbuf + slen,"null");
} else { } else {
bool_to_html(sfp_pins_last & (0x2 << (sfp << 2))); bool_to_html(sfp_pins_last & (0x2 << (((machine.is_sfp[i]-1) << 2))));
} }
} else { } else {
bool_to_html(0); bool_to_html(0);
@@ -847,49 +818,3 @@ void send_cmd_log(void)
p = (p + 1) & CMD_HISTORY_MASK; p = (p + 1) & CMD_HISTORY_MASK;
} }
} }
void send_vlanlist(void)
{
/* Worst case per entry: {"id":4094,"name":"<117-char name>"} = 138 bytes
* (name bound: CMD_BUF_SIZE=128 minus command prefix); +1 for closing ']'.
* At worst case ~18 VLANs fit; typical configs with short names fit many more. */
__xdata uint16_t i;
__xdata uint16_t n;
uint8_t first = 1;
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
slen += strtox(outbuf + slen, "{\"mgmt\":");
itoa16_html(management_vlan);
slen += strtox(outbuf + slen, ",\"vlan\":[");
for (i = 1; i < 4095; i++) {
if (vlan_get(i) < 0)
continue;
if (!(sfr_data[0] & 0x02)) /* bit 1: VLAN table entry valid */
continue;
if (slen + 141 > TCP_OUTBUF_SIZE) /* comma + 138-byte worst-case entry + closing "]}" */
break;
if (!first)
char_to_html(',');
first = 0;
slen += strtox(outbuf + slen, "{\"id\":");
itoa16_html(i);
slen += strtox(outbuf + slen, ",\"name\":\"");
n = vlan_name(i);
if (n != 0xffff) {
while (vlan_names[n] && vlan_names[n] != ' ')
char_to_html(vlan_names[n++]);
}
slen += strtox(outbuf + slen, "\"}");
}
char_to_html(']');
char_to_html('}');
}
-1
View File
@@ -14,7 +14,6 @@ void send_mtu(void);
void send_config(void); void send_config(void);
void send_cmd_log(void); void send_cmd_log(void);
void send_lag(void); void send_lag(void);
void send_vlanlist(void);
/* Convert only the lower nibble to ascii HEX char. /* Convert only the lower nibble to ascii HEX char.
For convenience the upper nibble is masked out. For convenience the upper nibble is masked out.
+12 -11
View File
@@ -6,36 +6,37 @@ CC_FLAGS = -mmcs51
ASM = sdas8051 ASM = sdas8051
AFLAGS= -plosgff AFLAGS= -plosgff
BUILDDIR = output BUILDDIR = output/
SRCS = installer.c SRCS = installer.c
OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel} OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
all: create_build_dir $(BUILDDIR)/updatebuilder $(BUILDDIR)/rtlplayground_oem_upgrade.bin all: create_build_dir $(BUILDDIR)updatebuilder $(BUILDDIR)rtlplayground.bin
create_build_dir: create_build_dir:
mkdir -p $(BUILDDIR) mkdir -p $(BUILDDIR)
$(BUILDDIR)/updatebuilder: updatebuilder.c $(BUILDDIR)updatebuilder: updatebuilder.c
gcc $^ -o $@ gcc $^ -o $@
$(BUILDDIR)/installer.rel: installer.c $(BUILDDIR)installer.rel: installer.c
$(CC) $(CC_FLAGS) --code-loc ${CODE_LOCATION} -o $@ -c $< $(CC) $(CC_FLAGS) --code-loc ${CODE_LOCATION} -o $@ -c $<
$(BUILDDIR)/crtstart.rel: crtstart.asm $(BUILDDIR)crtstart.rel: crtstart.asm
$(ASM) $(AFLAGS) -o $@ $< $(ASM) $(AFLAGS) -o $@ $<
$(BUILDDIR)/%.rel: $(BUILDDIR)/%.asm $(BUILDDIR)%.rel: $(BUILDDIR)%.asm
${ASM} ${AFLAGS} -o $@ $^ ${ASM} ${AFLAGS} -o $@ $^
$(BUILDDIR)/%.rel: %.c $(BUILDDIR)%.rel: %.c
$(CC) $(CC_FLAGS) -o $@ -c $< $(CC) $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)/rtlinstaller.ihx: $(BUILDDIR)/crtstart.rel $(OBJS) $(BUILDDIR)rtlinstaller.ihx: $(BUILDDIR)crtstart.rel $(OBJS)
$(CC) $(CC_FLAGS) -Wl-bHOME=${INSTALLER_ADDRESS} -Wl-r -o $@ $^ $(CC) $(CC_FLAGS) -Wl-bHOME=${INSTALLER_ADDRESS} -Wl-r -o $@ $^
$(BUILDDIR)/rtlplayground_oem_upgrade.bin: $(BUILDDIR)/rtlinstaller.ihx ../$(BUILDDIR)/rtlplayground.bin $(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlinstaller.ihx ../$(BUILDDIR)/rtlplayground.bin
./$(BUILDDIR)/updatebuilder -i $< -o $(BUILDDIR)/rtlplayground_oem_upgrade.bin ../$(BUILDDIR)/rtlplayground.bin cp ../$(BUILDDIR)/rtlplayground.bin $(BUILDDIR)
./$(BUILDDIR)/updatebuilder -i $< $(BUILDDIR)rtlplayground.bin
clean: clean:
rm -r $(BUILDDIR) rm -r $(BUILDDIR)
+10 -573
View File
@@ -1,7 +1,6 @@
#include "machine.h" #include "machine.h"
#include "rtl837x_pins.h" #include "rtl837x_pins.h"
#include "rtl837x_leds.h" #include "rtl837x_leds.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h" #include "rtl837x_regs.h"
#include "rtl837x_common.h" #include "rtl837x_common.h"
@@ -74,58 +73,6 @@ __code const struct machine machine = {
void machine_custom_init(void) { } void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_6XH_X2
__code const struct machine machine = {
.machine_name = "keepLink KP-9000-6XH-X2",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP port
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
// Right SFP port
.sfp_port[1].pin_detect = GPIO37,
.sfp_port[1].pin_los = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO48_I2C_SCL1, // Button-Switch is unpopulated on PCB, but can be added manually (hole in case is already there)
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
LEDS_2G5 | LEDS_LINK, // Left LED (Amber)
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Right LED (Green)
0,
0
},
{
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
0
},
},
.led_mux_custom = 1,
.led_mux = {
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,
0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,
0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
},
};
void machine_custom_init(void) {
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_KP_9000_9XH_X_EU #elif defined MACHINE_KP_9000_9XH_X_EU
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XH-X-EU", .machine_name = "keepLink KP-9000-9XH-X-EU",
@@ -267,19 +214,15 @@ __code const struct machine machine = {
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */ .sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
.reset_pin = GPIO54_ACL_BIT2_EN, .reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 }, .high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1}, .port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
.led_sets = { .led_sets = {
{ /* RJ45: Green LED */ {
/* Green LED */
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G, LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0, 0,
/* Amber LED */ /* Amber LED */
LEDS_2G5 | LEDS_LINK | LEDS_ACT, LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0 0
}, { /* SFP PORT: SINGLE GREEN LED */
LEDS_10M | LEDS_100M | LEDS_1G | LEDS_2G5 | LEDS_10G | LEDS_LINK | LEDS_ACT,
0,
0,
0,
}, },
}, },
}; };
@@ -310,19 +253,15 @@ __code const struct machine machine = {
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */ .sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
.reset_pin = GPIO_NA, .reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 }, .high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1}, .port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
.led_sets = { .led_sets = {
{ /* RJ45: Green LED */ {
/* Green LED */
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G, LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0, 0,
/* Amber LED */ /* Amber LED */
LEDS_2G5 | LEDS_LINK | LEDS_ACT, LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0 0
}, { /* SFP PORT: SINGLE GREEN LED */
LEDS_10M | LEDS_100M | LEDS_1G | LEDS_2G5 | LEDS_10G | LEDS_LINK | LEDS_ACT,
0,
0,
0,
}, },
}, },
}; };
@@ -344,7 +283,7 @@ __code const struct machine machine = {
.sfp_port[0].pin_tx_disable = GPIO_NA, .sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1, .sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, .sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO48_I2C_SCL1, .reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 }, .high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1}, .port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = { .led_sets = {
@@ -415,7 +354,6 @@ void machine_custom_init(void) { }
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "SWTGW218AS 8+1 Managed Switch", .machine_name = "SWTGW218AS 8+1 Managed Switch",
.isRTL8373 = 1, .isRTL8373 = 1,
.mac_flash_offset = 0x1FC000,
.min_port = 0, .min_port = 0,
.max_port = 8, .max_port = 8,
.n_sfp = 1, .n_sfp = 1,
@@ -546,9 +484,9 @@ __code const struct machine machine = {
void machine_custom_init(void) { } void machine_custom_init(void) { }
#elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS) // Sold as a variety of devices, see doc/ #elif defined MACHINE_HI_K0402WS
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "PCB-K0402WS-V3.0", .machine_name = "HiSource HI-K0402WS",
.isRTL8373 = 0, .isRTL8373 = 0,
.min_port = 3, .min_port = 3,
.max_port = 8, .max_port = 8,
@@ -606,6 +544,7 @@ __code const struct machine machine = {
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1}, .is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN, .sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37, .sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA, .sfp_port[0].pin_tx_disable = GPIO_NA,
@@ -632,508 +571,6 @@ __code const struct machine machine = {
void machine_custom_init(void) { } void machine_custom_init(void) { }
#elif defined MACHINE_ZX310S_4T2XH
__code const struct machine machine = {
.machine_name = "ZX310S-4T2XH",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 1,
.n_10g = 1,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO48_I2C_SCL1,
.high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
.led_mux_custom = 1,
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
0x09, 0x0c, 0x3f, 0x0d, 0x10, // 65e4
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
0x1d, 0x20, 0x21 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
/* Ports 1-4: Orange: 2.5GBit, Green: 10/100/1000MBit
* Port 5: Blue: 10GBit, Green: 10Mbit-5GBit
* SFP-port: Blue: 10GBit, Green 100MBit-5GBit
*/
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT | LEDS_5G,
LEDS_LINK | LEDS_ACT | LEDS_10G,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
}
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_STEAMEMO_IG204_V1
__code const struct machine machine = {
.machine_name = "Steamemo IG204 V1",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP port (5)
// LED pin 9
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
// Right SFP port (6)
// LED pin 24
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
// RJ45 Amber LED (left)
LEDS_2G5 | LEDS_LINK,
// RJ45 Green LED (Right)
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
},
{
// SFP LED
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
0, // unused
0, // unused
0
},
},
.led_mux_custom = 1,
.led_mux = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x0f, 0x20, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x0c, 0x21, 0x22, 0x23
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_HI_K0801WS
__code const struct machine machine = {
.machine_name = "Hi-Source HI-k0801WS",
.isRTL8373 = 1,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = {
.sda = GPIO39_I2C_SDA4,
.scl = GPIO40_I2C_SCL3_MDC1
},
.reset_pin = GPIO_NA,
.high_leds = {
.mux = LED_27 | LED_29,
.enable = LED_28_SYS | LED_29
},
/* Ports 1-8 use set 0, port 9 SFP uses set 1 */
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_sets = {
{ /* Set 0: RJ45 copper ports
* Amber = 2.5G
* Green = 1G/100M/10M with activity
*/
LEDS_2G5 | LEDS_LINK | LEDS_ACT, /* Amber */
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* Green */
0
},
{ /* Set 1: SFP port, single green LED for all valid speeds */
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
0
},
},
};
void machine_custom_init(void) { }
#elif defined MACHINE_FNS1200P
__code const struct machine machine = {
.machine_name = "FNS-1200P",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
/* Left SFP (logical 8, SDS1): GPIO30=ModAbs, GPIO37=RX_LOS */
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
/* Copper ports use SET0; SFP ports use SET1 */
.port_led_set = {0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{ /* SET0: copper — LED0=amber (2.5G), LED2=green (1G/100M/10M) */
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
0,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0
},
{ /* SET1: SFP — all speeds link/act */
LEDS_10G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0, 0
},
},
.led_mux_custom = 1,
.led_mux = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* GPIO0-7: unused */
0x0f, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, /* GPIO8-14 */
0x14, 0x15, 0x16, 0x18, 0x19, 0x1a, /* GPIO15-20 */
0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x23 /* GPIO21-27 */
},
};
void machine_custom_init(void)
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1
__code const struct machine machine = {
.machine_name = "PCB-SWTG024AS-A-2.0.1",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
// SFP port on SDS0 / logical port 3
.sfp_port[0].pin_detect = GPIO37,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 0,
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
// SFP port on SDS1 / logical port 8
.sfp_port[1].pin_detect = GPIO38,
.sfp_port[1].pin_los = GPIO_NA,
.sfp_port[1].pin_tx_disable = GPIO_NA,
.sfp_port[1].sds = 1,
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
.led_sets = {
{
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT
},
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
LEDS_10G | LEDS_LINK | LEDS_ACT,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
},
},
.led_mux_custom = 1,
.led_mux = {
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
},
};
void machine_custom_init(void)
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
}
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
__code const struct machine machine = {
.machine_name = "SWTG024AS-A-V2.0.1-5C-1SFP",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
/* Ports 1-5 RJ45 use set 0, port 9 SFP uses set 1
* Ports 1-5: Green: 2.5GBit, Amber: 10/100/1000MBit
* SFP-port: Blue: 10GBit, Green: 100MBit-2.5GBit
*/
.led_sets = {
{
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT
},
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
LEDS_10G | LEDS_LINK | LEDS_ACT,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
},
},
.led_mux_custom = 1,
.led_mux = {
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
},
};
void machine_custom_init(void)
{
uint16_t pval;
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x100);
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x4000);
}
#elif defined MACHINE_SWTG024AS_V2_0
__code const struct machine machine = {
.machine_name = "SWTG024AS-V2.0",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
.sfp_port[0].pin_los = GPIO37,
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
/* Ports 1-5 RJ45 use set 0, port 9 SFP uses set 1
* Ports 1-5: Green: 2.5GBit, Amber: 10/100/1000MBit
* SFP-port: Blue: 10GBit, Amber: 100MBit-2.5GBit
*/
.led_sets = {
{
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT
},
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
LEDS_10G | LEDS_LINK | LEDS_ACT,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
},
},
.led_mux_custom = 1,
.led_mux = {
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
},
};
void machine_custom_init(void)
{
uint16_t pval;
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x100);
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x4000);
}
#elif defined MACHINE_ZX310S_4T2XT
__code const struct machine machine = {
.machine_name = "ZX310S_4T2XT",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 0,
.n_10g = 2,
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 0},
.reset_pin = GPIO48_I2C_SCL1,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
.led_mux_custom = 1,
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
0x09, 0x0c, 0x3f, 0x0d, 0x10, // 65e4
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
0x1d, 0x20, 0x21 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
/* Ports 1-4: Green: 2.5GBit, Orange: 10/100/1000MBit
* Ports 5-6: Green: 10GBit, Orange: <= 5GBit
*/
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_DUPLEX,
LEDS_2G5 | LEDS_LINK | LEDS_ACT },
{
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_5G,
LEDS_2G5 | LEDS_LINK,
LEDS_COL | LEDS_DUPLEX
}
},
};
void machine_custom_init(void) {
// For this device, the reset value of RTL837X_PIN_MUX_0 is 0x30000000,
// which would disables all LEDS, enable them manually:
REG_SET(RTL837X_PIN_MUX_0, 0x30db68bf);
}
#elif defined MACHINE_FG_4GT_2SX_V2_0
__code const struct machine machine = {
.machine_name = "FG-4GT-2SX_V2.0",
.isRTL8373 = 0,
.min_port = 3,
.max_port = 8,
.n_sfp = 2,
.log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5},
.phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0},
.is_sfp = {0, 0, 0, 2, 0, 0, 0, 0, 1},
// Left SFP port
.sfp_port[0].pin_detect = GPIO38,
.sfp_port[0].pin_los = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
// Right SFP port
.sfp_port[1].pin_detect = GPIO37,
.sfp_port[1].pin_los = GPIO_NA,
.sfp_port[1].sds = 0,
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO_NA,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
/* Ports 1-4 RJ45 use set 0, port 5-6 SFP uses set 1
* Ports 1-4: Green: 2.5GBit, Amber: 10/100/1000MBit
* Ports 5-6: Green: 100MBit-10GBit
*/
.led_sets = {
{
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
LEDS_2G5 | LEDS_LINK | LEDS_ACT
},
{
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_10G | LEDS_LINK,
0,
LEDS_COL | LEDS_DUPLEX
},
{
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
LEDS_2G5 | LEDS_1G | LEDS_LINK,
LEDS_5G | LEDS_2G5 | LEDS_LINK | LEDS_ACT,
LEDS_10G | LEDS_LINK | LEDS_ACT
},
{
LEDS_TX,
LEDS_RX,
LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5 |
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_ACT,
LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5 |
LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M | LEDS_LINK
},
},
.led_mux_custom = 1,
.led_mux = {
0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x3f, 0x15, 0x16,
0x18, 0x0e, 0x19, 0x11, 0x12, 0x1a, 0x15, 0x16, 0x1c, 0x19,
0x1a, 0x1d, 0x1d, 0x1e, 0x1e, 0x20, 0x21, 0x22
},
};
void machine_custom_init(void) {
REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7624155b);
}
#else #else
#error "Please select a machine type in machine.h" #error "Please select a machine type in machine.h"
#endif #endif
+2 -14
View File
@@ -6,9 +6,8 @@
/* /*
* Select your machine type below * Select your machine type below
*/ */
// #define MACHINE_KP_9000_6XHML_X2 #define MACHINE_KP_9000_6XHML_X2
// #define MACHINE_KP_9000_6XH_X // #define MACHINE_KP_9000_6XH_X
// #define MACHINE_KP_9000_6XH_X2
// #define MACHINE_KP_9000_9XH_X_EU // #define MACHINE_KP_9000_9XH_X_EU
// #define MACHINE_KP_9000_9XHML_X_V2_2 // #define MACHINE_KP_9000_9XHML_X_V2_2
// #define MACHINE_KP_9000_9XHML_X_V3_1 // #define MACHINE_KP_9000_9XHML_X_V3_1
@@ -18,19 +17,10 @@
// #define MACHINE_HG0402XG_V1_1 // #define MACHINE_HG0402XG_V1_1
// #define MACHINE_SWTG018AS_A_V_2_0 // #define MACHINE_SWTG018AS_A_V_2_0
// #define MACHINE_SWTGW218AS // #define MACHINE_SWTGW218AS
// #define MACHINE_PCB_K0402WS_V3 // #define MACHINE_HI_K0402WS
// #define MACHINE_K0501W_V2_0 // #define MACHINE_K0501W_V2_0
// #define MACHINE_LIANGUO_ZX_SWTGW215AS // #define MACHINE_LIANGUO_ZX_SWTGW215AS
// #define MACHINE_ZX310S_4T2XH
// #define MACHINE_ZX310S_4T2XT
// #define MACHINE_STEAMEMO_IG204_V1
// #define MACHINE_DEFAULT_8C_1SFP // #define MACHINE_DEFAULT_8C_1SFP
// #define MACHINE_HI_K0801WS
// #define MACHINE_FNS1200P
// #define MACHINE_PCB_SWTG024AS_A_2_0_1
// #define MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
// #define MACHINE_SWTG024AS_V2_0
// #define MACHINE_FG_4GT_2SX_V2_0
typedef struct { typedef struct {
// GPIO pins for SDA/SCL // GPIO pins for SDA/SCL
@@ -68,7 +58,6 @@ typedef struct machine {
// Highest logical port number // Highest logical port number
uint8_t max_port; uint8_t max_port;
uint8_t n_sfp; uint8_t n_sfp;
uint8_t n_10g;
uint8_t log_to_phys_port[9]; uint8_t log_to_phys_port[9];
uint8_t phys_to_log_port[9]; // Starts at 0 for port 1 uint8_t phys_to_log_port[9]; // Starts at 0 for port 1
uint8_t is_sfp[9]; // 0 for non-SFP ports 1 or 2 for the I2C port number uint8_t is_sfp[9]; // 0 for non-SFP ports 1 or 2 for the I2C port number
@@ -85,7 +74,6 @@ typedef struct machine {
uint32_t led_sets[4][4]; uint32_t led_sets[4][4];
uint8_t led_mux_custom; uint8_t led_mux_custom;
uint8_t led_mux[28]; uint8_t led_mux[28];
uint32_t mac_flash_offset;
}; };
typedef struct machine_runtime typedef struct machine_runtime

Some files were not shown because too many files have changed in this diff Show More