49 Commits
Author SHA1 Message Date
feelfree69 7b4d0d55d2 Merge pull request #713 from dobodu/main
Fix double sy_sysport_err and add new translations
2026-10-26 08:45:15 +01:00
dobodu fe1d4119d0 Fix double sy_sysport_err and add new translations
Removes
double entries for sy_sysport_err corrected
Add
sy_dns1, sy_dns2, sy_dns_err & sy_dns_dhcp translations
2026-10-26 00:13:49 +01:00
feelfree69 5c6a82d50f Merge pull request #568 from DrDoof/fix/upload-boundary-cr
httpd: re-check the byte that breaks a partial boundary match
2026-10-25 16:52:47 +01:00
feelfree69 26c420d26a Merge pull request #701 from hlyi/PSW8_25MG
Add REALHD_PSW8_25MG support and makefile enhancement
2026-10-25 15:52:26 +01:00
HL Yi eb394af95f add REALHD_PSW8_25MG support 2026-10-25 09:11:35 -05:00
feelfree69 4a4caeffd7 Merge pull request #703 from hlyi/make-chg
makefile enhancement for machine build
2026-10-25 14:37:47 +01:00
HL Yi 391360f517 makefile enhancement that only when both .h and .c exist to be considered as a device. It allows generic pcb-specific c not listed as a device 2026-10-25 06:21:45 -05:00
feelfree69 ed8e4b1a56 Merge pull request #560 from brunoz78/multi-session
httpd: four login sessions instead of one
2026-10-25 11:52:56 +01:00
feelfree69 78f28488c1 Merge pull request #534 from DrDoof/fix/html-min-stamp
build: minify the web files only when they change
2026-10-25 11:48:16 +01:00
Brunoz78andClaude Sonnet 5.5 e1c79ec4cd httpd: reuse the slot of a valid cookie, end sessions on passwd
Review feedback on #560 (DrDoof):

- A login that came with a cookie that is still valid took a second
  slot. The first one looked fresh, so the next login could push out
  someone who is using the switch. The slot of the cookie now gets the
  new id.
- Changing the password leaves no old login valid: session_init() from
  parse_passwd(). With one session the next login pushed a leftover one
  out, with several it would stay valid until the next restart.
- The 32-bit comparison of the last use times moves into a leaf function,
  so the compiler does not give it a 4-byte scratch in internal RAM.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-25 10:51:23 +01:00
Brunoz78andClaude Opus 5.5 a7db0ca8b6 httpd: keep the login sessions in bank 3
The web server's bank had no room left for the four sessions once the
original firmware's more robust header handling came in. Picking a slot,
checking a cookie and starting a session move to sessions.c in bank 3;
httpd.c only calls session_init(), session_check() and session_new().
The random id is written straight into the reply, which drops
gen_random_hex_chars() from bank 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 10:51:05 +01:00
Claude 70f59b64f5 httpd: four login sessions instead of one
Logging in from a second browser ended the first one's session at its next
request: two browsers open on the switch logged each other out every few
seconds. Up to four sessions now, each with its own cookie and expiry; a
fifth login replaces the least recently used. The expiry check is a leaf
function so its 32-bit scratch stays out of internal RAM (stack still
159 bytes with HEALTH).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tx2W7xVecMoKbBCkD2i8PG
(cherry picked from commit 03330f4077ef8872d861d951c8e44ece3c573935)
2026-10-25 10:51:05 +01:00
feelfree69 f0cbaba7b1 Merge pull request #672 from dobodu/main
French translation update
2026-10-25 10:20:24 +01:00
logicog a18c334139 Merge pull request #649 from DrDoof/build/sdcc-in-tree
build: build SDCC 4.6.0 with the mcs51 fixes in the tree
2026-10-25 06:18:24 +01:00
DrDoof 337b171ac4 build: minify the web files only when they change
html_min was phony, so every make deleted output/html_min and minified
all of html/ again, even with nothing changed. A stamp file now stands for
the minified copy and depends on the sources and on minify.py. A list of
the source names, rewritten only when it changes, is a dependency too, so
adding or removing a file in html/ still redoes the copy and a removed
file does not stay behind in the image. If output/html_min is missing,
the stamp is remade in the same run.

The note on version.h in webui-compression.md still said it was phony.
2026-10-25 03:11:03 +01:00
d00f 53eb3f5486 Merge pull request #583 from avicarmeli/fix/cpu-vlan-init
Fix CPU port PVID initialization independent of user port range
2026-10-25 02:44:18 +01:00
d00f 241edfdbda test: every last byte, CR runs and broken matches through the upload
Three more bench scenarios around the closing boundary. Every value
of the last image byte, uploaded whole and split right after the
payload, must end the part. A run of CR before the boundary of even
length passed before the fix and an odd one did not, so both are
checked. An image made of CR only, longer than a flash page, and one
made of repeated "\r\n-" exercise the broken matches back to back:
each one appends to the page buffer without a byte written, and the
page flush after both paths has to keep up.
2026-10-25 02:49:21 +02:00
DrDoof 714c9eb343 httpd: re-check the byte that breaks a partial boundary match
stream_upload() matches the closing multipart boundary byte by byte.
When a byte breaks a partial match, the matched prefix goes to flash as
data, and so does the breaking byte, without being compared against the
start of the boundary.

The boundary starts with "\r\n--", so an image whose last byte is '\r'
never completes: that '\r' starts a match, the '\r' of the boundary
breaks it and is written as data, and the rest of the boundary no
longer matches. The browser waits for a reply that never comes.

Flush the matched prefix and look at the breaking byte again from the
start of the boundary. A boundary may not contain CR, so no longer
suffix of the matched prefix can start a new match.
2026-10-25 02:49:14 +02:00
feelfree69 f2c89fd75b Merge pull request #651 from Kamikaze94/bugfix/sidebar-scrolling
WebUI: Lock sidebar layout and move scrolling to main element
2026-10-25 00:21:08 +02:00
avicarmeli ca2f1d101d Merge upstream main into CPU VLAN fix 2026-10-24 23:38:25 +03:00
d00f 9cc859ad30 build: carry the sdas fix for SDCC bug 4070
The 8051 assembler sign-extends every value to 24 bits, so the top
byte of a __sfr32 address list like 0xa4a5a6a7 comes out as 0xff.
The patch keeps 32-bit arithmetic while leaving the 24-bit T line
addresses alone, so the relocations are unchanged. Proposed upstream
in the bug thread. With it SFR_DATA_U32 can be used again, which
saves about 240 bytes of code in REG_SET.
2026-10-24 21:59:37 +02:00
d00f 0181276ec6 ci: build the in-tree SDCC and keep it between runs
The workflow and the Dockerfile install what building SDCC needs instead
of the distribution's sdcc, and the workflow caches toolchain/ keyed on
the contents of sdcc/.
2026-10-24 21:59:37 +02:00
d00f 905e588071 build: build SDCC 4.6.0 with two mcs51 fixes in the tree
Released SDCC 4.5.0 and 4.6.0 miscompile some of our code in the mcs51
register allocator (SDCC bugs 4153 and 4154, fixed in trunk r17025 and
r17039). The first make now downloads the 4.6.0 sources, checks their
sha256, applies the two fixes from sdcc/ and installs the compiler into
toolchain/, named after a checksum of sdcc/, so a changed patch builds a
new one. make CC=sdcc still uses an installed compiler.
2026-10-24 21:58:46 +02:00
feelfree69 bb16302a80 Merge pull request #622 from bloqaudio/fix/port-counter-lines
web: give each packet counter of a port its own line
2026-10-24 19:56:44 +02:00
feelfree69 50fda40fd9 Merge pull request #584 from bloqaudio/fix/mirror-status
mirror: show the configured monitor port in "mirror status"
2026-10-24 19:54:44 +02:00
feelfree69 9c65039bab Merge pull request #623 from bloqaudio/fix/save-button-dirty
web: highlight Save to flash only when there are unsaved changes
2026-10-24 19:39:55 +02:00
feelfree69 7e0bc93b55 Merge pull request #503 from bloqaudio/fix/uip-fragment-log-rate-limit
uip: rate-limit the dropped-fragment log
2026-10-24 16:40:33 +02:00
feelfree69 e1e1292ab0 Merge pull request #621 from bloqaudio/fix/num-header-align
web: right-align the headers of number columns
2026-10-24 16:36:11 +02:00
feelfree69 975caaff02 Merge pull request #633 from bloqaudio/fix/save-merge-lldp
web: keep LLDP lines from piling up in the saved configuration
2026-10-24 16:05:59 +02:00
feelfree69 cffe4793b1 Merge pull request #695 from L4ky/add-keeplink-kp90009xhpx
Add KeepLink KP-9000-9XHP-X as brand of POE-2G080110GS
2026-10-24 13:53:01 +02:00
feelfree69 9ed1e89c8b Merge pull request #698 from rwalli/fix/firefox-pw-autofill
Web UI: keep Firefox from autofilling the new admin password
2026-10-24 13:50:26 +02:00
feelfree69 ba2f759df3 Merge pull request #696 from rwalli/fix/uptime-ram-counter
rtl8372_init: set SDS 0 to SGMII as the stock firmware does
2026-10-24 12:44:58 +02:00
robs 884a1ac016 CHANGELOG: SDS 0 init on RTL8372 boards without 10G ports 2026-10-24 08:45:03 +02:00
robs 51ed063dcb rtl8372_init: set SDS 0 to SGMII as the stock firmware does
The masks were 0, so 0x3e2 was ORed into the reset value 0xbff and both
SerDes stayed off on boards without 10G ports (n_10g == 0), e.g. the
HC-SWTG124AS. With SDS 0 off RTL837X_REG_SEC_COUNTER does not hold a
written value: it reads 0, so NTP never retried after a failed first
attempt at boot and froze the clock after a sync.

Tested with regset on an HC-SWTG124AS: the register keeps a write with
SDS 0 in SGMII or 10GR, not with SDS 0 off (also not with only SDS 1
on).
2026-10-24 08:30:27 +02:00
robs 0da6318777 Web UI: keep Firefox from autofilling the new admin password
Firefox filled a saved login into the System tab's password fields and
its user name into the NTP poll interval, the input before them. That
input event marked the Time card as edited, so ntpLoad() left NTP off,
the server empty and the time zone at UTC-12:00.
2026-10-24 01:20:45 +02:00
Luca S. d13a5d125d Add KeepLink KP-9000-9XHP-X as brand of POE-2G080110GS 2026-10-24 00:21:28 +02:00
Kamikaze94 7b0a07efaa Merge branch 'logicog:main' into bugfix/sidebar-scrolling 2026-10-22 01:37:32 +02:00
dobodu 3deee14f94 French translation update
Add LLDP
Add storm control
Add NTP and syslog 
translations
2026-10-21 10:49:29 +02:00
avicarmeli 827d3b389c Fix Makefile test list continuation after merge 2026-10-20 16:55:24 +03:00
avicarmeli ef224ec8f4 Merge branch 'main' into fix/cpu-vlan-init 2026-10-20 16:44:04 +03:00
Kamikaze94 a1998c70d7 WebUI: Lock sidebar layout and move scrolling to main element 2026-10-19 00:51:19 +02:00
bloqaudio 196d22d7c3 web: keep LLDP lines from piling up in the saved configuration
Save to flash merges the running log into the startup configuration.
Neither its toggle nor its overwrite rules knew "lldp on|off", so every
switch of LLDP added another line: four switches left four lines.
"port <n> lldp permit|block" fell under the rule for "port <n> <speed>",
so setting a port's speed dropped its LLDP setting from the saved
configuration, and the other way round.

"lldp on|off" is now a toggle, and a per-port LLDP setting replaces only
an earlier per-port LLDP setting of that port.
2026-10-16 10:43:08 -05:00
bloqaudio 680a40dab5 web: highlight Save to flash only when there are unsaved changes
The button in the header was always drawn as the primary action, on
every page, so it competed with each page's own buttons, for example
the upload button on the Firmware page. It is now a plain button and
turns primary together with the "unsaved changes" badge.
2026-10-15 00:12:14 -05:00
bloqaudio 97b15f4022 web: give each packet counter of a port its own line
The port tooltip and the port details showed "TX good / bad: 8794 / 0
pkts", which reads as 8794 bad packets. Each counter now has its own
line, labelled as on the Statistics page, and the two strings only that
line used are removed from every language.
2026-10-15 00:11:04 -05:00
bloqaudio d5ccd38dd3 web: right-align the headers of number columns
"table.t th" sets text-align:left and is more specific than ".num", so
the headers of the counter columns on the dashboard and the statistics
page stayed left-aligned above right-aligned values.
2026-10-14 23:48:46 -05:00
avicarmeli 6bae5c5c90 test: run CPU VLAN variants in the standard host suite 2026-10-12 20:16:21 +03:00
bloqaudio c2980e42d8 mirror: show the configured monitor port in "mirror status"
"mirror status" printed the local mirroring_port, which is still 0 at
that point, so it named the same port whatever was configured. Print
the port from RTL837x_MIRROR_CTRL instead, which the function has
already read to tell whether mirroring is enabled. send_mirror() decodes
the register the same way for the web interface.
2026-10-12 12:02:02 -05:00
avicarmeli 875933b9f9 fix: initialize CPU MAC9 VLAN state independently of user port count 2026-10-12 10:43:42 +03:00
bloqaudio d0374541c5 uip: rate-limit the dropped-fragment log
uip has no reassembly, so every fragment it receives is discarded and
logged. A neighbour that broadcasts fragmented traffic therefore produces a
continuous stream of "ip: fragment dropped." rather than an occasional one,
at roughly thirteen lines a second on a quiet segment, which buries every
other console message.

The message carries real information: a sudden burst of it says something
about the network. What carries none is repeating it per fragment. Report
the count once per five second window instead, which keeps the signal and
ends the flood.

The count is printed through the no_syslog primitives, as the original
message was, so the flood cannot move from the console into the log ring.
itoa() writes through write_char(), which also feeds the ring, so it gets
a no_syslog twin beside it rather than a private copy of its digits.
2026-09-25 08:20:27 -05:00
39 changed files with 885 additions and 91 deletions

No files matched your search

+1
View File
@@ -3,6 +3,7 @@
.gitattributes .gitattributes
.github/ .github/
output/ output/
toolchain/
installer/output/ installer/output/
*.bin *.bin
html_data.c html_data.c
+10 -2
View File
@@ -29,7 +29,12 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
apt update apt update
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y apt install make gcc g++ bison flex libboost-dev patch bzip2 curl ca-certificates xxd python-is-python3 libjson-c-dev zlib1g-dev -y
- name: Cache the patched SDCC
uses: actions/cache@v4
with:
path: branch/toolchain
key: sdcc-${{ hashFiles('branch/sdcc/*') }}
- name: Run the host-side unit tests - name: Run the host-side unit tests
run: cd branch && make -C test run: cd branch && make -C test
- name: Check that every machine definition can be compiled - name: Check that every machine definition can be compiled
@@ -41,7 +46,10 @@ jobs:
- name: Make project with the health instrumentation - name: Make project with the health instrumentation
run: cd branch && make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1 run: cd branch && make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1
- name: Make main - name: Make main
run: cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map run: |
ln -s ../branch/toolchain main/toolchain
PATH="$(echo "$PWD"/branch/toolchain/sdcc-*/bin):$PATH"
cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map
- name: Calculate bank growth - name: Calculate bank growth
run: | run: |
sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV" sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV"
+1
View File
@@ -2,6 +2,7 @@
.idea/ .idea/
output/ output/
output-main/ output-main/
toolchain/
html_data.c html_data.c
html_data.h html_data.h
version.h version.h
+9
View File
@@ -25,7 +25,16 @@
## Fixed ## Fixed
- Time
- `rtl8372_init()` sets SDS 0 to SGMII as the stock firmware does. The masks were 0, so on RTL8372
boards without 10G ports both SerDes stayed off, and with SDS 0 off `RTL837X_REG_SEC_COUNTER`
does not hold a written value: NTP never retried after a failed first attempt at boot and
froze the clock after a sync.
- Web UI - Web UI
- Firefox no longer fills a saved login into the new admin password fields. It also put the
user name into the NTP poll interval, which marked the Time card as edited, so it kept its
defaults (NTP off, no server, UTC-12:00) instead of the switch's settings.
- Accept firmware uploads regardless of the file part's MIME type, including - Accept firmware uploads regardless of the file part's MIME type, including
`application/macbinary` sent by Chrome on macOS for `.bin` files. `application/macbinary` sent by Chrome on macOS for `.bin` files.
+8 -1
View File
@@ -3,7 +3,14 @@ FROM debian:13-slim
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
make \ make \
gcc \ gcc \
sdcc \ g++ \
bison \
flex \
libboost-dev \
patch \
bzip2 \
curl \
ca-certificates \
xxd \ xxd \
python3 \ python3 \
libjson-c-dev \ libjson-c-dev \
+35 -13
View File
@@ -4,8 +4,11 @@ DEFAULT_CONFIG_LOCATION = 454656
CONFIG_LOCATION = 458752 CONFIG_LOCATION = 458752
HTML_LOCATION = 262144 HTML_LOCATION = 262144
SDCC_PREFIX = toolchain/sdcc-$(shell cat sdcc/* | cksum | cut -d' ' -f1)
ifeq ($(origin CC),default) ifeq ($(origin CC),default)
CC = sdcc SDCC = $(SDCC_PREFIX)/bin/sdcc
CC = $(SDCC)
ASM = $(SDCC_PREFIX)/bin/sdas8051
endif endif
CC_FLAGS = -mmcs51 -I. -Imachine -Ihttpd -Iuip CC_FLAGS = -mmcs51 -I. -Imachine -Ihttpd -Iuip
ASM ?= sdas8051 ASM ?= sdas8051
@@ -72,7 +75,7 @@ all: create_build_dir $(VERSION_HEADER) $(MACHINE_SRC) $(SUBDIRS) $(BUILDDIR)/rt
bank_size: bank_size:
tools/bank_occupancy.sh "$(MACHINE)" tools/bank_occupancy.sh "$(MACHINE)"
create_build_dir: create_build_dir: $(SDCC)
mkdir -p "$(BUILDDIR)" mkdir -p "$(BUILDDIR)"
mkdir -p "$(BUILDDIR)/uip" mkdir -p "$(BUILDDIR)/uip"
mkdir -p "$(BUILDDIR)/httpd" mkdir -p "$(BUILDDIR)/httpd"
@@ -102,6 +105,7 @@ SRCS = \
sfp.c \ sfp.c \
dns.c \ dns.c \
dns_cli.c \ dns_cli.c \
sessions.c \
ntp.c \ ntp.c \
ntp_cli.c \ ntp_cli.c \
syslog.c \ syslog.c \
@@ -145,13 +149,23 @@ HTML := $(shell find html -name '*.js' -or -name '*.html' -or -name '*.svg' -or
# The raw html/ sources stay untouched for development; the minified # The raw html/ sources stay untouched for development; the minified
# copy is a build artifact under output/. # copy is a build artifact under output/.
HTML_MIN := $(BUILDDIR)/html_min HTML_MIN := $(BUILDDIR)/html_min
HTML_MIN_LIST := $(BUILDDIR)/html_min.list
HTML_MIN_STAMP := $(BUILDDIR)/html_min.stamp
.PHONY: html_min .PHONY: html_min
html_min: $(HTML) html_min: $(HTML_MIN_STAMP)
$(HTML_MIN_LIST): FORCE
@mkdir -p $(BUILDDIR)
@echo $(sort $(HTML)) > $@.tmp
@cmp -s $@.tmp $@ && rm -f $@.tmp || mv $@.tmp $@
$(HTML_MIN_STAMP): $(HTML) $(HTML_MIN_LIST) tools/minify.py $(if $(wildcard $(HTML_MIN)),,FORCE)
rm -rf $(HTML_MIN) rm -rf $(HTML_MIN)
mkdir -p $(HTML_MIN) mkdir -p $(HTML_MIN)
@for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done @for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done
@touch $@
html_data.c html_data.h &: $(HTML) | tools html_min html_data.c html_data.h &: $(HTML_MIN_STAMP) | tools
tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
$(VERSION_HEADER): FORCE $(VERSION_HEADER): FORCE
@@ -169,12 +183,18 @@ $(SUBDIRS):
$(MAKE) -C $@ BUILDDIR=$(BUILDDIR) $(MAKE) -C $@ BUILDDIR=$(BUILDDIR)
clean: $(SUBDIRSCLEAN) clean: $(SUBDIRSCLEAN)
-rm -f html_data.c html_data.h $(VERSION_HEADER) -rm -f html_data.c html_data.h $(VERSION_HEADER) $(HTML_MIN_LIST) $(HTML_MIN_STAMP)
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi -if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
distclean: $(SUBDIRSCLEAN) distclean: $(SUBDIRSCLEAN)
-rm -f html_data.c html_data.h $(VERSION_HEADER) -rm -f html_data.c html_data.h $(VERSION_HEADER) $(HTML_MIN_LIST) $(HTML_MIN_STAMP)
-rm -rf $(BUILDDIR) -rm -rf $(BUILDDIR)
-rm -rf toolchain
ifneq ($(SDCC),)
$(SDCC):
sh sdcc/build.sh $(abspath $(SDCC_PREFIX))
endif
$(SUBDIRSCLEAN): $(SUBDIRSCLEAN):
$(MAKE) -C $(@:clean=) clean $(MAKE) -C $(@:clean=) clean
@@ -214,16 +234,18 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir .PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir
# Every machine/ definition is compiled, so a machine added to machine/ is # Every machine/ definition is compiled, so a machine added to machine/ is
# covered without registering it anywhere. The _init.c files are excluded here: # covered without registering it anywhere. A board only counts once both its
# they are the boot hooks, compiled separately below (the board's own if it # <machine>.c and its <machine>.h are present: the header is what the rest of
# exists, otherwise default_machine_init.c). The machine-specific defines are # the build includes, so a .c without one is an incomplete board. The _init.c
# filtered out of $(CC_FLAGS) and supplied per iteration instead, so this also # files are excluded here: they are the boot hooks, compiled separately below
# works as "make machine_check MACHINE=...". # (the board's own if it exists, otherwise default_machine_init.c). The
MACHINE_DEFS := $(sort $(patsubst machine/%.c,%,$(filter-out machine/%_init.c,$(wildcard machine/*.c)))) # machine-specific defines are filtered out of $(CC_FLAGS) and supplied per
# iteration instead, so this also works as "make machine_check MACHINE=...".
MACHINE_DEFS := $(sort $(filter $(patsubst machine/%.h,%,$(wildcard machine/*.h)),$(patsubst machine/%.c,%,$(filter-out machine/%_init.c,$(wildcard machine/*.c)))))
MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS)) MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS))
.PHONY: machine_check .PHONY: machine_check
machine_check: machine_check: $(SDCC)
@mkdir -p $(BUILDDIR)/tmp @mkdir -p $(BUILDDIR)/tmp
@set -eo pipefail; \ @set -eo pipefail; \
for MACHINE in $(MACHINE_DEFS); \ for MACHINE in $(MACHINE_DEFS); \
+10 -3
View File
@@ -56,12 +56,19 @@ device simulator is provided, which runs entirely under Linux as a local webserv
## (0) Compiling Requirements ## (0) Compiling Requirements
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04 Install the following particular build requisites (Debian 12/13):
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 zlib1g-dev sudo apt install make gcc g++ bison flex libboost-dev patch bzip2 curl xxd python-is-python3 libjson-c-dev zlib1g-dev
``` ```
The first `make` downloads SDCC 4.6.0, applies the fixes in `sdcc/` and builds it into
`toolchain/`, which takes a few minutes. Later builds reuse it. The released SDCC 4.5.0
and 4.6.0 miscompile parts of this code, see [SDCC bug #4153](https://sourceforge.net/p/sdcc/bugs/4153/)
and [#4154](https://sourceforge.net/p/sdcc/bugs/4154/); both fixes are in SDCC trunk since
r17039. The third patch is for [#4070](https://sourceforge.net/p/sdcc/bugs/4070/), where the
assembler drops the top byte of a `__sfr32` address list; it is proposed upstream and lets
`SFR_DATA_U32` be used again. To use an SDCC you installed yourself instead, run `make CC=sdcc ...`.
<details> <details>
<summary>If using Docker (click to expand)</summary> <summary>If using Docker (click to expand)</summary>
+5 -1
View File
@@ -24,6 +24,7 @@
#include "sfp.h" #include "sfp.h"
#include "dhcp.h" #include "dhcp.h"
#include "syslog.h" #include "syslog.h"
#include "sessions.h"
#include "dns.h" #include "dns.h"
#include "ntp.h" #include "ntp.h"
#include "uip/uip.h" #include "uip/uip.h"
@@ -849,7 +850,7 @@ void parse_mirror(void)
print_string("NOT Enabled: "); print_string("NOT Enabled: ");
} }
print_string("Mirroring port: "); print_string("Mirroring port: ");
print_phys_port(mirroring_port); print_phys_port(mPort >> 1);
reg_read_m(RTL837x_MIRROR_CONF); reg_read_m(RTL837x_MIRROR_CONF);
uint16_t m = sfr_data[0]; uint16_t m = sfr_data[0];
m = (m << 8) | sfr_data[1]; m = (m << 8) | sfr_data[1];
@@ -1479,6 +1480,9 @@ void parse_passwd(void)
passwd[j++] = c; passwd[j++] = c;
} while (c != NUL && j < 20); } while (c != NUL && j < 20);
passwd[j] = NUL; passwd[j] = NUL;
/* Logins made with the old password end here. With one session the next
* login pushed a leftover one out; with several it would stay valid. */
session_init();
return; return;
} }
cmd_error("Missing password\n"); cmd_error("Missing password\n");
+2
View File
@@ -1,11 +1,13 @@
# MokerLink POE-2G080110GS # MokerLink POE-2G080110GS
The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware. The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware.
The`KP-9000-9XHP-X` is the KeepLink rebrand for same product.
## Brands ## Brands
| Brand | Type |Managed| PCB | Flash | Chip RTL | | Brand | Type |Managed| PCB | Flash | Chip RTL |
|--------|------------------|-------|------------------|-----------------|---------------| |--------|------------------|-------|------------------|-----------------|---------------|
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N | | Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
| KeepLink | KP-9000-9XHP-X | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
## Hardware overview ## Hardware overview
Front Front
+93
View File
@@ -0,0 +1,93 @@
# PCB-AFGW SWTG218ANS V2.0.2
RTL8373-based 8×2.5G PoE + 1×10G SFP+ web-managed switch, sold as the
**RealHD PSW8-25MG**.
### Label specifications
- **Manufacturer**: RealHD
- **Model**: PSW8-25MG
- **PCB marking**: `PCB-AFGW SWTG218ANS_V2.0.2` (silkscreened as `PCB-AFGW SWTG218ANS_V2.0.2_23308`)
- **Ports**:
- 8 × RJ45: 10/100/1000/2500 Mbps with PoE
- 1 × SFP+: 1G / 2.5G / 10G (front panel marking `9(10G)`)
- **Power input**: internal AC PSU, `100-240V~ 50/60Hz 2A MAX`, DC output `53.5V 2.8A 150W`
- **Front panel LEDs**: `PWR`, `SYS`, per RJ45 port `Link/Act` and `PoE`, per SFP port 2.5G (green) and 10G (blue)
- **Stock firmware defaults**: web-managed PoE switch
### What works
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE is not configurable via RTLPlayground)
- SFP+ port supporting 1G, 2.5G and 10G modules
- LEDs: green (2.5G) and amber (1G/100M/10M) per RJ45 port with activity, green (1G/2.5G) and blue (10G) on the SFP port, plus the `SYS` LED
### Photos
Front panel:
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/device_front.jpg" width="800" />
Board mounted in the case, with the internal PSU above it:
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/dev_top_w_pcb.jpg" width="800" />
### PCB overview
Top side:
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/pcb_front.jpg" width="800" />
Bottom side:
<img src="photos/PCB-AFGW_SWTG218ANS_V2.0.2/pcb_back.jpg" width="800" />
A 4-pad UART header with `RXD` / `TXD` silkscreened sits next to the right heatsink.
### Port layout
| Logical port | Physical port | Type |
|--------------|---------------|--------|
| 1-8 | 1-8 | RJ45 |
| 9 | 9 | SFP+ |
### LED configuration
RJ45 ports use LED SET0, the SFP+ port uses LED SET1. The board needs the custom
LED mux (`led_mux_custom = 1`), and `RTL837X_REG_LED_GLB_IO_EN` is written to
`0x7f24977f` in `machine_custom_init()` so the LED pins are enabled as wired here.
| SET | LED pin 0 | LED pin 1 |
|------|-----------------------------------------------|-------------------------------------------------------|
| SET0 | Green — lights on 2.5G link with activity | Amber — lights on 1G / 100M / 10M link with activity |
| SET1 | All speeds — lights on any link with activity | 10G — lights on 10G link with activity |
On the front panel this gives one bi-color `Link/Act` LED per RJ45 port (green at
2.5G, amber at 10/100/1000M, blinking with activity) and one `PoE` LED per RJ45
port, which is driven by the PoE hardware and not by the switch. The SFP+ port has
a green 2.5G LED and a blue 10G LED.
### SFP GPIO assignments
| SFP (logical 9) | pin_detect (ModAbs) | pin_los | pin_tx_disable | SerDes | I2C SDA | I2C SCL |
|-----------------|---------------------|---------|----------------|--------|------------------|----------------------|
| SFP | GPIO38 | GPIO_NA | GPIO_NA | SDS1 | GPIO39_I2C_SDA4 | GPIO40_I2C_SCL3_MDC1 |
### Machine configuration
```
make MACHINE=REALHD_PSW8_25MG
```
### Programming
The serial console runs at 8N1 on 115200 baud with the RTLPlayground firmware
(see the UART header note under *PCB overview*). The stock firmware baud rate 57600. The flash chip was 2MB.
### PoE
The 8 RJ45 ports support PoE, powered by the internal 150W AC PSU (DC output
53.5V 2.8A) mounted above the main board.
Note: RTLPlayground does not provide PoE management for this board. The PoE
hardware runs with its own configuration, the same as on the other PoE boards in
this project.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

+2
View File
@@ -29,6 +29,7 @@ The following devices have been tested and are fully working:
| 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-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 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 |
| keepLINK | KP-9000-9XHP-X | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
| LIANGUO | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 | | LIANGUO | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 | | LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
| LIANGUO | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 | | LIANGUO | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
@@ -38,6 +39,7 @@ The following devices have been tested and are fully working:
| MokerLink| 2G08110GSN | No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 0.5M | 8 + 1 | | MokerLink| 2G08110GSN | No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | 0.5M | 8 + 1 |
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 | | Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
| ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 | | ONT | ONT-S207CW-62TS-SE | No | [PCB-SWTG024AS-A-2.0.1](devices/ONT-S207CW-62TS-SE.md) | 0.5M | 4 + 2 |
| RealHD | PSW8-25MG | Yes | [PCB-AFGW SWTG218ANS V2.0.2](devices/PCB-AFGW_SWTG218ANS_V2.0.2.md) | 2M | 8 + 1 |
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 | | Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 | | Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
| SICSOLINK| SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 | | SICSOLINK| SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
+5 -2
View File
@@ -79,8 +79,11 @@ JSON polling of the visible section).
computation no longer depends on uninitialised buffer content. computation no longer depends on uninitialised buffer content.
- `version.h` is now written by a single atomic `printf` (change from - `version.h` is now written by a single atomic `printf` (change from
upstream) instead of five separate `echo`s, so a parallel build upstream) instead of five separate `echo`s, so a parallel build
(`make -j`) can no longer read a half-written copy. It stays in (`make -j`) can no longer read a half-written copy. It depends on
`.PHONY` so it is regenerated on every build. `FORCE`, so its recipe runs on every build, but the file is only
rewritten when its content changes. The minified copy in
`output/html_min/` is redone only when a web file, the list of web
files or `tools/minify.py` changes.
## Verification ## Verification
+28 -13
View File
@@ -16,7 +16,7 @@ d_system:"System",d_traffic:"Traffic",
d_traffic_h:"packets/s, live",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX bad",d_rxbad:"RX bad", d_traffic_h:"packets/s, live",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX bad",d_rxbad:"RX bad",
i_host:"Hostname",i_ip:"IP address",i_mask:"Netmask",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware", i_host:"Hostname",i_ip:"IP address",i_mask:"Netmask",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware",
i_built:"Built",i_hw:"Hardware",i_temp:"Temperature",i_flash:"Flash",i_syslog:"Syslog", i_built:"Built",i_hw:"Hardware",i_temp:"Temperature",i_flash:"Flash",i_syslog:"Syslog",
p_state:"State",p_disabled:"disabled",p_up:"up",p_txgb:"TX good / bad",p_rxgb:"RX good / bad", p_state:"State",p_disabled:"disabled",p_up:"up",
p_pkts:"pkts",p_module:"Module",p_temp:"Temperature",p_vcc:"Vcc",p_txbias:"TX bias",p_txpower:"TX power", p_pkts:"pkts",p_module:"Module",p_temp:"Temperature",p_vcc:"Vcc",p_txbias:"TX bias",p_txpower:"TX power",
p_rxpower:"RX power",p_txfault:"TX fault",p_txdis:"TX disabled",p_rxlos:"RX LOS",p_adv:"Advertising", p_rxpower:"RX power",p_txfault:"TX fault",p_txdis:"TX disabled",p_rxlos:"RX LOS",p_adv:"Advertising",
pt_title:"Port configuration",pt_conn:"Devices learned",pt_speed:"Speed",pt_mtu:"MTU", pt_title:"Port configuration",pt_conn:"Devices learned",pt_speed:"Speed",pt_mtu:"MTU",
@@ -147,7 +147,7 @@ d_system:"システム",d_traffic:"トラフィック",
d_traffic_h:"パケット/秒、リアルタイム",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 異常",d_rxbad:"RX 異常", d_traffic_h:"パケット/秒、リアルタイム",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 異常",d_rxbad:"RX 異常",
i_host:"ホスト名",i_ip:"IP アドレス",i_mask:"ネットマスク",i_gw:"ゲートウェイ",i_mac:"MAC",i_fw:"ファームウェア", i_host:"ホスト名",i_ip:"IP アドレス",i_mask:"ネットマスク",i_gw:"ゲートウェイ",i_mac:"MAC",i_fw:"ファームウェア",
i_built:"ビルド日",i_hw:"ハードウェア",i_temp:"温度",i_flash:"フラッシュ",i_syslog:"Syslog", i_built:"ビルド日",i_hw:"ハードウェア",i_temp:"温度",i_flash:"フラッシュ",i_syslog:"Syslog",
p_state:"状態",p_disabled:"無効",p_up:"アップ",p_txgb:"TX 正常 / 異常",p_rxgb:"RX 正常 / 異常", p_state:"状態",p_disabled:"無効",p_up:"アップ",
p_pkts:"pkts",p_module:"モジュール",p_temp:"温度",p_vcc:"電圧",p_txbias:"TX バイアス",p_txpower:"TX 電力", p_pkts:"pkts",p_module:"モジュール",p_temp:"温度",p_vcc:"電圧",p_txbias:"TX バイアス",p_txpower:"TX 電力",
p_rxpower:"RX 電力",p_txfault:"TX 障害",p_txdis:"TX 無効",p_rxlos:"RX 信号ロス",p_adv:"アドバタイズ", p_rxpower:"RX 電力",p_txfault:"TX 障害",p_txdis:"TX 無効",p_rxlos:"RX 信号ロス",p_adv:"アドバタイズ",
pt_title:"ポート設定",pt_conn:"学習済みデバイス",pt_speed:"速度",pt_mtu:"MTU", pt_title:"ポート設定",pt_conn:"学習済みデバイス",pt_speed:"速度",pt_mtu:"MTU",
@@ -260,7 +260,7 @@ d_system:"系统",d_traffic:"流量",
d_traffic_h:"包/秒,实时",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 错误",d_rxbad:"RX 错误", d_traffic_h:"包/秒,实时",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 错误",d_rxbad:"RX 错误",
i_host:"主机名",i_ip:"IP 地址",i_mask:"子网掩码",i_gw:"网关",i_mac:"MAC",i_fw:"固件", i_host:"主机名",i_ip:"IP 地址",i_mask:"子网掩码",i_gw:"网关",i_mac:"MAC",i_fw:"固件",
i_built:"构建日期",i_hw:"硬件",i_temp:"温度",i_flash:"Flash",i_syslog:"Syslog", i_built:"构建日期",i_hw:"硬件",i_temp:"温度",i_flash:"Flash",i_syslog:"Syslog",
p_state:"状态",p_disabled:"已禁用",p_up:"已连接",p_txgb:"TX 正常 / 错误",p_rxgb:"RX 正常 / 错误", p_state:"状态",p_disabled:"已禁用",p_up:"已连接",
p_pkts:"个包",p_module:"模块",p_temp:"温度",p_vcc:"供电电压",p_txbias:"TX 偏置电流",p_txpower:"TX 光功率", p_pkts:"个包",p_module:"模块",p_temp:"温度",p_vcc:"供电电压",p_txbias:"TX 偏置电流",p_txpower:"TX 光功率",
p_rxpower:"RX 光功率",p_txfault:"TX 故障",p_txdis:"TX 禁用",p_rxlos:"RX 信号丢失",p_adv:"通告能力", p_rxpower:"RX 光功率",p_txfault:"TX 故障",p_txdis:"TX 禁用",p_rxlos:"RX 信号丢失",p_adv:"通告能力",
pt_title:"端口配置",pt_conn:"已学习设备",pt_speed:"速率",pt_mtu:"MTU", pt_title:"端口配置",pt_conn:"已学习设备",pt_speed:"速率",pt_mtu:"MTU",
@@ -373,7 +373,7 @@ d_system:"Sistema",d_traffic:"Tráfico",
d_traffic_h:"paquetes/s, en vivo",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX erróneos",d_rxbad:"RX erróneos", d_traffic_h:"paquetes/s, en vivo",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX erróneos",d_rxbad:"RX erróneos",
i_host:"Nombre de host",i_ip:"Dirección IP",i_mask:"Máscara de red",i_gw:"Puerta de enlace",i_mac:"MAC",i_fw:"Firmware", i_host:"Nombre de host",i_ip:"Dirección IP",i_mask:"Máscara de red",i_gw:"Puerta de enlace",i_mac:"MAC",i_fw:"Firmware",
i_built:"Compilado",i_hw:"Hardware",i_flash:"Flash",i_syslog:"Syslog", i_built:"Compilado",i_hw:"Hardware",i_flash:"Flash",i_syslog:"Syslog",
p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo",p_txgb:"TX correctos / erróneos",p_rxgb:"RX correctos / erróneos", p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo",
p_pkts:"paquetes",p_module:"Módulo",p_temp:"Temperatura",p_vcc:"Vcc",p_txbias:"Polarización TX",p_txpower:"Potencia TX", p_pkts:"paquetes",p_module:"Módulo",p_temp:"Temperatura",p_vcc:"Vcc",p_txbias:"Polarización TX",p_txpower:"Potencia TX",
p_rxpower:"Potencia RX",p_txfault:"Fallo TX",p_txdis:"TX deshabilitado",p_rxlos:"Pérdida RX (LOS)",p_adv:"Anunciado", p_rxpower:"Potencia RX",p_txfault:"Fallo TX",p_txdis:"TX deshabilitado",p_rxlos:"Pérdida RX (LOS)",p_adv:"Anunciado",
pt_title:"Configuración de puerto",pt_conn:"Dispositivos aprendidos",pt_speed:"Velocidad",pt_mtu:"MTU", pt_title:"Configuración de puerto",pt_conn:"Dispositivos aprendidos",pt_speed:"Velocidad",pt_mtu:"MTU",
@@ -472,7 +472,7 @@ fw_timeout:"el switch no ha vuelto tras 150 s: comprueba la alimentación / cons
fr:{ fr:{
nav_dash:"Tableau de bord",nav_ports:"Ports",nav_stp:"Arborescence",nav_stats:"Statistiques", nav_dash:"Tableau de bord",nav_ports:"Ports",nav_stp:"Arborescence",nav_stats:"Statistiques",
nav_vlan:"LANs virtuels",nav_l2:"Table MAC",nav_mirror:"Mise en mirroir",nav_lag:"Aggrégation",nav_eee:"Energie", nav_vlan:"LANs virtuels",nav_l2:"Table MAC",nav_mirror:"Mise en mirroir",nav_lag:"Aggrégation",nav_eee:"Energie",
nav_bw:"Bande passante",nav_system:"Système",nav_fw:"Micro logiciel", nav_bw:"Bande passante",nav_system:"Système",nav_fw:"Micro logiciel",nav_lldp:"Couche de Liaison",
hdr_dirty:"Changements non sauvegardés",hdr_dirty_t:"La configuration utilisée diffère de celle au démarrage", hdr_dirty:"Changements non sauvegardés",hdr_dirty_t:"La configuration utilisée diffère de celle au démarrage",
hdr_save:"Sauvegarder en flash",hdr_save_t:"Maintenir la configuration actuelle en flash", hdr_save:"Sauvegarder en flash",hdr_save_t:"Maintenir la configuration actuelle en flash",
th_auto:"Système",th_auto_sel:"Système (sélénisé)",sy_display:"Affichage",sy_theme:"Thème",sy_display_note:"Enregistré seulement dans ce navigateur.",th_light:"Clair",th_dark:"Sombre", th_auto:"Système",th_auto_sel:"Système (sélénisé)",sy_display:"Affichage",sy_theme:"Thème",sy_display_note:"Enregistré seulement dans ce navigateur.",th_light:"Clair",th_dark:"Sombre",
@@ -485,7 +485,7 @@ d_system:"Système",d_traffic:"Trafic",
d_traffic_h:"paquets/s (en direct)",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX KO",d_rxbad:"RX KO", d_traffic_h:"paquets/s (en direct)",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX KO",d_rxbad:"RX KO",
i_host:"Nom d'hote",i_ip:"Adresse IP",i_mask:"Masque réseau",i_gw:"Passerelle",i_mac:"Adresse MAC",i_fw:"Micro logiciel", i_host:"Nom d'hote",i_ip:"Adresse IP",i_mask:"Masque réseau",i_gw:"Passerelle",i_mac:"Adresse MAC",i_fw:"Micro logiciel",
i_built:"Compilé le",i_hw:"Matériel",i_temp:"Température",i_flash:"Taille Flash",i_syslog:"Journal système", i_built:"Compilé le",i_hw:"Matériel",i_temp:"Température",i_flash:"Taille Flash",i_syslog:"Journal système",
p_state:"Etat",p_disabled:"Inactif",p_up:"Actif",p_txgb:"TX bon / mauvais",p_rxgb:"RX bon / mauvais", p_state:"Etat",p_disabled:"Inactif",p_up:"Actif",
p_pkts:"paquets",p_module:"Module",p_temp:"Température",p_vcc:"Vcc",p_txbias:"TX biais",p_txpower:"TX puissance", p_pkts:"paquets",p_module:"Module",p_temp:"Température",p_vcc:"Vcc",p_txbias:"TX biais",p_txpower:"TX puissance",
p_rxpower:"RX puissance",p_txfault:"TX erreur",p_txdis:"TX désactivé",p_rxlos:"RX pertes de signaux",p_adv:"Capacités", p_rxpower:"RX puissance",p_txfault:"TX erreur",p_txdis:"TX désactivé",p_rxlos:"RX pertes de signaux",p_adv:"Capacités",
pt_title:"Configuration du port",pt_conn:"Appareils appris",pt_speed:"Vitesse",pt_mtu:"MTU", pt_title:"Configuration du port",pt_conn:"Appareils appris",pt_speed:"Vitesse",pt_mtu:"MTU",
@@ -509,6 +509,7 @@ stp_en_q:"Activer l'arbrescence?",
stp_en_d:"Les ports sont d'abord bloqués et cela prend deux fois le délai de retransmission pour atteindre l'état de retransmission; les ports en bordures recouvrent immédiatement leur état.", stp_en_d:"Les ports sont d'abord bloqués et cela prend deux fois le délai de retransmission pour atteindre l'état de retransmission; les ports en bordures recouvrent immédiatement leur état.",
stp_dis_q:"Désactiver l'arborescence ?",stp_dis_d:"Tous les ports vont être retransmis; la protection de boucles est perdue.", stp_dis_q:"Désactiver l'arborescence ?",stp_dis_d:"Tous les ports vont être retransmis; la protection de boucles est perdue.",
stp_cost_err:"Le coût du chemin doit être compris entre 0 et 200000000", stp_cost_err:"Le coût du chemin doit être compris entre 0 et 200000000",
lldp_enabled: "Activer LLDP",lldp_title:"Protocole de découverte de la couche de liason (LLDP)",lldp_portname:"Nom",lldp_enable:"Envoi de trames",
st_title:"Statiqtique du port",st_h:"cumul depuis le démarrage",st_txg:"TX OK",st_txb:"TX KO",st_rxg:"RX OK", st_title:"Statiqtique du port",st_h:"cumul depuis le démarrage",st_txg:"TX OK",st_txb:"TX KO",st_rxg:"RX OK",
st_rxb:"RX KO",st_details:"Détails",st_counters:"Compteur MIB",st_nonzero:"non-zero seulement", st_rxb:"RX KO",st_details:"Détails",st_counters:"Compteur MIB",st_nonzero:"non-zero seulement",
st_autoref:"rafraichissement automatique",st_counter:"Compteur",st_value:"Valeur",st_fail:"Erreur au chargement des compteurs", st_autoref:"rafraichissement automatique",st_counter:"Compteur",st_value:"Valeur",st_fail:"Erreur au chargement des compteurs",
@@ -542,6 +543,9 @@ e_idle:"Inactif",e_na:"N/A",
bw_title:"Limitations de bande passante",bw_h:"Mbit/s, 0.016-10000",bw_in:"Limite entrante",bw_out:"Limite sortante", bw_title:"Limitations de bande passante",bw_h:"Mbit/s, 0.016-10000",bw_in:"Limite entrante",bw_out:"Limite sortante",
bw_exceed:"Lorsque dépassé",bw_fc:"Limiter",bw_drop:"Rejetter", bw_exceed:"Lorsque dépassé",bw_fc:"Limiter",bw_drop:"Rejetter",
bw_in_err:"La limite entrante doit être comprise entre 0.016 et 10000 Mbit/s",bw_out_err:"La limite sortante doit être comprise entre 0.016 et 10000 Mbit/s", bw_in_err:"La limite entrante doit être comprise entre 0.016 et 10000 Mbit/s",bw_out_err:"La limite sortante doit être comprise entre 0.016 et 10000 Mbit/s",
sc_title:"Contrôle des tempêtes",sc_h:"par port et par type de diffusion (générale ou groupée), vide = inactif",sc_bcast:"Générale (Broadcast)",sc_mcast:"Groupée (Multicast)",
sc_ucast:"Unicast inconnu",sc_umcast:"Multicast inconnu",sc_err:" La limite de tempête doit être comprise entre 1 à 1048575 pps ou 1 à 10000000 kbit/s",
sc_note:"Les trames de chacun des types ci-dessus dépassant les limites sont abandonnées lorsqu'elles arrivent sur le communtateur.",
sy_network:"Réseau",sy_dhcp:"Uiliser DHCP",sy_dhcp_t:"Aquérir l'adresse via le protocole DHCP",sy_services:"Services", sy_network:"Réseau",sy_dhcp:"Uiliser DHCP",sy_dhcp_t:"Aquérir l'adresse via le protocole DHCP",sy_services:"Services",
sy_igmp:"Surveillance IGMP",sy_sysip:"IP du serveur...",sy_server:"Serveur",sy_port:"Port", sy_igmp:"Surveillance IGMP",sy_sysip:"IP du serveur...",sy_server:"Serveur",sy_port:"Port",
sy_sesstmo:"Temps mort de session (s)",sy_sesstmo_err:"Le temps morts de session doit être compris en 1-65535 s", sy_sesstmo:"Temps mort de session (s)",sy_sesstmo_err:"Le temps morts de session doit être compris en 1-65535 s",
@@ -555,7 +559,14 @@ sy_ip_err:"Erreur d'IP / masque réseau / passerelle",sy_host_err:"Nom d'hôte :
sy_net_q:"Appliquer les paramètres réseau?",sy_net_d:"L'adresse IP de management va devenir {ip}: merci de réouvrir le page depuis cette adresse.", sy_net_q:"Appliquer les paramètres réseau?",sy_net_d:"L'adresse IP de management va devenir {ip}: merci de réouvrir le page depuis cette adresse.",
sy_ip_changed:"L'adresse IP a changée, reconnectez-vous à http://{ip}/",sy_dhcp_q:"Passer en DHCP?", sy_ip_changed:"L'adresse IP a changée, reconnectez-vous à http://{ip}/",sy_dhcp_q:"Passer en DHCP?",
sy_dhcp_d:"Le commutateur va demander une addresse via le DHCP. Vous devrez rechercher sa prochaine adresse IP pour vous reconnecter.", sy_dhcp_d:"Le commutateur va demander une addresse via le DHCP. Vous devrez rechercher sa prochaine adresse IP pour vous reconnecter.",
sy_sysip_err:"Adresse IP du serveur Syslog invalide",sy_sysport_err:"Le port Syslog doit être compris entre 1 et 65535", sy_sysip_err:"Adresse IP du serveur Syslog invalide",sy_dns1:"DNS principal",sy_dns2:"DNS secondaire",sy_dns_err:"Adresse IP du DNS invalide",sy_dns_dhcp:"émis par le DHCP: {ip}",
sy_time:"Temps",sy_ntp:"NTP",sy_ntpsrv:"Serveur NTP",sy_ntpsrv_p:"Nom d'hôte ou adresse IPv4",sy_ntpint:"intervalle de scrutation [min]",
sy_tz:"Fuseau horaire",sy_dst:"Heure d'été",sy_dst_eu:"Europe",
sy_dst_us:"Etats-Unis",sy_now:"Heure locale",
sy_sync:"Dernière synchronisation",sy_ntpaddr:"Adresse du serveur",sy_nosync:"Désynchronisé",sy_waiting:"En attente du serveur",
sy_ago:"depuis {n} minutes",sy_ntp_err:"Entrez le nom d'hôte ou l'adresse IPv4 du serveur NTP",sy_ntpint_err:"L'intervalle de scrutation doit être compris entre 1 et 1440",
sy_time_note:"Le commutateur n'a pas d'horloge sauvegardée par batterie: L'heure est donc perdue à chaque redémarrage et doit être récupérée grâce au serveur NTP une fois le réseau fonctionnel. Sauvegardez en mémoire flash pour enregistrer les paramètres.",
sy_sysport_err:"Le port Syslog doit être compris entre 1 et 65535",
sy_pw_len:"Mot de passe : 1 à 20 caractères",sy_pw_space:"Le mot de passe ne doit pas contenir d'espaces",sy_pw_match:"Les mots de passe ne correspondent pas", sy_pw_len:"Mot de passe : 1 à 20 caractères",sy_pw_space:"Le mot de passe ne doit pas contenir d'espaces",sy_pw_match:"Les mots de passe ne correspondent pas",
sy_pw_q:"Changer le mot de passe d'administration?",sy_pw_d:"Cela prend effet immédiatement dès la prochaine connection. Enregistrez en Flash pour rendre la modification persistante.", sy_pw_q:"Changer le mot de passe d'administration?",sy_pw_d:"Cela prend effet immédiatement dès la prochaine connection. Enregistrez en Flash pour rendre la modification persistante.",
sy_reboot_q:"Redémarrer le commutateur ?",sy_reboot_d:"Il y a des paramètres NON SAUVEGARDES qui vont être perdus. Sauvegardez-les au préalable en mémoire flash si vous souhaitez les conserver.", sy_reboot_q:"Redémarrer le commutateur ?",sy_reboot_d:"Il y a des paramètres NON SAUVEGARDES qui vont être perdus. Sauvegardez-les au préalable en mémoire flash si vous souhaitez les conserver.",
@@ -602,7 +613,7 @@ d_system:"System",d_traffic:"Datenverkehr",
d_traffic_h:"Pakete/s, live",d_txpps:"TX Pakete/s",d_rxpps:"RX Pakete/s",d_txbad:"TX fehlerhaft",d_rxbad:"RX fehlerhaft", d_traffic_h:"Pakete/s, live",d_txpps:"TX Pakete/s",d_rxpps:"RX Pakete/s",d_txbad:"TX fehlerhaft",d_rxbad:"RX fehlerhaft",
i_host:"Hostname",i_ip:"IP-Adresse",i_mask:"Netzmaske",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware", i_host:"Hostname",i_ip:"IP-Adresse",i_mask:"Netzmaske",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware",
i_built:"Erstellt",i_hw:"Hardware",i_temp:"Temperatur",i_flash:"Flash",i_syslog:"Syslog", i_built:"Erstellt",i_hw:"Hardware",i_temp:"Temperatur",i_flash:"Flash",i_syslog:"Syslog",
p_state:"Zustand",p_disabled:"deaktiviert",p_up:"verbunden",p_txgb:"TX gut / fehlerhaft",p_rxgb:"RX gut / fehlerhaft", p_state:"Zustand",p_disabled:"deaktiviert",p_up:"verbunden",
p_pkts:"Pakete",p_module:"Modul",p_temp:"Temperatur",p_vcc:"Vcc",p_txbias:"TX-Bias",p_txpower:"Sendeleistung", p_pkts:"Pakete",p_module:"Modul",p_temp:"Temperatur",p_vcc:"Vcc",p_txbias:"TX-Bias",p_txpower:"Sendeleistung",
p_rxpower:"Empfangsleistung",p_txfault:"TX-Fehler",p_txdis:"TX deaktiviert",p_rxlos:"RX LOS",p_adv:"Angeboten", p_rxpower:"Empfangsleistung",p_txfault:"TX-Fehler",p_txdis:"TX deaktiviert",p_rxlos:"RX LOS",p_adv:"Angeboten",
pt_title:"Port-Konfiguration",pt_conn:"Gelernte Geräte",pt_speed:"Geschwindigkeit",pt_mtu:"MTU", pt_title:"Port-Konfiguration",pt_conn:"Gelernte Geräte",pt_speed:"Geschwindigkeit",pt_mtu:"MTU",
@@ -836,6 +847,7 @@ function isConfCmd(line){
function setDirty(d){ function setDirty(d){
S.dirty=d; S.dirty=d;
$("dirty").classList.toggle("show",d); $("dirty").classList.toggle("show",d);
$("saveBtn").classList.toggle("pri",d);
} }
function postCmd(cmd,quiet){ function postCmd(cmd,quiet){
return api("/cmd",{method:"POST",body:cmd}).then(function(r){ return api("/cmd",{method:"POST",body:cmd}).then(function(r){
@@ -1024,8 +1036,10 @@ function portRows(p){
var rows=[[t("c_port"),String(p.portNum)],[t("c_type"),p.isSFP?"SFP":"RJ45"]]; var rows=[[t("c_port"),String(p.portNum)],[t("c_type"),p.isSFP?"SFP":"RJ45"]];
if(p.name)rows.push([t("c_name"),p.name]); if(p.name)rows.push([t("c_name"),p.name]);
rows.push([t("p_state"),!p.enabled?t("p_disabled"):(p.link>0?t("p_up")+" "+LINKS[p.link]:t("c_down"))]); rows.push([t("p_state"),!p.enabled?t("p_disabled"):(p.link>0?t("p_up")+" "+LINKS[p.link]:t("c_down"))]);
rows.push([t("p_txgb"),BigInt(p.txG)+" / "+BigInt(p.txB)+" "+t("p_pkts")]); rows.push([t("st_txg"),BigInt(p.txG)+" "+t("p_pkts")]);
rows.push([t("p_rxgb"),BigInt(p.rxG)+" / "+BigInt(p.rxB)+" "+t("p_pkts")]); rows.push([t("st_txb"),BigInt(p.txB)+" "+t("p_pkts")]);
rows.push([t("st_rxg"),BigInt(p.rxG)+" "+t("p_pkts")]);
rows.push([t("st_rxb"),BigInt(p.rxB)+" "+t("p_pkts")]);
if(p.isSFP){ if(p.isSFP){
if(p.sfp_vendor)rows.push([t("p_module"),[p.sfp_vendor,p.sfp_model,p.sfp_serial].filter(Boolean).join(" / ")]); if(p.sfp_vendor)rows.push([t("p_module"),[p.sfp_vendor,p.sfp_model,p.sfp_serial].filter(Boolean).join(" / ")]);
var ext=p.sfp_options&0x40; var ext=p.sfp_options&0x40;
@@ -2243,14 +2257,14 @@ var CONF_OVERWRITE=[
/^ntp\s+server\b/,/^ntp\s+interval\b/,/^ntp\s+timezone\b/,/^ntp\s+dst\b/, /^ntp\s+server\b/,/^ntp\s+interval\b/,/^ntp\s+timezone\b/,/^ntp\s+dst\b/,
/^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/, /^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
/^pvid\s+\d{1,2}\b/, /^pvid\s+\d{1,2}\b/,
/^port\s+\d{1,2}(?!\s+name\b)/,/^port\s+\d{1,2}\s+name\b/, /^port\s+\d{1,2}(?!\s+(name|lldp)\b)/,/^port\s+\d{1,2}\s+name\b/,
/^mirror\b/, /^mirror\b/,
/^lag\s+\d\b/,/^laghash\s+\d\b/,/^isolate\s+\d{1,2}\b/, /^lag\s+\d\b/,/^laghash\s+\d\b/,/^isolate\s+\d{1,2}\b/,
/^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/, /^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/,
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+(edge|cost|prio|guard|filter|p2p)\b/, /^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+(edge|cost|prio|guard|filter|p2p)\b/,
/^igmp\b/,/^mtu\s+\d{1,2}\b/,/^storm\s+\d{1,2}\s+(bcast|mcast|ucast|umcast)\b/, /^igmp\b/,/^mtu\s+\d{1,2}\b/,/^storm\s+\d{1,2}\s+(bcast|mcast|ucast|umcast)\b/,
]; ];
var CONF_TOGGLE=[/^(syslog)\s+(on|off)$/,/^(ntp)\s+(on|off)$/,/^(stp)\s+(on|off)$/,/^(stp\s+(port\s+\d{1,2}|lag\s+[1-4]))\s+(on|off)$/]; var CONF_TOGGLE=[/^(syslog)\s+(on|off)$/,/^(ntp)\s+(on|off)$/,/^(stp)\s+(on|off)$/,/^(lldp)\s+(on|off)$/,/^(stp\s+(port\s+\d{1,2}|lag\s+[1-4]))\s+(on|off)$/];
function mergeConf(base,texts){ function mergeConf(base,texts){
var conf=base.slice(); var conf=base.slice();
function drop(rx){conf=conf.filter(function(c){return!rx.test(c)})} function drop(rx){conf=conf.filter(function(c){return!rx.test(c)})}
@@ -2268,6 +2282,7 @@ function mergeConf(base,texts){
} }
if((m=line.match(/^lag (\d) lacp off$/))){drop(new RegExp("^lag "+m[1]+" lacp( |$)"));return;} if((m=line.match(/^lag (\d) lacp off$/))){drop(new RegExp("^lag "+m[1]+" lacp( |$)"));return;}
if(line==="mirror off"){drop(/^mirror /);return;} if(line==="mirror off"){drop(/^mirror /);return;}
if((m=line.match(/^(port \d{1,2} lldp) (permit|block)$/))){drop(new RegExp("^"+m[1]+" (permit|block)$"));conf.push(line);return;}
if(!isConfCmd(line))return; if(!isConfCmd(line))return;
if((m=line.match(/^ingress (.+)$/))){ if((m=line.match(/^ingress (.+)$/))){
if(/^[tua]$/.test(m[1])){drop(/^ingress /);conf.push(line);return;} if(/^[tua]$/.test(m[1])){drop(/^ingress /);conf.push(line);return;}
@@ -2300,7 +2315,7 @@ function mergeConf(base,texts){
var key=line.match(rx)[0]; var key=line.match(rx)[0];
conf=conf.filter(function(item){ conf=conf.filter(function(item){
return!(item===key||(item.indexOf(key+" ")===0 return!(item===key||(item.indexOf(key+" ")===0
&&!/\smgmt$/.test(item)&&item.indexOf(key+" name ")!==0)); &&!/\smgmt$/.test(item)&&item.indexOf(key+" name ")!==0&&item.indexOf(key+" lldp ")!==0));
}); });
break; break;
} }
+7 -6
View File
@@ -33,7 +33,7 @@
html,body{height:100%} html,body{height:100%}
body{ body{
font:14px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif; font:14px/1.45 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
background:var(--bg);color:var(--fg);display:flex; background:var(--bg);color:var(--fg);display:flex;overflow:hidden;
} }
button,input,select,textarea{font:inherit;color:var(--fg)} button,input,select,textarea{font:inherit;color:var(--fg)}
a{color:var(--ac);text-decoration:none} a{color:var(--ac);text-decoration:none}
@@ -72,8 +72,8 @@ select.ctl,button.ctl{
button.pri{background:var(--ac);color:var(--acfg);border-color:transparent;font-weight:600} button.pri{background:var(--ac);color:var(--acfg);border-color:transparent;font-weight:600}
button.pri:hover,button.ctl:hover{filter:brightness(1.07)} button.pri:hover,button.ctl:hover{filter:brightness(1.07)}
button:disabled{opacity:.45;cursor:default;filter:none} button:disabled{opacity:.45;cursor:default;filter:none}
main{padding:18px 20px 40px;max-width:1400px;width:100%} main{padding:18px 20px 40px;width:100%;overflow-y:auto;}
section.tab{display:none} section.tab{display:none;max-width:1400px;}
section.tab.act{display:block} section.tab.act{display:block}
.card{ .card{
background:var(--panel);border:1px solid var(--bd);border-radius:10px; background:var(--panel);border:1px solid var(--bd);border-radius:10px;
@@ -89,6 +89,7 @@ table.t th{
padding:6px 8px;border-bottom:1px solid var(--bd);white-space:nowrap; padding:6px 8px;border-bottom:1px solid var(--bd);white-space:nowrap;
} }
table.t th[data-sort]{cursor:pointer;user-select:none} table.t th[data-sort]{cursor:pointer;user-select:none}
table.t th.num{text-align:right}
table.t td{padding:6px 8px;border-bottom:1px solid var(--bd);vertical-align:middle} table.t td{padding:6px 8px;border-bottom:1px solid var(--bd);vertical-align:middle}
table.t tr:last-child td{border-bottom:0} table.t tr:last-child td{border-bottom:0}
table.t tr:hover td{background:var(--sel)} table.t tr:hover td{background:var(--sel)}
@@ -223,7 +224,7 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
<span id="ttitle"></span> <span id="ttitle"></span>
<div id="strip"></div> <div id="strip"></div>
<span id="dirty" data-i18n="hdr_dirty" data-i18n-t="hdr_dirty_t">unsaved changes</span> <span id="dirty" data-i18n="hdr_dirty" data-i18n-t="hdr_dirty_t">unsaved changes</span>
<button class="ctl pri" id="saveBtn" data-i18n="hdr_save" data-i18n-t="hdr_save_t">Save to flash</button> <button class="ctl" id="saveBtn" data-i18n="hdr_save" data-i18n-t="hdr_save_t">Save to flash</button>
</header> </header>
<main> <main>
@@ -437,8 +438,8 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
<p class="small mut" style="margin-top:8px" data-i18n="sy_time_note">The switch has no battery backed clock.</p> <p class="small mut" style="margin-top:8px" data-i18n="sy_time_note">The switch has no battery backed clock.</p>
</div> </div>
<div class="card"><h2 data-i18n="sy_password">Admin password</h2> <div class="card"><h2 data-i18n="sy_password">Admin password</h2>
<label class="row"><span class="lb" data-i18n="sy_newpw">New password</span><input class="in" id="sy-pw1" type="password" maxlength="20"></label> <label class="row"><span class="lb" data-i18n="sy_newpw">New password</span><input class="in" id="sy-pw1" type="password" autocomplete="new-password" maxlength="20"></label>
<label class="row"><span class="lb" data-i18n="sy_repeat">Repeat</span><input class="in" id="sy-pw2" type="password" maxlength="20"></label> <label class="row"><span class="lb" data-i18n="sy_repeat">Repeat</span><input class="in" id="sy-pw2" type="password" autocomplete="new-password" maxlength="20"></label>
<button class="ctl pri" id="sy-pwapply" style="margin-top:8px" data-i18n="sy_pwapply">Change password</button> <button class="ctl pri" id="sy-pwapply" style="margin-top:8px" data-i18n="sy_pwapply">Change password</button>
<p class="small mut" style="margin-top:8px" data-i18n="sy_pw_note">Takes effect immediately; save to flash to keep it after reboot.</p> <p class="small mut" style="margin-top:8px" data-i18n="sy_pw_note">Takes effect immediately; save to flash to keep it after reboot.</p>
</div> </div>
+9 -39
View File
@@ -6,12 +6,12 @@
#include "cmd_parser.h" #include "cmd_parser.h"
#include "rtl837x_flash.h" #include "rtl837x_flash.h"
#include "uip.h" #include "uip.h"
#include "sessions.h"
#include "html_data.h" #include "html_data.h"
// #define DEBUG // #define DEBUG
#include "debug.h" #include "debug.h"
#define SESSION_ID_LENGTH 12
#define SESSION_TIMEOUT_DEFAULT 200 #define SESSION_TIMEOUT_DEFAULT 200
/* Seconds of inactivity after which a session cookie stops validating. /* Seconds of inactivity after which a session cookie stops validating.
@@ -75,10 +75,9 @@ __xdata uint8_t postbody_endpoint;
__xdata uint16_t postbody_start; __xdata uint16_t postbody_start;
__xdata char passwd[21]; __xdata char passwd[21];
__xdata char session_id[SESSION_ID_LENGTH + 1]; // Up to four logins at once, see sessions.c
__xdata uint8_t authenticated; __xdata uint8_t authenticated;
__xdata uint32_t now; __xdata uint32_t now;
__xdata uint32_t last_session_use;
#define TSTATE_NONE 0 #define TSTATE_NONE 0
#define TSTATE_TX 1 #define TSTATE_TX 1
@@ -109,6 +108,7 @@ void httpd_init(void) __banked
// handling one, and nothing has set it yet at init time. // handling one, and nothing has set it yet at init time.
for (uint8_t i = 0; i < UIP_CONNS; i++) for (uint8_t i = 0; i < UIP_CONNS; i++)
uip_conns[i].appstate.tstate = TSTATE_CLOSED; uip_conns[i].appstate.tstate = TSTATE_CLOSED;
session_init();
} }
@@ -343,38 +343,11 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
read_reg_timer(&now); read_reg_timer(&now);
if (session && session_id[0]) { if (session)
if (now - last_session_use > session_timeout) { session_check();
dbg_string("Session expired\n");
} else {
if (is_word_x(session, session_id)) {
authenticated = 1;
last_session_use = now;
} else {
dbg_string("Invalid session cookie!\n");
}
}
}
return p; return p;
} }
/*
* Generate random HEX-chars at the buffer location.
*/
void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
{
uint8_t i = 0;
while (bytes) {
if (!i)
get_random_32();
b[--bytes] = itohex(sfr_data[i]);
if (!bytes) { break; }
b[--bytes] = itohex(sfr_data[i] >> 4 | sfr_data[i] << 4);
i = (i + 1) & 0x3;
}
}
/* 0: body incomplete, 1: configuration stored, 2: malformed */ /* 0: body incomplete, 1: configuration stored, 2: malformed */
static uint8_t config_take(void) static uint8_t config_take(void)
{ {
@@ -531,9 +504,10 @@ uint8_t stream_upload(void)
memcpy(flash_buf + write_len, boundary, bindex); memcpy(flash_buf + write_len, boundary, bindex);
write_len += bindex; write_len += bindex;
bindex = 0; bindex = 0;
} } else {
crc16_bank1(upload_settings.p + upload_settings.bptr); crc16_bank1(upload_settings.p + upload_settings.bptr);
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++]; flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
}
if (write_len >= FLASH_PAGE_SIZE) { if (write_len >= FLASH_PAGE_SIZE) {
/* The staged image spans FIRMWARE_UPLOAD_START to twice that, /* The staged image spans FIRMWARE_UPLOAD_START to twice that,
* the span check_and_flash_update_image() reads back. Nothing * the span check_and_flash_update_image() reads back. Nothing
@@ -565,7 +539,6 @@ uint8_t stream_upload(void)
memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len); memcpy(flash_buf, flash_buf + FLASH_PAGE_SIZE, write_len);
} }
} }
bindex = 0;
} }
} while(1); } while(1);
} }
@@ -675,13 +648,10 @@ static void run_login_body(__xdata uint8_t *body)
{ {
if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) { if (strstart(body, "pwd=") && is_url_word_x(body + 4, passwd)) {
dbg_string("Password accepted!\n"); dbg_string("Password accepted!\n");
read_reg_timer(&last_session_use); read_reg_timer(&now);
gen_random_hex_chars(session_id, SESSION_ID_LENGTH);
session_id[SESSION_ID_LENGTH] = NUL;
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \ slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
"Set-Cookie: session="); "Set-Cookie: session=");
for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++) session_new();
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"); dbg_string("Password invalid!\n");
+31
View File
@@ -0,0 +1,31 @@
#include "machine_defs.h"
__code const struct machine machine = {
MACHINE_COMMON_SETTING,
.mac_flash_offset = 0x1FC000,
.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 = 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 = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
.reset_pin = GPIO48_I2C_SCL1,
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x09, 0x0d, 0x10, 0x11, 0x0e, 0x14, 0x11, 0x12, 0x15, 0x15, 0x16, 0x18, 0x19, 0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21 },
.led_mux_custom = 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
},
},
};
@@ -0,0 +1,6 @@
#include "machine_init_defs.h"
void machine_custom_init(void) __banked
{
REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7f24977f);
}
+1
View File
@@ -0,0 +1 @@
PCB_AFGW_SWTG218ANS_V_2_0_2.c
+7
View File
@@ -0,0 +1,7 @@
#ifndef _MACHINE_SWTG218ANS_V_2_0_2_H_
#define _MACHINE_SWTG218ANS_V_2_0_2_H_
#define MACHINE_MODEL "RealHD PSW8-25MG"
#define MACHINE_CHIPSET RTL8373
#endif
+1
View File
@@ -0,0 +1 @@
PCB_AFGW_SWTG218ANS_V_2_0_2_init.c
+1
View File
@@ -154,6 +154,7 @@ void print_long(uint32_t a);
void print_short(uint16_t a); void print_short(uint16_t a);
void print_byte(uint8_t a); void print_byte(uint8_t a);
void itoa(uint8_t v); void itoa(uint8_t v);
void itoa_no_syslog(uint8_t v);
void itoa_short(uint16_t v); void itoa_short(uint16_t v);
void print_sfr_data(void); void print_sfr_data(void);
void print_phy_data(void); void print_phy_data(void);
+4 -2
View File
@@ -221,9 +221,11 @@ void rtl8372_init(void) __banked
} else if(machine.n_10g == 2) { } else if(machine.n_10g == 2) {
REG_SET(RTL837X_REG_SDS_MODES, 0x1ad); // Both 10g ports use SDS_QXGMII REG_SET(RTL837X_REG_SDS_MODES, 0x1ad); // Both 10g ports use SDS_QXGMII
} else { } else {
// Replace the reset value 0xbff (both SDS off) instead of ORing into it:
// RTL837X_REG_SEC_COUNTER only holds a written value while SDS 0 is on
reg_read_m(RTL837X_REG_SDS_MODES); reg_read_m(RTL837X_REG_SDS_MODES);
sfr_mask_data(1, 0, 0x03); sfr_mask_data(1, 0xff, 0x03);
sfr_mask_data(0, 0, 0xe2); sfr_mask_data(0, 0xff, 0xe2);
reg_write_m(RTL837X_REG_SDS_MODES); reg_write_m(RTL837X_REG_SDS_MODES);
} }
+2 -2
View File
@@ -271,7 +271,7 @@ void vlan_setup(void) __banked
wait_table_ready(); wait_table_ready();
// Set PVID 1 for every port. TODO: Skip unused ports! // Set PVID 1 for every port. TODO: Skip unused ports!
for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT + 1; i++) { // Do this also for the CPU port (+1) for (uint8_t i = MACHINE_MIN_PORT; i <= CPU_PORT; i++) { // CPU MAC is independent of the last user port
uint16_t reg = RTL837x_PVID_BASE_REG + ((i >> 1) << 2); uint16_t reg = RTL837x_PVID_BASE_REG + ((i >> 1) << 2);
#ifdef DEBUG #ifdef DEBUG
print_byte(i); write_char(':'); write_char(' '); print_short(reg); write_char('='); print_byte(i); write_char(':'); write_char(' '); print_short(reg); write_char('=');
@@ -307,7 +307,7 @@ void vlan_setup(void) __banked
REG_SET(RTL837X_VLAN_L2_LRN_DIS_0, 0); REG_SET(RTL837X_VLAN_L2_LRN_DIS_0, 0);
REG_SET(RTL837X_VLAN_L2_LRN_DIS_1, 0); REG_SET(RTL837X_VLAN_L2_LRN_DIS_1, 0);
// Enable VLAN 1: Ports 0-9, i.e. including the CPU port are untagged members // Enable VLAN 1: user ports untagged, CPU MAC9 tagged (untag bit 19 clear)
REG_SET(RTL837x_TBL_DATA_IN_A, machine_detected.isRTL8373? 0x0207ffff : 0x0207e3f8); // 02: Entry valid, 7...: membership REG_SET(RTL837x_TBL_DATA_IN_A, machine_detected.isRTL8373? 0x0207ffff : 0x0207e3f8); // 02: Entry valid, 7...: membership
REG_SET(RTL837X_TBL_CTRL, 0x00010303); // Write VLAN 1 REG_SET(RTL837X_TBL_CTRL, 0x00010303); // Write VLAN 1
+13
View File
@@ -305,6 +305,19 @@ void itoa(uint8_t v)
} }
void itoa_no_syslog(uint8_t v)
{
uint8_t t = (v / 100);
uint8_t print_zeros = t;
if (print_zeros)
write_char_no_syslog('0' + t);
t = (v / 10) % 10;
print_zeros |= t;
if (print_zeros)
write_char_no_syslog('0' + t);
write_char_no_syslog('0' + (v % 10));
}
/* Same as itoa(), one decade wider: enough for a port number. Kept separate /* Same as itoa(), one decade wider: enough for a port number. Kept separate
* rather than widening itoa() itself, because every existing caller passes a * rather than widening itoa() itself, because every existing caller passes a
* byte and would start paying for 16-bit divisions it does not need. */ * byte and would start paying for 16-bit divisions it does not need. */
+15
View File
@@ -0,0 +1,15 @@
https://sourceforge.net/p/sdcc/bugs/4153/
Index: src/mcs51/ralloc.c
===================================================================
--- src/mcs51/ralloc.c (revision 17011)
+++ src/mcs51/ralloc.c (working copy)
@@ -1208,7 +1208,7 @@
int change = 0;
/* if the result has been spilt then cannot share */
- if (opsym->isspilt)
+ if (result->isspilt || opsym->isspilt)
return 0;
for (;;)
+24
View File
@@ -0,0 +1,24 @@
https://sourceforge.net/p/sdcc/bugs/4154/
Index: src/mcs51/ralloc.c
===================================================================
--- src/mcs51/ralloc.c (revision 17011)
+++ src/mcs51/ralloc.c (working copy)
@@ -641,6 +641,7 @@
spillThis (symbol * sym)
{
int i;
+ bool ownsRegs = bitVectBitValue (_G.regAssigned, sym->key);
/* if this is rematerializable or has a spillLocation
we are okay, else we need to create a spillLocation
for it */
@@ -658,7 +659,8 @@
{
if (sym->regs[i])
{
- freeReg (sym->regs[i]);
+ if (ownsRegs)
+ freeReg (sym->regs[i]);
sym->regs[i] = NULL;
}
}
+130
View File
@@ -0,0 +1,130 @@
https://sourceforge.net/p/sdcc/bugs/4070/
Index: sdas/asxxsrc/asexpr.c
===================================================================
--- sdas/asxxsrc/asexpr.c
+++ sdas/asxxsrc/asexpr.c
@@ -863,18 +863,59 @@
return((n & s_mask) ? (n | ~v_mask) : (n & v_mask));
}
-/*)Function void exprmasks(esp)
+/*)Function void exprmasks(n)
*
* int n T Line Bytes in Address
*
* The function exprmasks() configures the assembler
- * for 16, 24, or 32-Bit Data/Addresses.
+ * for 16, 24, or 32-Bit Data/Addresses. The arithmetic
+ * precision follows the address width unless a port
+ * calls valmasks() afterwards.
*
* local variables:
* none
*
* global variables:
* int a_bytes T Line Bytes in Address
+ *
+ * functions called:
+ * void valmasks() asexpr.c
+ *
+ * side effects:
+ * The address width and arithmetic precision
+ * parameters are set.
+ */
+
+void
+exprmasks(int n)
+{
+ switch(n) {
+ default:
+ n = 2;
+ case 2:
+ case 3:
+ case 4:
+ break;
+ }
+ a_bytes = n;
+ valmasks(n);
+}
+
+/*)Function void valmasks(n)
+ *
+ * int n Bytes of arithmetic precision
+ *
+ * The function valmasks() configures the 16, 24, or
+ * 32-Bit arithmetic precision independently of the
+ * T Line address width. A port whose addresses fit
+ * in 24 bits but whose symbols may hold 32-bit values
+ * (the 8051 __sfr32 address lists, for example) uses
+ * exprmasks(3) followed by valmasks(4).
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
* a_uint a_mask Address mask
* a_uint s_mask Sign mask
* a_uint v_mask Value mask
@@ -885,16 +926,13 @@
* side effects:
* The arithmetic precision parameters are set.
*/
-
+
void
-exprmasks(int n)
+valmasks(int n)
{
- a_bytes = n;
-
#ifdef LONGINT
- switch(a_bytes) {
+ switch(n) {
default:
- a_bytes = 2;
case 2:
a_mask = (a_uint) 0x0000FFFFl;
s_mask = (a_uint) 0x00008000l;
@@ -914,9 +952,8 @@
break;
}
#else
- switch(a_bytes) {
+ switch(n) {
default:
- a_bytes = 2;
case 2:
a_mask = (a_uint) 0x0000FFFF;
s_mask = (a_uint) 0x00008000;
Index: sdas/asxxsrc/asxxxx.h
===================================================================
--- sdas/asxxsrc/asxxxx.h
+++ sdas/asxxsrc/asxxxx.h
@@ -1354,6 +1354,7 @@
extern int digit(int c, int r);
extern int is_digit(int c, int r);
extern void exprmasks(int n);
+extern void valmasks(int n);
extern void expr(struct expr *esp, int n);
extern void binop(int c, struct expr *esp, struct expr *re);
extern int is_abs(struct expr *esp);
Index: sdas/as8051/i51mch.c
===================================================================
--- sdas/as8051/i51mch.c
+++ sdas/as8051/i51mch.c
@@ -782,9 +782,12 @@
hilo = 1;
/*
- * Address Space
+ * Address Space: 24-bit addresses in the T lines,
+ * 32-bit arithmetic so that __sfr32 address lists
+ * like 0xa4a5a6a7 keep their most significant byte.
*/
- exprmasks(3);
+ exprmasks(3);
+ valmasks(4);
/*
* First time only:
Executable
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
set -eu
V=4.6.0
SHA=5fd6a93e5997ce01756868fe35e441095cfb637894a80c262514a634094973b6
PREFIX=$1
D=$(cd "$(dirname "$0")" && pwd)
W=$(mktemp -d)
trap 'rm -rf "$W"' EXIT
curl -fL -o "$W/sdcc.tar.bz2" "https://downloads.sourceforge.net/project/sdcc/sdcc/$V/sdcc-src-$V.tar.bz2"
if command -v sha256sum >/dev/null; then
echo "$SHA $W/sdcc.tar.bz2" | sha256sum -c -
else
echo "$SHA $W/sdcc.tar.bz2" | shasum -a 256 -c -
fi
tar -C "$W" -xjf "$W/sdcc.tar.bz2"
cd "$W/sdcc-$V"
for p in "$D"/*.patch; do
patch -p0 < "$p"
done
off=""
for p in z80 z180 r2k r2ka r3ka r4k r5k r6k sm83 tlcs90 ez80 ez80_z80 z80n r800 ds390 ds400 pic14 pic16 hc08 s08 stm8 pdk13 pdk14 pdk15 mos6502 mos65c02 huc6280 f8 f8l; do
off="$off --disable-$p-port"
done
./configure --prefix="$PREFIX" $off --disable-sdcdb --disable-ucsim --disable-non-free
make -j"$(getconf _NPROCESSORS_ONLN)"
make install
+128
View File
@@ -0,0 +1,128 @@
/*
* Login sessions of the web interface.
*
* Up to SESSIONS logins at once, each with its own cookie and its own expiry.
* With a single one, logging in from a second browser (or a phone) ended the
* first browser's session at its next request.
*
* This sits in bank 3: the web server's own bank is full, so httpd.c only
* calls in here. It shares three things with httpd.c: the cookie value it
* parsed (session), the time read for the request (now) and the result
* (authenticated); the reply is written to outbuf at slen.
*/
#pragma codeseg BANK3
#pragma constseg BANK3
#include <stdint.h>
#include "rtl837x_common.h"
#include "sessions.h"
extern volatile __xdata uint8_t sfr_data[4];
extern __xdata uint16_t session_timeout;
extern __xdata uint32_t now;
extern __xdata uint8_t authenticated;
extern __xdata uint8_t * __xdata session;
extern __xdata uint8_t outbuf[];
extern __xdata uint16_t slen;
__xdata char session_id[SESSIONS][SESSION_ID_LENGTH + 1];
__xdata uint32_t last_session_use[SESSIONS];
static __xdata uint8_t ss_slot, ss_i, ss_oldest, ss_c;
/* The slot whose cookie the last request came with; only meaningful while
* authenticated is set, which only session_check() does */
static __xdata uint8_t ss_hit;
static __code const char ss_hex[] = "0123456789abcdef";
/* What may follow a cookie value: ';' separates cookies in a Cookie header */
static __code const char ss_end[] = " \t:?=\n\r;";
/* Leaf function, so the compiler keeps its 32-bit scratch in the overlay
* rather than in internal RAM. */
static uint8_t ss_stale(void)
{
if (now - last_session_use[ss_slot] > session_timeout)
return 1;
return 0;
}
/* Likewise a leaf: the 32-bit comparison needs no stack of its own this way */
static uint8_t ss_older(void)
{
if (last_session_use[ss_slot] < last_session_use[ss_oldest])
return 1;
return 0;
}
/* Whether the cookie value is the id of slot ss_slot */
static uint8_t ss_match(void)
{
for (ss_i = 0; ss_i < SESSION_ID_LENGTH; ss_i++) {
if (session[ss_i] != session_id[ss_slot][ss_i])
return 0;
}
ss_c = session[SESSION_ID_LENGTH];
if (!ss_c)
return 1;
for (ss_i = 0; ss_end[ss_i]; ss_i++) {
if (ss_c == ss_end[ss_i])
return 1;
}
return 0;
}
void session_init(void) __banked
{
for (ss_slot = 0; ss_slot < SESSIONS; ss_slot++)
session_id[ss_slot][0] = NUL;
}
void session_check(void) __banked
{
for (ss_slot = 0; ss_slot < SESSIONS; ss_slot++) {
if (!session_id[ss_slot][0])
continue;
if (ss_stale()) {
session_id[ss_slot][0] = NUL;
} else if (ss_match()) {
authenticated = 1;
ss_hit = ss_slot;
last_session_use[ss_slot] = now;
return;
}
}
}
void session_new(void) __banked
{
if (authenticated && session_id[ss_hit][0]) {
/* The login came with a cookie that is still valid: its slot gets the
* new id. A second slot for the same browser would leave the old one
* looking fresh and push out someone else at the next login. */
ss_slot = ss_hit;
} else {
/* A free or expired slot, else the least recently used */
ss_oldest = 0;
for (ss_slot = 0; ss_slot < SESSIONS; ss_slot++) {
if (!session_id[ss_slot][0] || ss_stale())
break;
if (ss_older())
ss_oldest = ss_slot;
}
if (ss_slot == SESSIONS)
ss_slot = ss_oldest;
}
last_session_use[ss_slot] = now;
for (ss_i = 0; ss_i < SESSION_ID_LENGTH; ss_i++) {
if (!(ss_i & 7))
get_random_32();
ss_c = sfr_data[(ss_i >> 1) & 3];
if (ss_i & 1)
ss_c >>= 4;
session_id[ss_slot][ss_i] = ss_hex[ss_c & 0xf];
outbuf[slen++] = ss_hex[ss_c & 0xf];
}
session_id[ss_slot][SESSION_ID_LENGTH] = NUL;
}
+19
View File
@@ -0,0 +1,19 @@
#ifndef _SESSIONS_H_
#define _SESSIONS_H_
#include <stdint.h>
#define SESSIONS 4
#define SESSION_ID_LENGTH 12
extern __xdata char session_id[SESSIONS][SESSION_ID_LENGTH + 1];
extern __xdata uint32_t last_session_use[SESSIONS];
/* No session at boot */
void session_init(void) __banked;
/* Sets authenticated if the cookie in session belongs to a live session */
void session_check(void) __banked;
/* Starts a session at now and writes its id to outbuf at slen */
void session_new(void) __banked;
#endif
+11
View File
@@ -29,6 +29,9 @@ TESTS = $(BUILDDIR)/test_cmd_editor \
$(BUILDDIR)/test_page_json \ $(BUILDDIR)/test_page_json \
$(BUILDDIR)/test_httpd_tx \ $(BUILDDIR)/test_httpd_tx \
$(BUILDDIR)/test_tick_gate \ $(BUILDDIR)/test_tick_gate \
$(BUILDDIR)/test_cpu_vlan_full \
$(BUILDDIR)/test_cpu_vlan_restricted \
$(BUILDDIR)/test_cpu_vlan_8372 \
$(BUILDDIR)/test_nic_rx \ $(BUILDDIR)/test_nic_rx \
$(BUILDDIR)/test_lacp $(BUILDDIR)/test_lacp
@@ -69,6 +72,14 @@ $(BUILDDIR)/test_lacp: test_lacp.c $(SRCROOT)/rtl837x_lacp.c | $(BUILDDIR)
# this test carries the environment below them itself. # this test carries the environment below them itself.
$(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR) $(BUILDDIR)/test_httpd_tx: test_httpd_tx.c $(SRCROOT)/httpd/httpd.c $(SRCROOT)/uip/uip.c | $(BUILDDIR)
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS) $(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
# the login sessions httpd.c calls into
$(BUILDDIR)/test_httpd_tx: $(SRCROOT)/sessions.c
# CPU VLAN initialization with full and reduced user-port ranges.
$(BUILDDIR)/test_cpu_vlan_restricted: CFLAGS += -DMACHINE_MAX_PORT=7
$(BUILDDIR)/test_cpu_vlan_8372: CFLAGS += -DMACHINE_MAX_PORT=7 -DMACHINE_MIN_PORT=3 -DRTLP_TEST_IS8373=0
$(BUILDDIR)/test_cpu_vlan_full $(BUILDDIR)/test_cpu_vlan_restricted $(BUILDDIR)/test_cpu_vlan_8372: test_cpu_vlan.c $(TABLE_ENV) | $(BUILDDIR)
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
run: $(TESTS) run: $(TESTS)
@fail=0; for t in $(TESTS); do \ @fail=0; for t in $(TESTS); do \
+4 -1
View File
@@ -57,13 +57,16 @@ const uint8_t hex_chars[] = "0123456789abcdef";
uint8_t *hex = (uint8_t *)hex_chars; uint8_t *hex = (uint8_t *)hex_chars;
/* ---- a 9-port RTL8373 whose logical ports map to themselves ---- */ /* ---- a 9-port RTL8373 whose logical ports map to themselves ---- */
#ifndef RTLP_TEST_IS8373
#define RTLP_TEST_IS8373 1
#endif
const struct machine machine = { const struct machine machine = {
.machine_name = "HOSTTEST", .machine_name = "HOSTTEST",
.n_sfp = 0, .n_sfp = 0,
.log_to_phys_port = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, .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 }, .phys_to_log_port = { 0, 1, 2, 3, 4, 5, 6, 7, 8 },
}; };
struct machine_runtime machine_detected = { .isRTL8373 = 1 }; struct machine_runtime machine_detected = { .isRTL8373 = RTLP_TEST_IS8373 };
/* ---- firmware state the modules read or write ---- */ /* ---- firmware state the modules read or write ---- */
uint8_t outbuf[TCP_OUTBUF_SIZE]; uint8_t outbuf[TCP_OUTBUF_SIZE];
+24
View File
@@ -0,0 +1,24 @@
#include <stdint.h>
#include <stdio.h>
#include "rtl837x_common.h"
#include "rtl837x_port.h"
#include "machine.h"
#include "support.h"
#include "hw_mock.h"
extern const struct machine machine;
extern struct machine_runtime machine_detected;
int main(void) {
hw_reset();out_reset();
hw_reg_set(RTL837X_VLAN_PORT_EGR_TAG,0xa50fffff);
hw_reg_set(RTL837x_PVID_BASE_REG+16,0x5a123456);
vlan_setup();
uint32_t untouched=(1u<<(MACHINE_MIN_PORT*2))-1;
CHECK(hw_reg_get(RTL837X_VLAN_PORT_EGR_TAG)==(0xa5000000|untouched),"CPU egress set, unrelated bits preserved");
CHECK(hw_reg_get(RTL837x_PVID_BASE_REG+16)==0x5a001001,"CPU PVID initialized explicitly");
uint16_t active=((1u<<(MACHINE_MAX_PORT+1))-1)&~((1u<<MACHINE_MIN_PORT)-1);
CHECK(hw_reg_get(RTL837X_VLAN_PORT_IGR_FLTR)==(active|PMASK_CPU),"CPU ingress included, excluded user ports rejected");
CHECK(hw_vlan_word(1)==(machine_detected.isRTL8373?0x0207ffff:0x0207e3f8),"existing family VLAN membership preserved");
CHECK(hw_vlan_word(2)==0,"no unrelated VLAN changed");
printf("CPU VLAN min=%u max=%u RTL8373=%u: %d checks, %d failed\n",MACHINE_MIN_PORT,MACHINE_MAX_PORT,machine_detected.isRTL8373,tests_run,tests_failed);
return tests_failed?1:0;
}
+194 -5
View File
@@ -81,7 +81,7 @@ static uint8_t written_config[CONFIG_LEN];
static uint16_t written_config_len; static uint16_t written_config_len;
static uint32_t config_erase_addr, config_write_addr; static uint32_t config_erase_addr, config_write_addr;
static int config_erases, config_writes; static int config_erases, config_writes;
static uint8_t flash_written[64]; static uint8_t flash_written[1024];
static size_t flash_written_len; static size_t flash_written_len;
static int flash_write_bad; static int flash_write_bad;
@@ -132,7 +132,9 @@ void reset_chip(void) { reset_calls++; }
void delay(uint16_t t) { (void)t; } void delay(uint16_t t) { (void)t; }
void write_char(char c) { (void)c; } void write_char(char c) { (void)c; }
void write_char_no_syslog(char c) { (void)c; } void write_char_no_syslog(char c) { (void)c; }
void itoa_no_syslog(uint8_t v) { (void)v; }
void print_string(const char *p) { (void)p; } void print_string(const char *p) { (void)p; }
void print_string_no_syslog(const char *p) { (void)p; }
void print_string_newline_no_syslog(const char *p) { (void)p; } void print_string_newline_no_syslog(const char *p) { (void)p; }
void set_sys_led_state(uint8_t state) { (void)state; } void set_sys_led_state(uint8_t state) { (void)state; }
void cmd_parser(void) { } void cmd_parser(void) { }
@@ -142,7 +144,8 @@ void clear_command_history(void) { }
void udp_callbacks(void) { } void udp_callbacks(void) { }
void tcpip_output(void) { } void tcpip_output(void) { }
void get_random_32(void) { } void get_random_32(void) { }
void read_reg_timer(uint32_t *tmr) { *tmr = 0; } static uint32_t fake_now;
void read_reg_timer(uint32_t *tmr) { *tmr = fake_now; }
/* uip-conf.h asks uIP not to define the packet buffer: on the switch it lives /* uip-conf.h asks uIP not to define the packet buffer: on the switch it lives
* at a fixed XDATA address, so the bench provides the storage itself. */ * at a fixed XDATA address, so the bench provides the storage itself. */
@@ -191,9 +194,9 @@ void send_lldp(void) {}
extern uint8_t authenticated; extern uint8_t authenticated;
extern char session_id[]; extern char session_id[];
extern uint32_t last_session_use[];
extern char passwd[21]; extern char passwd[21];
extern uint16_t session_timeout; extern uint16_t session_timeout;
extern uint32_t last_session_use;
/* uip.c defines the listen table but no header declares it; the bench reads it /* uip.c defines the listen table but no header declares it; the bench reads it
* to confirm the port httpd_init() asked for is the one uIP is watching. */ * to confirm the port httpd_init() asked for is the one uIP is watching. */
@@ -549,7 +552,7 @@ static void scenario_bad_l4_checksum(void)
/* Private HTTP lifecycle values; drive the real callback, not a model. */ /* Private HTTP lifecycle values; drive the real callback, not a model. */
enum { TSTATE_NONE = 0, TSTATE_TX = 1 }; enum { TSTATE_NONE = 0, TSTATE_TX = 1, TSTATE_POST = 4 };
extern uint16_t slen, cont_len, sent_len, bindex, crc_final, write_len; extern uint16_t slen, cont_len, sent_len, bindex, crc_final, write_len;
extern uint8_t boundary[], verify_crc, outbuf[]; extern uint8_t boundary[], verify_crc, outbuf[];
extern struct { uint8_t *p; uint16_t bptr, plen; } upload_settings; extern struct { uint8_t *p; uint16_t bptr, plen; } upload_settings;
@@ -877,6 +880,77 @@ static void scenario_split_get_header_terminator(void)
"fragmented GET terminator: CRLFCRLF may span receive events"); "fragmented GET terminator: CRLFCRLF may span receive events");
} }
/* The sessions of the login tests below: four in use, slot 1 the least recently used */
#define ID_STRIDE 13 /* SESSION_ID_LENGTH + 1 */
static const char *slot_id(int i)
{
return session_id + i * ID_STRIDE;
}
static void fill_sessions(void)
{
static const char *const ids[4] = { "0123456789ab", "aaaaaaaaaaaa", "bbbbbbbbbbbb", "cccccccccccc" };
static const uint32_t used[4] = { 50, 10, 60, 70 };
fake_now = 100;
for (int i = 0; i < 4; i++) {
strcpy(session_id + i * ID_STRIDE, ids[i]);
last_session_use[i] = used[i];
}
}
static int others_kept(int first, int second, int third)
{
static const char *const ids[4] = { "0123456789ab", "aaaaaaaaaaaa", "bbbbbbbbbbbb", "cccccccccccc" };
return !strcmp(slot_id(first), ids[first]) && !strcmp(slot_id(second), ids[second]) &&
!strcmp(slot_id(third), ids[third]);
}
static void scenario_login_with_valid_cookie_reuses_its_slot(void)
{
static const char post[] =
"POST /login HTTP/1.1\r\n"
"Cookie: session=0123456789ab\r\n"
"Content-Length: 8\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\n"
"pwd=1234";
login_session_start();
fill_sessions();
client_send(TCP_ACK | TCP_PSH, post, (int)strlen(post));
CHECK(stream_contains("Location: index.html\r\n"),
"login with a valid cookie: accepted");
CHECK(strcmp(slot_id(0), "0123456789ab") != 0,
"login with a valid cookie: its own slot gets the new id");
CHECK(others_kept(1, 2, 3),
"login with a valid cookie: nobody else is pushed out");
fake_now = 0;
}
static void scenario_login_without_cookie_replaces_least_recently_used(void)
{
static const char post[] =
"POST /login HTTP/1.1\r\n"
"Content-Length: 8\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\n"
"pwd=1234";
login_session_start();
fill_sessions();
client_send(TCP_ACK | TCP_PSH, post, (int)strlen(post));
CHECK(stream_contains("Location: index.html\r\n"),
"login without a cookie: accepted");
CHECK(strcmp(slot_id(1), "aaaaaaaaaaaa") != 0,
"login without a cookie: the least recently used slot is taken");
CHECK(others_kept(0, 2, 3),
"login without a cookie: the other three stay");
fake_now = 0;
}
static void scenario_fragmented_get_without_cookie(void) static void scenario_fragmented_get_without_cookie(void)
{ {
static const char first[] = static const char first[] =
@@ -1041,7 +1115,7 @@ static void scenario_upload(const char *name, const char *part_type, int split)
session_start(MSS_FULL); session_start(MSS_FULL);
strcpy(session_id, "0123456789ab"); strcpy(session_id, "0123456789ab");
session_timeout = 200; session_timeout = 200;
last_session_use = 0; /* read_reg_timer() returns zero in this bench. */ last_session_use[0] = 0; /* read_reg_timer() returns zero in this bench. */
flash_size = 0x100000; flash_size = 0x100000;
flash_written_len = 0; flash_written_len = 0;
flash_write_bad = 0; flash_write_bad = 0;
@@ -1082,6 +1156,115 @@ static void scenario_upload(const char *name, const char *part_type, int split)
flash_size = saved_flash_size; flash_size = saved_flash_size;
} }
extern uint32_t uptr;
#define UPLOAD_LEN 600
#define UPLOAD_BOUNDARY "\r\n--XyZ"
#define UPLOAD_TRAILER UPLOAD_BOUNDARY "--\r\n"
static int upload_in_two(uint8_t *body, uint16_t body_len, uint16_t split)
{
uptr = FIRMWARE_UPLOAD_START;
write_len = 0;
bindex = 0;
verify_crc = 0;
flash_written_len = 0;
flash_write_bad = 0;
strcpy((char *)boundary, UPLOAD_BOUNDARY);
uip_conn = &uip_conns[0];
uip_conn->appstate.tstate = TSTATE_POST;
upload_settings.p = body;
upload_settings.bptr = 0;
upload_settings.plen = split;
stream_upload();
if (uip_conn->appstate.tstate == TSTATE_POST) {
upload_settings.p = body + split;
upload_settings.bptr = 0;
upload_settings.plen = body_len - split;
stream_upload();
}
return uip_conn->appstate.tstate == TSTATE_NONE
&& uptr == FIRMWARE_UPLOAD_START + UPLOAD_LEN && !flash_write_bad
&& flash_written_len == UPLOAD_LEN + 1 && !flash_written[UPLOAD_LEN];
}
static void scenario_upload_cr_before_boundary(void)
{
uint8_t body[UPLOAD_LEN + sizeof(UPLOAD_TRAILER)];
uint16_t body_len, split;
int completed = 0, intact = 0, splits = 0;
for (uint16_t i = 0; i < UPLOAD_LEN; i++)
body[i] = pattern(i);
body[UPLOAD_LEN - 2] = 'x';
body[UPLOAD_LEN - 1] = '\r';
body_len = UPLOAD_LEN + sizeof(UPLOAD_TRAILER) - 1;
memcpy(body + UPLOAD_LEN, UPLOAD_TRAILER, sizeof(UPLOAD_TRAILER) - 1);
for (split = 0; split <= body_len; split++) {
splits++;
if (upload_in_two(body, body_len, split)) {
completed++;
if (!memcmp(flash_written, body, UPLOAD_LEN))
intact++;
}
}
if (verbose)
printf(" %d of %d splits complete, %d intact\n", completed, splits, intact);
CHECK(completed == splits,
"upload: an image ending in CR still finds the closing boundary");
CHECK(intact == splits,
"upload: the CR and the bytes before it reach the flash unchanged");
}
static int upload_whole_and_split(uint8_t *body, uint16_t body_len)
{
return upload_in_two(body, body_len, body_len) && !memcmp(flash_written, body, UPLOAD_LEN)
&& upload_in_two(body, body_len, UPLOAD_LEN) && !memcmp(flash_written, body, UPLOAD_LEN);
}
static void scenario_upload_last_byte(void)
{
uint8_t body[UPLOAD_LEN + sizeof(UPLOAD_TRAILER)];
uint16_t body_len = UPLOAD_LEN + sizeof(UPLOAD_TRAILER) - 1;
int bad = -1;
for (uint16_t i = 0; i < UPLOAD_LEN; i++)
body[i] = pattern(i);
memcpy(body + UPLOAD_LEN, UPLOAD_TRAILER, sizeof(UPLOAD_TRAILER) - 1);
for (int last = 0; last < 256 && bad < 0; last++) {
body[UPLOAD_LEN - 1] = last;
if (!upload_whole_and_split(body, body_len))
bad = last;
}
if (bad >= 0)
printf(" last byte 0x%02x loses the closing boundary\n", bad);
CHECK(bad < 0, "upload: the part ends after the payload whatever its last byte");
body[UPLOAD_LEN - 1] = '\r';
body[UPLOAD_LEN - 2] = '\r';
CHECK(upload_whole_and_split(body, body_len), "upload: an even run of CR before the boundary");
body[UPLOAD_LEN - 3] = '\r';
CHECK(upload_whole_and_split(body, body_len), "upload: an odd run of CR before the boundary");
}
static void scenario_upload_broken_matches(void)
{
uint8_t body[UPLOAD_LEN + sizeof(UPLOAD_TRAILER)];
uint16_t body_len = UPLOAD_LEN + sizeof(UPLOAD_TRAILER) - 1;
memcpy(body + UPLOAD_LEN, UPLOAD_TRAILER, sizeof(UPLOAD_TRAILER) - 1);
memset(body, '\r', UPLOAD_LEN);
CHECK(upload_whole_and_split(body, body_len),
"upload: a run of CR longer than a flash page is staged intact");
for (uint16_t i = 0; i < UPLOAD_LEN; i++)
body[i] = "\r\n-"[i % 3];
CHECK(upload_whole_and_split(body, body_len),
"upload: repeated partial delimiters are staged as payload");
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (argc > 1 && !strcmp(argv[1], "-v")) if (argc > 1 && !strcmp(argv[1], "-v"))
@@ -1113,6 +1296,12 @@ int main(int argc, char **argv)
scenario_upload("octet-stream control", "Content-Type: application/octet-stream\r\n", 0); scenario_upload("octet-stream control", "Content-Type: application/octet-stream\r\n", 0);
scenario_upload("MacBinary, split part terminator", "Content-Type: application/macbinary\r\n", 1); scenario_upload("MacBinary, split part terminator", "Content-Type: application/macbinary\r\n", 1);
scenario_upload("no part Content-Type", "", 0); scenario_upload("no part Content-Type", "", 0);
scenario_upload_cr_before_boundary();
scenario_upload_last_byte();
scenario_upload_broken_matches();
scenario_login_with_valid_cookie_reuses_its_slot();
scenario_login_without_cookie_replaces_least_recently_used();
printf("\n%s (%d failure%s)\n", printf("\n%s (%d failure%s)\n",
failures ? "BENCH: FAILURES" : "BENCH: ALL PASS", failures ? "BENCH: FAILURES" : "BENCH: ALL PASS",
+19 -1
View File
@@ -98,6 +98,7 @@
#include "../rtl837x_regs.h" #include "../rtl837x_regs.h"
extern __xdata uint8_t rx_headers[16]; extern __xdata uint8_t rx_headers[16];
extern volatile __xdata uint32_t ticks;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Variable definitions. */ /* Variable definitions. */
@@ -243,6 +244,9 @@ __xdata struct uip_stats uip_stat;
#if UIP_LOGGING == 1 #if UIP_LOGGING == 1
#define UIP_LOG(m) print_string_newline_no_syslog(m); #define UIP_LOG(m) print_string_newline_no_syslog(m);
#define FRAGDROP_WINDOW (5 * SYS_TICK_HZ)
static __xdata u16_t fragdrop_mark;
static __xdata u8_t fragdrop_count;
#else #else
#define UIP_LOG(m) #define UIP_LOG(m)
#endif /* UIP_LOGGING == 1 */ #endif /* UIP_LOGGING == 1 */
@@ -710,6 +714,17 @@ uip_process(u8_t flag) __banked
/* Check if we were invoked because of the perodic timer fireing. */ /* Check if we were invoked because of the perodic timer fireing. */
} else if(flag == UIP_TIMER) { } else if(flag == UIP_TIMER) {
// print_string("T1\n"); // print_string("T1\n");
#if UIP_LOGGING == 1
if(fragdrop_count && (u16_t)ticks - fragdrop_mark >= FRAGDROP_WINDOW) {
print_string_no_syslog("ip: fragments dropped: ");
itoa_no_syslog(fragdrop_count);
if(fragdrop_count == 0xff)
write_char_no_syslog('+');
write_char_no_syslog('\n');
fragdrop_mark = (u16_t)ticks;
fragdrop_count = 0;
}
#endif /* UIP_LOGGING == 1 */
#if UIP_IDLE_TIMEOUT #if UIP_IDLE_TIMEOUT
if(uip_connr == uip_conns) { if(uip_connr == uip_conns) {
uip_idle_age = 0; uip_idle_age = 0;
@@ -915,7 +930,10 @@ uip_process(u8_t flag) __banked
#else /* UIP_REASSEMBLY */ #else /* UIP_REASSEMBLY */
UIP_STAT(++uip_stat.ip.drop); UIP_STAT(++uip_stat.ip.drop);
UIP_STAT(++uip_stat.ip.fragerr); UIP_STAT(++uip_stat.ip.fragerr);
UIP_LOG("ip: fragment dropped."); #if UIP_LOGGING == 1
if(fragdrop_count != 0xff)
++fragdrop_count;
#endif /* UIP_LOGGING == 1 */
goto drop; goto drop;
#endif /* UIP_REASSEMBLY */ #endif /* UIP_REASSEMBLY */
} }