Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c263a8ab64 | ||
|
|
c02f660c08 | ||
|
|
4e00f5a592 | ||
|
|
eff3f42ae1 | ||
|
|
dda873a633 | ||
|
|
9b2bd7f1b8 | ||
|
|
2dfe531fe0 | ||
|
|
72c2625121 | ||
|
|
58fd1a3ccc | ||
|
|
4f1a2f04d8 | ||
|
|
cedc795b82 | ||
|
|
ccf541a06b | ||
|
|
d5124df89e | ||
|
|
3eacc9c8a5 | ||
|
|
735672ccf1 | ||
|
|
1ebee4d6e9 | ||
|
|
e67c928eb7 | ||
|
|
46f8ea8712 | ||
|
|
b0eab52a2e | ||
|
|
8ce062c349 | ||
|
|
f768220a73 | ||
|
|
eab2e26510 | ||
|
|
b0ed56d423 | ||
|
|
36a064d03d | ||
|
|
2d01b8b7d7 | ||
|
|
fa632cdc6e | ||
|
|
177fb76e1b | ||
|
|
ff57084799 | ||
|
|
2dc5520928 | ||
|
|
7c11142a04 | ||
|
|
957a5b0e23 | ||
|
|
c773230a9b | ||
|
|
0e9c997d06 | ||
|
|
5ab247e996 | ||
|
|
d80717f3f0 | ||
|
|
24069439b0 | ||
|
|
4117f549cc | ||
|
|
2e24b24426 | ||
|
|
b71239f394 | ||
|
|
6e69f5bba3 | ||
|
|
1224335b66 | ||
|
|
e5b19bc594 | ||
|
|
89fcc6836d | ||
|
|
f9d4ab0074 | ||
|
|
6f68ccef28 | ||
|
|
8e687ef28e | ||
|
|
87db2dd4b8 | ||
|
|
aac1aed4c8 | ||
|
|
f0aea3dcac | ||
|
|
f10ab30f6d | ||
|
|
de431c6d84 | ||
|
|
26547f3e01 | ||
|
|
13b75a73c9 | ||
|
|
c6fceae724 | ||
|
|
068ec4c510 | ||
|
|
3a92459190 | ||
|
|
5ffeb3d16a | ||
|
|
de705380c9 | ||
|
|
e4f3315af3 | ||
|
|
07ab04e668 | ||
|
|
c5ce24ff78 | ||
|
|
bcb237158f | ||
|
|
f103daaafa | ||
|
|
168add47a3 | ||
|
|
423886dc54 | ||
|
|
4a9137387c | ||
|
|
2fc08f40d2 | ||
|
|
4a7fd7a098 | ||
|
|
19cd1200b4 | ||
|
|
333adbaf19 | ||
|
|
8051061fd7 | ||
|
|
8ae3f5e70f | ||
|
|
9ce328d155 | ||
|
|
2e463a2f30 | ||
|
|
422dc3f24d | ||
|
|
4b01ff9f8a | ||
|
|
456a4d9d3f | ||
|
|
02e9189f5f | ||
|
|
aff7d9c098 | ||
|
|
770926abd1 | ||
|
|
13f04d8acb | ||
|
|
49284fee15 | ||
|
|
db9ce7543e | ||
|
|
7a14c2d4a5 | ||
|
|
92948079a9 | ||
|
|
e406a3e82b | ||
|
|
c43b955db0 | ||
|
|
0321763e91 | ||
|
|
4bbbcd7d04 | ||
|
|
682ed861fa | ||
|
|
3a9045b97e | ||
|
|
4b9f6c319f | ||
|
|
6e2701bc8c | ||
|
|
ac3b4b17ae | ||
|
|
f87eb70c6a | ||
|
|
214cc6b737 | ||
|
|
40177f6318 | ||
|
|
d3dda09079 | ||
|
|
277e729f2c | ||
|
|
f778b9159b | ||
|
|
b6d6d2391d | ||
|
|
2c231fdf69 | ||
|
|
689751ffe6 | ||
|
|
fa93340c24 | ||
|
|
e9523a2f67 | ||
|
|
088be074f5 | ||
|
|
340fdd97e5 | ||
|
|
09ce4b391b | ||
|
|
7e6577a811 | ||
|
|
675faf0471 | ||
|
|
175ca9464a | ||
|
|
38241f0a08 | ||
|
|
0fe323b12f | ||
|
|
94187461c6 | ||
|
|
fa0eb91586 | ||
|
|
2f872ea08e | ||
|
|
ab2d30a05b | ||
|
|
d37ce07119 | ||
|
|
4bd6ffd083 | ||
|
|
94cfec8693 | ||
|
|
a4bb3f1725 | ||
|
|
931e6da0ab | ||
|
|
88454ec7d7 | ||
|
|
f0efb84abb | ||
|
|
62d3424a92 | ||
|
|
a3860c29cb | ||
|
|
b1961c6955 | ||
|
|
bb84bdc55a | ||
|
|
9733ff61a0 | ||
|
|
1b5243714e | ||
|
|
36459fdd76 | ||
|
|
ce11790a0d | ||
|
|
55431b39f6 | ||
|
|
46e1c955ba | ||
|
|
7b728cec6f | ||
|
|
0d17dd563f | ||
|
|
d556d634ca | ||
|
|
2844a1ed6d | ||
|
|
7b5e365d5e | ||
|
|
45fb382b07 | ||
|
|
8973774594 | ||
|
|
48c5b0c9cf | ||
|
|
1557a7cf3c | ||
|
|
131bc106af | ||
|
|
19ccc4003d | ||
|
|
b5fe9f217f | ||
|
|
f65d14f452 | ||
|
|
b92fba870c | ||
|
|
4deee377a7 | ||
|
|
fe42b07e2b | ||
|
|
9984649177 | ||
|
|
7d47edb649 | ||
|
|
fdb19fe0ee | ||
|
|
b9b50f9a70 | ||
|
|
c31b67572b | ||
|
|
a4e3b4368b | ||
|
|
93003c8cb8 | ||
|
|
fd058ea74d | ||
|
|
edc469fe29 | ||
|
|
a71c5359a5 | ||
|
|
9e3863cc4e | ||
|
|
d22ec04b5b | ||
|
|
0a65536a7f | ||
|
|
0631c813e2 | ||
|
|
eaebeba528 | ||
|
|
b36fd95356 | ||
|
|
52b1d1a4ea | ||
|
|
48f28ae7ff | ||
|
|
a7fc8303e9 | ||
|
|
a62866a93a | ||
|
|
42bbed9661 | ||
|
|
3c8de6da87 | ||
|
|
3a6f62b1d5 | ||
|
|
530e2683f0 | ||
|
|
9fedc6dd3d | ||
|
|
5e23d13771 | ||
|
|
09d5857fdd | ||
|
|
be309853c9 | ||
|
|
072edb36a8 | ||
|
|
10dd330e3c | ||
|
|
c514eb8bf3 | ||
|
|
e2c4ed6be3 | ||
|
|
56ee56af2e | ||
|
|
8626b4c1d4 | ||
|
|
0cc09e4015 | ||
|
|
674dc1f35d | ||
|
|
7e6b443e07 | ||
|
|
73ec184c23 | ||
|
|
bf41fbd202 | ||
|
|
04ab442c6d | ||
|
|
c02623a610 | ||
|
|
c69bf4c5ec | ||
|
|
575274786a | ||
|
|
7f4f6dae03 | ||
|
|
4eeb12c020 | ||
|
|
7d81b15b6e | ||
|
|
d6253ddc25 | ||
|
|
8cac67cdf7 | ||
|
|
5620e950ce | ||
|
|
83491bc9e3 | ||
|
|
eb83b8be09 | ||
|
|
bece4a20a1 | ||
|
|
cdc84c75e4 | ||
|
|
6be1871bb4 | ||
|
|
4686515de3 | ||
|
|
c39cc421a7 | ||
|
|
c1df7c23d1 | ||
|
|
13cc9db1ce | ||
|
|
3dcab09047 | ||
|
|
18b28edcbb | ||
|
|
f0b311fc43 | ||
|
|
974052877d | ||
|
|
ae77ffe495 | ||
|
|
ffde4eaf60 | ||
|
|
eb4bae278b | ||
|
|
552bd1cb18 |
No files matched your search
@@ -22,5 +22,9 @@ jobs:
|
||||
run: make -C test
|
||||
- name: Check if machine.c can be compiled for all machines
|
||||
run: make machine_check
|
||||
- name: Make project
|
||||
run: make MACHINE="KP_9000_6XHML_X2"
|
||||
- name: Make project (4x2/RTL8372)
|
||||
run: make CI=1 MACHINE="KP_9000_6XHML_X2"
|
||||
- name: Make project (8x1/RTL8373)
|
||||
run: make CI=1 MACHINE="KP_9000_9XHML_X_V3_1"
|
||||
- name: Make project with the health instrumentation
|
||||
run: make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1
|
||||
@@ -7,3 +7,7 @@ version.h
|
||||
tools/httpd_sim
|
||||
tools/injector
|
||||
tools/fileadder
|
||||
|
||||
# host-test stand-ins for the two generated headers
|
||||
!test/stub/html_data.h
|
||||
!test/stub/version.h
|
||||
@@ -14,6 +14,12 @@
|
||||
|
||||
## Fixed
|
||||
|
||||
- Config
|
||||
- A startup configuration line longer than the command buffer no longer stops the replay:
|
||||
the offending line is skipped and the following lines are still applied.
|
||||
- The web UI and the configuration upload now refuse a line the replay cannot take,
|
||||
instead of writing it to flash.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
- Config
|
||||
|
||||
@@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y \
|
||||
python3 \
|
||||
libjson-c-dev \
|
||||
git \
|
||||
zlib1g-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# git safe.directory for mounted repos (Makefile uses git describe)
|
||||
|
||||
@@ -19,6 +19,14 @@ ifeq ($(MACHINE),)
|
||||
else
|
||||
CC_FLAGS += -DMACHINE_$(MACHINE)
|
||||
endif
|
||||
# Health instrumentation and the "health" console command: HEALTH=1 gmake ...
|
||||
ifneq ($(HEALTH),)
|
||||
CC_FLAGS += -DHEALTH
|
||||
endif
|
||||
|
||||
ifeq ($(CI),1)
|
||||
CC_FLAGS += --Werror
|
||||
endif
|
||||
|
||||
BUILDDIR = output/$(MACHINE)
|
||||
VERSION_HEADER := version.h
|
||||
@@ -71,10 +79,13 @@ SRCS += \
|
||||
rtl837x_igmp.c \
|
||||
rtl837x_init.c \
|
||||
rtl837x_leds.c \
|
||||
rtl837x_leds_dump.c \
|
||||
rtl837x_phy.c \
|
||||
rtl837x_pins.c\
|
||||
rtl837x_port.c \
|
||||
rtl837x_stp.c
|
||||
rtl837x_stp.c \
|
||||
rtl837x_lldp.c \
|
||||
rtl837x_storm.c
|
||||
SRCS += \
|
||||
httpd/httpd.c \
|
||||
httpd/page_impl.c
|
||||
@@ -104,11 +115,14 @@ html_min: $(HTML)
|
||||
html_data.c html_data.h &: $(HTML) | tools html_min
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
|
||||
|
||||
$(VERSION_HEADER):
|
||||
$(VERSION_HEADER): FORCE
|
||||
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
|
||||
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
|
||||
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
|
||||
"#endif" > $(VERSION_HEADER)
|
||||
"#endif" > $(VERSION_HEADER).tmp
|
||||
@cmp -s $(VERSION_HEADER).tmp $(VERSION_HEADER) \
|
||||
&& rm -f $(VERSION_HEADER).tmp \
|
||||
|| mv $(VERSION_HEADER).tmp $(VERSION_HEADER)
|
||||
|
||||
httpd: html_data.h
|
||||
|
||||
@@ -126,15 +140,25 @@ distclean: $(SUBDIRSCLEAN)
|
||||
$(SUBDIRSCLEAN):
|
||||
$(MAKE) -C $(@:clean=) clean
|
||||
|
||||
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h
|
||||
# Objects depend on the flags they were built with, through a stamp file that
|
||||
# is rewritten only when CC_FLAGS actually changes.
|
||||
CCFLAGS_STAMP := $(BUILDDIR)/.ccflags
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
||||
$(CCFLAGS_STAMP): FORCE | create_build_dir
|
||||
@echo '$(CC_FLAGS)' | cmp -s - $@ 2>/dev/null || echo '$(CC_FLAGS)' > $@
|
||||
|
||||
$(BUILDDIR)/%.rel: %.c $(CCFLAGS_STAMP) | create_build_dir html_data.h
|
||||
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/%.rel: %.asm | create_build_dir
|
||||
$(BUILDDIR)/%.rel: %.asm $(CCFLAGS_STAMP) | create_build_dir
|
||||
${ASM} ${AFLAGS} -o $@ $<
|
||||
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
|
||||
|
||||
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
|
||||
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
||||
$(CC) $(CC_FLAGS) --xram-size 49151 -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
|
||||
|
||||
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
|
||||
objcopy --input-target=ihex -O binary $< $@
|
||||
@@ -144,11 +168,11 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i
|
||||
tools/output/imagebuilder -i $^ $@
|
||||
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -p html_data -b BANK1 $@
|
||||
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@
|
||||
tools/output/crc_calculator -u $@
|
||||
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
|
||||
|
||||
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) $(VERSION_HEADER) create_build_dir
|
||||
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir
|
||||
|
||||
.PHONY:
|
||||
machine_check:
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
A Playground for Firmware development for advanced user of RTL8372/RTL8373 based 2.5GBit Switches.
|
||||
|
||||
For each hardware configuration of these devices, there is usually a managed and an
|
||||
umanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||
unmanaged version sold, with mostly identical hardware. The aim is to provide management
|
||||
features also for unmanaged devices with additional features such as Management VLAN,
|
||||
dhcp servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||
DHCP servers, multi-language support, IPv6 and TLS-encrypted web-pages. At present, however
|
||||
only the following features are provided:
|
||||
- A modern web-interface with mouse-over to display further information
|
||||
- A serial console interface to configure all features
|
||||
- IGMP to configure Multicast streaming
|
||||
- Port configuration showing detailed informtion about own and Link-partner advertised
|
||||
Speed settins and configuration of these settings on the local side
|
||||
- Port configuration showing detailed information about own and Link-partner advertised
|
||||
Speed settings and configuration of these settings on the local side
|
||||
- Per-port configuration of frame sizes (MTUs) for Jumbo-Frame support or limiting MTUs
|
||||
for particular devices
|
||||
- EEE (Energy Efficient Ethernet) can be configured per-port. Detailed information is
|
||||
@@ -25,7 +25,7 @@ only the following features are provided:
|
||||
- Firmware updates via the web
|
||||
- Installation as a firmware upgrade from the original web-interface
|
||||
|
||||
<img width="1420" height="623" alt="GUI" src="doc/images/gui.png" />
|
||||
<img width="1673" height="977" alt="GUI" src="doc/images/gui.png" />
|
||||
|
||||
While the firmware provides already considerable improvements over the original managed firmware,
|
||||
the firmware still lacks support for the proprietary loop prevention
|
||||
@@ -37,7 +37,7 @@ a backup of the original flash content via a SOIC clamp such as also used for BI
|
||||
backups and can re-install that firmware in case something is wrong. For this no soldering
|
||||
skills are necessary.
|
||||
|
||||
The firmware supports all hardware featues of devices with
|
||||
The firmware supports all hardware features of devices with
|
||||
- 4 2.5GBit ports + 2 SFP+ ports
|
||||
- 5 2.5GBIT + 1 SFP+ port
|
||||
- 8 2.5GBit + 1 SFP+ port
|
||||
@@ -131,7 +131,7 @@ rtlplayground-v0.1.0-12c98ba-dirty-LIANGUO_ZX_SWTGW215AS.bin
|
||||
|
||||
> [!CAUTION]
|
||||
> This image can be flashed directly to the chip OR through the firmware update/upgrade
|
||||
> interface of RTLPlaygound interface
|
||||
> interface of RTLPlayground interface
|
||||
|
||||
## (2) Compiling for OEM running device with management options (web upgrade)
|
||||
|
||||
@@ -179,7 +179,7 @@ ghidra see this information about [Ghidra images](doc/ghidra.md).
|
||||
|
||||
## (4) Installation through the Web interface (software way)
|
||||
|
||||
Managed switches (OEM firmware of RTLplaygroud firmware) can be upgraded via the web interface.
|
||||
Managed switches (OEM firmware of RTLplayground firmware) can be upgraded via the web interface.
|
||||
Unmanaged switch cannot be flashed this way (see 5).
|
||||
|
||||
Go to "Firmware update" tab, select the correct file.
|
||||
@@ -190,7 +190,7 @@ Go to "Firmware update" tab, select the correct file.
|
||||
|
||||
> [!CAUTION]
|
||||
> Check one more time that your device matches the machine type before flashing.
|
||||
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung.
|
||||
> Be sure you have a backup of the original firmware before diving in RTLPlayground.
|
||||
|
||||
Finally, push the Upload File Button and you're done !
|
||||
|
||||
@@ -198,7 +198,7 @@ Finally, push the Upload File Button and you're done !
|
||||
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
|
||||
|
||||
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
|
||||
This is also the only way to unbrick your device if something went wroong.
|
||||
This is also the only way to unbrick your device if something went wrong.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
|
||||
@@ -218,7 +218,7 @@ This is also the only way to unbrick your device if something went wroong.
|
||||
- ERASE THE ROM (BLANK) !
|
||||
- Load the firmware into IMSProg.
|
||||
- Flash is to the ROM chip.
|
||||
- Disconect the clip from the ROM chip.
|
||||
- Disconnect the clip from the ROM chip.
|
||||
- You're done, ready for the first boot.
|
||||
|
||||
## (6) Connecting a serial interface (optional)
|
||||
@@ -233,7 +233,7 @@ When you power up the switch, the device will perform some examples and provide
|
||||
## (8) The web-interface
|
||||
|
||||
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
|
||||
specified an IP adress in the config.txt before compilation.
|
||||
specified an IP address in the config.txt before compilation.
|
||||
|
||||
> [!TIP]
|
||||
> The default password is `1234`.
|
||||
@@ -333,17 +333,18 @@ While in compilation part, you might write directly to config.txt file before ma
|
||||
nano config.txt
|
||||
```
|
||||
|
||||
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
|
||||
If you want to modify settings after the flash is done, go to the System tab and find the Startup Configuration.
|
||||
|
||||
<img width="1085" height="646" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
|
||||
<img width="1673" height="978" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
|
||||
|
||||
```
|
||||
ip xxx.xxx.xxx.xxx = IP adress of the switch
|
||||
gw yyy.yyy.yyy.yyy = IP adress of the gateway
|
||||
ip xxx.xxx.xxx.xxx = IP address of the switch
|
||||
gw yyy.yyy.yyy.yyy = IP address of the gateway
|
||||
netmask zzz.zzz.zzz.zzz = Network mask of the switch
|
||||
port x name xxx = Name xxx the port number x
|
||||
port z 1g = Set 1g speed for port z
|
||||
igmp on/off = Turn IGMP on or off
|
||||
session xxxx = Web session timeout in seconds (default 200)
|
||||
```
|
||||
[To be continue]
|
||||
|
||||
@@ -359,4 +360,5 @@ The following documents give further documentation on specific features of the R
|
||||
- [SFP+ ports](doc/sfp.md)
|
||||
- [Trunking aka. port aggregation](doc/trunking.md)
|
||||
- [VLAN](doc/vlan.md)
|
||||
- [Storm control](doc/storm_control.md)
|
||||
- [Modifications and Flash replacement](doc/mods.md)
|
||||
@@ -21,8 +21,9 @@ extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
__xdata uint32_t rtl8224_release_tick;
|
||||
extern __xdata uint8_t tx_seq;
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
|
||||
|
||||
|
||||
@@ -240,10 +241,10 @@ void rtl8224_enable(void) __banked
|
||||
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
// Configure Pin as output
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
|
||||
delay(100);
|
||||
delay(4);
|
||||
// Set pin 4 high
|
||||
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
|
||||
delay(500);
|
||||
rtl8224_release_tick = ticks;
|
||||
}
|
||||
|
||||
|
||||
@@ -397,10 +398,12 @@ void setup_i2c(void) __banked
|
||||
// HW Control register, enable I2C depending on PIN configuration
|
||||
reg_read_m(RTL837X_PIN_MUX_1);
|
||||
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
|
||||
const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl);
|
||||
const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda);
|
||||
uint8_t i2c = machine.sfp_port[sfp].i2c;
|
||||
uint8_t scl_bus = (i2c >> RTL837X_REG_I2C_SCL_SHIFT) & RTL837X_REG_I2C_SCL_MASK;
|
||||
uint8_t sda_bus = (i2c >> RTL837X_REG_I2C_SDA_SHIFT) & RTL837X_REG_I2C_SDA_MASK;
|
||||
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
|
||||
switch (scl_bus) {
|
||||
// `& RTL837X_REG_I2C_SCL_MASK` is needed to silens a compiler warning 110.
|
||||
switch (scl_bus & RTL837X_REG_I2C_SCL_MASK) {
|
||||
case 3:
|
||||
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
|
||||
sfr_mask_data(0, 0x60, 0x40);
|
||||
@@ -419,8 +422,6 @@ void setup_i2c(void) __banked
|
||||
sfr_mask_data(0, 0x80, 0x80);
|
||||
sfr_mask_data(1, 0x01, 0x00);
|
||||
break;
|
||||
default:
|
||||
print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n');
|
||||
}
|
||||
|
||||
switch (sda_bus) {
|
||||
@@ -444,8 +445,6 @@ void setup_i2c(void) __banked
|
||||
// Bit 9-10 0b01 -> SDA
|
||||
sfr_mask_data(1, 0x06, 0x02);
|
||||
break;
|
||||
default:
|
||||
print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n');
|
||||
}
|
||||
}
|
||||
reg_write_m(RTL837X_PIN_MUX_1);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
// #define DEBUG
|
||||
// #define REGDBG 1
|
||||
|
||||
#include <8051.h>
|
||||
#include "cmd_parser.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_flash.h"
|
||||
@@ -14,6 +16,8 @@
|
||||
#include "rtl837x_stp.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "rtl837x_bandwidth.h"
|
||||
#include "rtl837x_lldp.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "sfp.h"
|
||||
#include "dhcp.h"
|
||||
#include "syslog.h"
|
||||
@@ -21,26 +25,30 @@
|
||||
#include "version.h"
|
||||
|
||||
#include "machine.h"
|
||||
#include "rtl837x_leds.h"
|
||||
#include "phy.h"
|
||||
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata bool stp_enabled;
|
||||
extern __code uint8_t log_to_phys_port[9];
|
||||
extern __code const uint8_t log_to_phys_port[9];
|
||||
extern __xdata bool lldp_enabled;
|
||||
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern volatile __xdata uint8_t sfr_data[4];
|
||||
|
||||
extern __code uint8_t * __code greeting;
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code const uint8_t * __code const greeting;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
|
||||
extern __xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||
extern __xdata struct flash_region_t flash_region;
|
||||
|
||||
extern __xdata char passwd[21];
|
||||
|
||||
extern __xdata uint16_t session_timeout;
|
||||
|
||||
extern __xdata struct dhcp_state dhcp_state;
|
||||
|
||||
__xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
@@ -59,7 +67,6 @@ __xdata uint8_t hexvalue[4] = { 0 };
|
||||
|
||||
// Buffer for writing to flash 0x1fd000, copy to 0x1fe000
|
||||
__xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
__xdata uint8_t cmd_available;
|
||||
|
||||
__xdata char save_cmd;
|
||||
|
||||
@@ -105,7 +112,7 @@ inline uint8_t isnumber(uint8_t l)
|
||||
return (l <= ('9'-'0'));
|
||||
}
|
||||
|
||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd)
|
||||
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd)
|
||||
{
|
||||
if (cmd_words_len == 0 || start > (cmd_words_len - 1)) {
|
||||
return 0;
|
||||
@@ -426,6 +433,22 @@ err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmd_error(__code const char *msg)
|
||||
{
|
||||
err_status = ERR_INVALID_ARGUMENT;
|
||||
print_string("Error: ");
|
||||
print_string(msg);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t name_char(uint8_t c)
|
||||
{
|
||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||
return '.';
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// Sets the management MAC from a "mac <aa:bb:cc:dd:ee:ff>" command (or prints
|
||||
// the current one with a bare "mac"). Refuses blank/multicast/locally
|
||||
// administered/all-zero-OUI addresses so the running MAC stays reachable, and
|
||||
@@ -441,11 +464,11 @@ void parse_mac_cmd(void)
|
||||
return;
|
||||
}
|
||||
if (cmd_words_len != 2 || !parse_mac(cmd_words_b[1])) {
|
||||
print_string("Error: mac [<aa:bb:cc:dd:ee:ff>]\n");
|
||||
cmd_error("mac [<aa:bb:cc:dd:ee:ff>]\n");
|
||||
return;
|
||||
}
|
||||
if ((mac_parse_result[0] & 0x03) || ((mac_parse_result[0] | mac_parse_result[1] | mac_parse_result[2]) == 0)) {
|
||||
print_string("refusing: must be unicast, globally administered\n");
|
||||
cmd_error("the MAC must be unicast and globally administered\n");
|
||||
return;
|
||||
}
|
||||
if (memcmp(mac_parse_result, uip_ethaddr.addr, 6) == 0) {
|
||||
@@ -523,7 +546,7 @@ void parse_lag(void)
|
||||
port_lag_members_set(group, members);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: lag (show | <1-4> (d | <port>...))\n");
|
||||
cmd_error("lag (show | <1-4> (d | <port>...))\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -565,7 +588,7 @@ void parse_lag_hash(void)
|
||||
port_lag_hash_set(group, hash);
|
||||
return;
|
||||
err:
|
||||
print_string("Error: laghash <1-4> [smac|dmac|sip|dip|sport|dport]\n");
|
||||
cmd_error("laghash <1-4> [smac|dmac|sip|dip|sport|dport]\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -619,7 +642,7 @@ void parse_vlan(void)
|
||||
*vlan_str++ = hex[(vlan_settings.vlan >> 4) & 0xf] ;
|
||||
*vlan_str++ = hex[vlan_settings.vlan & 0xf];
|
||||
while(!cmd_is_space_or_nul(pos)) {
|
||||
uint8_t c = cmd_buffer[pos++];
|
||||
uint8_t c = name_char(cmd_buffer[pos++]);
|
||||
write_char(c);
|
||||
*vlan_str++ = c;
|
||||
}
|
||||
@@ -663,7 +686,7 @@ void parse_vlan(void)
|
||||
}
|
||||
return;
|
||||
err:
|
||||
print_string("Error: vlan (<vlan-id>|show) [port][t]...\n");
|
||||
cmd_error("vlan (<vlan-id>|show) [port][t]...\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -714,7 +737,7 @@ void parse_isolate(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("Error: isolate <port> [show|off] [port]...\n");
|
||||
cmd_error("isolate <port> [show|off] [port]...\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -751,7 +774,7 @@ void parse_ingress(void)
|
||||
// Setting mode for all ports at once
|
||||
for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) {
|
||||
if (!port_ingress_filter(log_port, mode)) {
|
||||
print_string("Error setting ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||
cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||
return;
|
||||
}
|
||||
print_string("All ports ingress filter set to: ");
|
||||
@@ -762,18 +785,18 @@ void parse_ingress(void)
|
||||
idx = cmd_words_b[w];
|
||||
uint8_t ret = cmd_parse_port(idx);
|
||||
if (ret != 1) {
|
||||
print_string("Invalid physical port number\n");
|
||||
cmd_error("Invalid physical port number\n");
|
||||
continue;
|
||||
}
|
||||
log_port = atoi_results_u8;
|
||||
idx += ret;
|
||||
|
||||
if (!vlan_ingress_mode_parse(cmd_buffer[idx++], &mode) || !cmd_is_space_or_nul(idx)) {
|
||||
print_string("Invalid ingress mode for port "); print_phys_port(log_port); print_string(" in ingress command\n");
|
||||
cmd_error("Invalid ingress mode for port "); print_phys_port(log_port); print_string(" in ingress command\n");
|
||||
goto err;
|
||||
}
|
||||
if (!port_ingress_filter(log_port, mode)) {
|
||||
print_string("Error setting ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||
cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n');
|
||||
return;
|
||||
}
|
||||
print_string("Port "); print_phys_port(log_port);
|
||||
@@ -783,7 +806,7 @@ void parse_ingress(void)
|
||||
}
|
||||
return;
|
||||
err:
|
||||
print_string("Error: ingress [p]<u/t/a>...\n");
|
||||
cmd_error("ingress [p]<u/t/a>...\n");
|
||||
}
|
||||
|
||||
void parse_mirror(void)
|
||||
@@ -848,7 +871,7 @@ void parse_mirror(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("Port/command missing: mirror [status/off/<mirroring port> [port][t/r]]...\n");
|
||||
cmd_error("Port/command missing: mirror [status/off/<mirroring port> [port][t/r]]...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -856,15 +879,16 @@ err:
|
||||
void parse_port(void)
|
||||
{
|
||||
if (cmd_words_len < 3) {
|
||||
print_string("\nUsage:" \
|
||||
cmd_error("\nUsage:" \
|
||||
"\nport <port> [show|on|off]" \
|
||||
"\nport <port> [10m|100m|1g|2g5|duplex] [half|full]" \
|
||||
"\nport <port> lldp [block|permit]" \
|
||||
"\nport <port> name [custom port name]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd_parse_port_separator(cmd_words_b[1]) == 0) {
|
||||
print_string("Invalid port number\n");
|
||||
cmd_error("Invalid port number\n");
|
||||
return;
|
||||
}
|
||||
phy_settings.port = atoi_results_u8;
|
||||
@@ -877,17 +901,28 @@ void parse_port(void)
|
||||
print_string_x(port_names[phy_settings.port]);
|
||||
if (!machine.is_sfp[phy_settings.port]) {
|
||||
phy_show(phy_settings.port);
|
||||
} else {
|
||||
write_char('\n');
|
||||
}
|
||||
port_media_show(phy_settings.port);
|
||||
} else if (cmd_compare(2, "name")) {
|
||||
uint8_t i = 0;
|
||||
while ( (i < PORT_NAME_SIZE-1) && (cmd_buffer[cmd_words_b[3] + i] != NUL) ) {
|
||||
port_names[phy_settings.port][i] = cmd_buffer[cmd_words_b[3] + i];
|
||||
while ( cmd_words_len > 3 && (i < PORT_NAME_SIZE-1) && (cmd_buffer[cmd_words_b[3] + i] != NUL) ) {
|
||||
port_names[phy_settings.port][i] = name_char(cmd_buffer[cmd_words_b[3] + i]);
|
||||
i++;
|
||||
}
|
||||
port_names[phy_settings.port][i] = NUL;
|
||||
print_string("\nName set to: \"");
|
||||
print_string_x(port_names[phy_settings.port]);
|
||||
print_string("\"\n");
|
||||
} else if (cmd_compare(2, "lldp")) {
|
||||
if (cmd_compare(3, "block")){
|
||||
lldp_logical_port_status &= ~((uint16_t)1 << phy_settings.port);
|
||||
} else if (cmd_compare(3, "permit")) {
|
||||
lldp_logical_port_status |= (uint16_t)1 << phy_settings.port;
|
||||
} else {
|
||||
print_string ("Unknown port <port> lldp [block|permit] command\n");
|
||||
}
|
||||
} else if (machine.is_sfp[phy_settings.port]) {
|
||||
print_string(" is SFP no PHY information available.\n");
|
||||
} else if (cmd_compare(2, "10m")) {
|
||||
@@ -942,7 +977,7 @@ void parse_port(void)
|
||||
phy_settings.duplex = PHY_DUPLEX_HALF;
|
||||
phy_set_duplex();
|
||||
} else {
|
||||
print_string("Unknown port command\n");
|
||||
cmd_error("Unknown port command\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,7 +1005,7 @@ void parse_mtu(void)
|
||||
print_byte(p);
|
||||
|
||||
if (atoi_short(cmd_words_b[2]) == 0 || atoi_results_short < 64 || atoi_results_short > 0x3fff) {
|
||||
print_string("MTU must be 64..16383\n");
|
||||
cmd_error("MTU must be 64..16383\n");
|
||||
return;
|
||||
}
|
||||
REG_WRITE(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8), (atoi_results_short >> 10) & 0xf, (atoi_results_short >> 2) & 0xff,
|
||||
@@ -979,7 +1014,7 @@ void parse_mtu(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("mtu [port] [size]\n");
|
||||
cmd_error("mtu [port] [size]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1036,11 +1071,11 @@ void parse_sfp(void)
|
||||
idx += ret;
|
||||
slot = atoi_results_u8 - 1;
|
||||
if (ret == 0 || !cmd_is_space(idx) || slot > 1) {
|
||||
print_string("Illegal SFP slot number\n");
|
||||
cmd_error("Illegal SFP slot number\n");
|
||||
return;
|
||||
}
|
||||
if (slot >= machine.n_sfp) {
|
||||
print_string("SFP slot not present\n");
|
||||
cmd_error("SFP slot not present\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1066,7 +1101,7 @@ void parse_sfp(void)
|
||||
handle_sfp();
|
||||
return;
|
||||
err:
|
||||
print_string("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
|
||||
cmd_error("\nUsage:\n\tsfp\n\tsfp [1|2] [1g|2g5|10g]\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1098,7 +1133,7 @@ void parse_regget(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: regget <hexvalue>\n\tlike: regget 0BB0 or regget 0c");
|
||||
cmd_error("regget <hexvalue>\n\tlike: regget 0BB0 or regget 0c");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1145,7 +1180,33 @@ void parse_regset(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: regset <hexvalue> <hexvalue>\n\tlike regset 0b abcd1234.");
|
||||
cmd_error("regset <hexvalue> <hexvalue>\n\tlike regset 0b abcd1234.");
|
||||
}
|
||||
|
||||
|
||||
static void print_temperature(uint16_t reg)
|
||||
{
|
||||
int16_t v;
|
||||
|
||||
reg_read(reg);
|
||||
v = SFR_DATA_U16;
|
||||
if (v < 0) {
|
||||
write_char('-');
|
||||
v = -v;
|
||||
}
|
||||
itoa(v >> 7);
|
||||
write_char('.');
|
||||
itoa(((v & 0x7f) * 10) >> 7);
|
||||
print_string(" C\n");
|
||||
}
|
||||
|
||||
|
||||
void parse_temp(void)
|
||||
{
|
||||
print_string("\nChip temperature: ");
|
||||
print_temperature(RTL837X_TM_RESULT);
|
||||
print_string("At power-on: ");
|
||||
print_temperature(RTL837X_TM_RESULT_POWERON);
|
||||
}
|
||||
|
||||
|
||||
@@ -1188,7 +1249,7 @@ void parse_sdsget(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: sdsget <sds-id> <hex:page> <hex:reg>\n");
|
||||
cmd_error("sdsget <sds-id> <hex:page> <hex:reg>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1244,7 +1305,7 @@ void parse_sdsset(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: sdsset <sds-id> <hex:page> <hex:reg> <hex:val>\n");
|
||||
cmd_error("sdsset <sds-id> <hex:page> <hex:reg> <hex:val>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1293,7 +1354,7 @@ void parse_phyget(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: phyget <phy-id> <dev-id> <hex:reg>\n");
|
||||
cmd_error("phyget <phy-id> <dev-id> <hex:reg>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1353,7 +1414,7 @@ void parse_physet(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: physet <phy-id> <dev-id> <hex:reg> <hex:val>\n");
|
||||
cmd_error("physet <phy-id> <dev-id> <hex:reg> <hex:val>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1388,7 +1449,7 @@ void parse_passwd(void)
|
||||
passwd[j] = NUL;
|
||||
return;
|
||||
}
|
||||
print_string("Missing password\n");
|
||||
cmd_error("Missing password\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -1411,8 +1472,8 @@ void parse_eee(void)
|
||||
speed_word = 2;
|
||||
} else if (cmd_is_space_or_nul(idx)) {
|
||||
// Word 2 is a port number
|
||||
if (cmd_parse_port_separator(idx) == 0) {
|
||||
print_string("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
if (cmd_parse_port_separator(cmd_words_b[2]) == 0) {
|
||||
cmd_error("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
return;
|
||||
}
|
||||
port = atoi_results_u8;
|
||||
@@ -1431,7 +1492,7 @@ void parse_eee(void)
|
||||
speed = EEE_2G5;
|
||||
else
|
||||
{
|
||||
print_string("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
cmd_error("Speed word invalid, use: [100m|1g|2g5]\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1451,7 +1512,7 @@ void parse_eee(void)
|
||||
else
|
||||
port_eee_status_all();
|
||||
} else {
|
||||
print_string("eee [on|off|status] [port] [100m|1g|2g5]\n");
|
||||
cmd_error("eee [on|off|status] [port] [100m|1g|2g5]\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1522,7 +1583,58 @@ void parse_bw(void)
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
||||
cmd_error("bw [in|out|status] <port> [<hexvalue>|off|drop|fc]\n");
|
||||
}
|
||||
|
||||
static __code const char * __code const storm_types[STORM_TYPES] = { "bcast", "mcast", "ucast", "umcast" };
|
||||
|
||||
void parse_storm(void)
|
||||
{
|
||||
uint8_t port, type, d;
|
||||
__xdata uint32_t rate;
|
||||
__xdata uint8_t *p;
|
||||
|
||||
if (cmd_words_len == 1)
|
||||
return storm_show();
|
||||
if (cmd_words_len < 4 || !cmd_parse_port_separator(cmd_words_b[1]))
|
||||
goto err;
|
||||
port = atoi_results_u8;
|
||||
|
||||
type = 0;
|
||||
while (!cmd_compare(2, storm_types[type])) {
|
||||
if (++type == STORM_TYPES)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (cmd_words_len == 4 && cmd_compare(3, "off"))
|
||||
return storm_off(port, type);
|
||||
if (cmd_words_len != 5)
|
||||
goto err;
|
||||
|
||||
rate = 0;
|
||||
p = &cmd_buffer[cmd_words_b[3]];
|
||||
do {
|
||||
d = *p++ - '0';
|
||||
if (d > 9 || rate > 99999999)
|
||||
goto err;
|
||||
rate = (rate << 3) + (rate << 1) + d;
|
||||
} while (*p != ' ' && *p != NUL);
|
||||
|
||||
if (cmd_compare(4, "pps")) {
|
||||
if (!rate || rate > 0xfffff)
|
||||
goto err;
|
||||
storm_set(port, type, rate, 1);
|
||||
} else if (cmd_compare(4, "kbps")) {
|
||||
if (!rate || rate > 10000000)
|
||||
goto err;
|
||||
storm_set(port, type, rate, 0);
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
return;
|
||||
|
||||
err:
|
||||
print_string("usage: storm [<port> bcast|mcast|ucast|umcast <rate> pps|kbps|off]\n");
|
||||
}
|
||||
|
||||
void parse_syslog(void)
|
||||
@@ -1560,7 +1672,7 @@ void parse_syslog(void)
|
||||
if (was_enabled)
|
||||
syslog_start();
|
||||
} else {
|
||||
print_string("Invalid IP address\n");
|
||||
cmd_error("Invalid IP address\n");
|
||||
}
|
||||
} else if (cmd_compare(1, "port")) {
|
||||
if (cmd_words_len < 3) { // no additional argument -> print current port
|
||||
@@ -1571,7 +1683,7 @@ void parse_syslog(void)
|
||||
/* atoi_short() returns zero for no digits and for a value past
|
||||
* 65535; port zero is not a port either, so both tests are needed. */
|
||||
if (!atoi_short(cmd_words_b[2]) || !atoi_results_short) {
|
||||
print_string("Invalid port\n");
|
||||
cmd_error("Invalid port\n");
|
||||
return;
|
||||
}
|
||||
/* The port is frozen into the connection by uip_udp_new(), so
|
||||
@@ -1587,12 +1699,31 @@ void parse_syslog(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
print_string("Error: syslog [on|off|ip [ip-address]|port [number]]\n");
|
||||
print_string(" on/off enables or disables syslog, ip sets the syslog server IP address,\n");
|
||||
print_string(" port sets the destination UDP port (default 514)\n");
|
||||
cmd_error("syslog [on|off|ip [ip-address]|port [number]]\n"
|
||||
" on/off enables or disables syslog, ip sets the syslog server IP address,\n"
|
||||
" port sets the destination UDP port (default 514)\n");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_session(void)
|
||||
{
|
||||
if (cmd_words_len >= 2) {
|
||||
/* atoi_short() returns zero for no digits and for a value past
|
||||
* 65535; a zero-second timeout is not useful either, so both
|
||||
* tests are needed. */
|
||||
if (!atoi_short(cmd_words_b[1]) || !atoi_results_short) {
|
||||
print_string("Must be 1-65535 s\n");
|
||||
return;
|
||||
}
|
||||
session_timeout = atoi_results_short;
|
||||
}
|
||||
/* Also the confirmation after setting: one message for both. */
|
||||
print_string("Session timeout: ");
|
||||
itoa_short(session_timeout);
|
||||
print_string(" s\n");
|
||||
}
|
||||
|
||||
|
||||
// Parse command into words
|
||||
// cmd_words_len contains the number of words found.
|
||||
// cmd_words_b[] contains only start of a word offset.
|
||||
@@ -1757,7 +1888,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Setting ip: ");
|
||||
print_ip(ip); write_char('\n');
|
||||
} else {
|
||||
print_string("Invalid IP address\n" \
|
||||
cmd_error("Invalid IP address\n" \
|
||||
"Error: ip [<ip-address>|dhcp]\n" \
|
||||
" The dhcp option enables the dhcp client, calling ip without options prints the current IP\n" \
|
||||
" Calling with a valid IP address will stop any ongoing dhcp client and set the IP address\n");
|
||||
@@ -1773,7 +1904,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Setting gw: ");
|
||||
print_ip(ip); write_char('\n');
|
||||
} else {
|
||||
print_string("Invalid IP address\n" \
|
||||
cmd_error("Invalid IP address\n" \
|
||||
"Error: gw <ip-address>\n");
|
||||
}
|
||||
}
|
||||
@@ -1787,7 +1918,7 @@ void cmd_parser(void) __banked
|
||||
print_string("Setting netmask: ");
|
||||
print_ip(ip); write_char('\n');
|
||||
} else {
|
||||
print_string("Invalid IP address\n");
|
||||
cmd_error("Invalid IP address\n");
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
@@ -1803,8 +1934,9 @@ void cmd_parser(void) __banked
|
||||
igmp_setup();
|
||||
else if (cmd_compare(1, "show"))
|
||||
igmp_show();
|
||||
else
|
||||
print_string("Error: igmp on|off|show\n");
|
||||
else {
|
||||
cmd_error("igmp on|off|show\n");
|
||||
}
|
||||
} else if (cmd_compare(0, "mac")) {
|
||||
parse_mac_cmd();
|
||||
} else if (cmd_compare(0, "hostname")) {
|
||||
@@ -1822,22 +1954,25 @@ void cmd_parser(void) __banked
|
||||
uint8_t c = *hp++;
|
||||
if (c == NUL || c == '\r' || c == '\n')
|
||||
break;
|
||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||
c = '.';
|
||||
*dst++ = c;
|
||||
*dst++ = name_char(c);
|
||||
}
|
||||
*dst = NUL;
|
||||
} else {
|
||||
print_string("Error: hostname [name] - the name must not contain spaces\n");
|
||||
cmd_error("hostname [name] - the name must not contain spaces\n");
|
||||
}
|
||||
} else if (cmd_compare(0, "stp")) {
|
||||
stp_parse();
|
||||
#ifdef HEALTH
|
||||
} else if (cmd_compare(0, "health")) {
|
||||
health_show();
|
||||
#endif
|
||||
} else if (cmd_compare(0, "pvid")) {
|
||||
if (cmd_words_len == 3 && cmd_parse_port_separator(cmd_words_b[1]) != 0
|
||||
&& atoi_short(cmd_words_b[2]) && atoi_results_short && atoi_results_short <= 4094)
|
||||
port_pvid_set(atoi_results_u8, atoi_results_short);
|
||||
else
|
||||
print_string("Error: pvid <port> <1-4094>\n");
|
||||
else {
|
||||
cmd_error("pvid <port> <1-4094>\n");
|
||||
}
|
||||
} else if (cmd_compare(0, "vlan")) {
|
||||
parse_vlan();
|
||||
} else if (cmd_compare(0, "isolate")) {
|
||||
@@ -1853,6 +1988,8 @@ void cmd_parser(void) __banked
|
||||
write_char('\n');
|
||||
} else if (cmd_compare(0, "gpio")) {
|
||||
print_gpio_status();
|
||||
} else if (cmd_compare(0, "leds")) {
|
||||
leds_dump();
|
||||
} else if (cmd_compare(0, "regget")) {
|
||||
parse_regget();
|
||||
} else if (cmd_compare(0, "regset")) {
|
||||
@@ -1873,6 +2010,10 @@ void cmd_parser(void) __banked
|
||||
parse_eee();
|
||||
} else if (cmd_compare(0, "bw")) {
|
||||
parse_bw();
|
||||
} else if (cmd_compare(0, "temp")) {
|
||||
parse_temp();
|
||||
} else if (cmd_compare(0, "storm")) {
|
||||
parse_storm();
|
||||
} else if (cmd_compare(0, "version")) {
|
||||
print_sw_version();
|
||||
} else if (cmd_compare(0, "time")) {
|
||||
@@ -1895,13 +2036,23 @@ void cmd_parser(void) __banked
|
||||
}
|
||||
} else if (cmd_compare(0, "ingress")) {
|
||||
parse_ingress();
|
||||
} else if (cmd_compare(0, "session")) {
|
||||
parse_session();
|
||||
} else if (cmd_compare(0, "lldp")) {
|
||||
if (cmd_compare(1, "on")) {
|
||||
print_string("LLDP enabled\n");
|
||||
lldp_enabled = 1;
|
||||
} else {
|
||||
print_string("LLDP disabled\n");
|
||||
lldp_enabled = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print_string("Unknown command\n");
|
||||
cmd_error("Unknown command\n");
|
||||
}
|
||||
|
||||
|
||||
if (save_cmd && cmd_words_len) {
|
||||
if (save_cmd && cmd_words_len && err_status == ERR_OK) {
|
||||
// Find end of the cmd-buffer, looking for the NUL-byte.
|
||||
uint8_t i = cmd_words_b[cmd_words_len - 1];
|
||||
do {
|
||||
@@ -1946,6 +2097,7 @@ void execute_config(void) __banked
|
||||
save_cmd = 0;
|
||||
|
||||
uint8_t cmd_idx = 0;
|
||||
uint8_t skipping = 0;
|
||||
do {
|
||||
flash_region.addr = pos;
|
||||
flash_region.len = FLASH_READ_BURST_SIZE;
|
||||
@@ -1956,20 +2108,23 @@ void execute_config(void) __banked
|
||||
do {
|
||||
if (cmd_idx >= (CMD_BUF_SIZE - 1)) {
|
||||
cmd_buffer[cmd_idx] = NUL;
|
||||
print_string("ERROR: Command too long: ");
|
||||
print_string("ERROR: Command too long, skipped: ");
|
||||
print_string_x(cmd_buffer);
|
||||
write_char('\n');
|
||||
err_status = ERR_CMD_TOO_LONG;
|
||||
goto config_done;
|
||||
cmd_idx = 0;
|
||||
skipping = 1;
|
||||
}
|
||||
c = flash_buf[cfg_idx++];
|
||||
if (c == 0 || c == '\n') {
|
||||
cmd_buffer[cmd_idx] = NUL;
|
||||
if (cmd_idx) {
|
||||
cmd_tokenize();
|
||||
if (err_status != ERR_OK)
|
||||
goto config_done;
|
||||
cmd_parser();
|
||||
if (skipping) {
|
||||
skipping = 0;
|
||||
} else {
|
||||
cmd_buffer[cmd_idx] = NUL;
|
||||
if (cmd_idx) {
|
||||
cmd_tokenize();
|
||||
if (err_status == ERR_OK)
|
||||
cmd_parser();
|
||||
}
|
||||
}
|
||||
if (c == 0)
|
||||
goto config_done;
|
||||
@@ -1977,8 +2132,10 @@ void execute_config(void) __banked
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd_buffer[cmd_idx] = c;
|
||||
cmd_idx++;
|
||||
if (!skipping) {
|
||||
cmd_buffer[cmd_idx] = c;
|
||||
cmd_idx++;
|
||||
}
|
||||
} while (cfg_idx);
|
||||
|
||||
pages_left--;
|
||||
@@ -1995,6 +2152,7 @@ config_done:
|
||||
// If a command is too long or can't be tokenized, remaining commands are not executed
|
||||
// Returns the status via `err_status`-variable.
|
||||
void execute_commands(__xdata uint8_t *p) __banked {
|
||||
__xdata uint8_t failed = ERR_OK;
|
||||
err_status = ERR_OK;
|
||||
uint8_t cmd_idx = 0;
|
||||
while (1) {
|
||||
@@ -2005,9 +2163,13 @@ void execute_commands(__xdata uint8_t *p) __banked {
|
||||
if (err_status != ERR_OK)
|
||||
return;
|
||||
cmd_parser();
|
||||
if (failed == ERR_OK)
|
||||
failed = err_status;
|
||||
}
|
||||
if (*p == 0)
|
||||
if (*p == 0) {
|
||||
err_status = failed;
|
||||
return;
|
||||
}
|
||||
cmd_idx = 0;
|
||||
} else {
|
||||
if (cmd_idx < (CMD_BUF_SIZE - 1)) {
|
||||
@@ -2024,3 +2186,161 @@ void execute_commands(__xdata uint8_t *p) __banked {
|
||||
p++;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef HEALTH
|
||||
/*
|
||||
* Health instrumentation. The counters live in xdata and are fed from the
|
||||
* main loop through the banked entry points below; the "health" command
|
||||
* prints everything in one go. All figures are raw hex, diffing two dumps
|
||||
* gives the rates. Phase times are in system ticks (SYS_TICK_HZ = 200,
|
||||
* 5 ms each); a phase counts as slow when it spans 2 or more ticks.
|
||||
*/
|
||||
extern __xdata uint16_t len_left; /* httpd: bytes still to send of the current file */
|
||||
extern __xdata uint8_t entry; /* httpd: index of the file being sent */
|
||||
|
||||
static __xdata uint32_t health_loops;
|
||||
__xdata uint16_t health_rx_frames;
|
||||
|
||||
static __xdata uint16_t ph_last_t;
|
||||
static __xdata uint8_t ph_max[HEALTH_PHASES];
|
||||
static __xdata uint16_t ph_slow[HEALTH_PHASES];
|
||||
|
||||
/* The ISR increments ticks between the two byte reads of a 16-bit load, so
|
||||
* read until two loads agree. */
|
||||
static uint16_t ticks_lo(void)
|
||||
{
|
||||
uint16_t a, b;
|
||||
a = (uint16_t)ticks;
|
||||
do {
|
||||
b = a;
|
||||
a = (uint16_t)ticks;
|
||||
} while (a != b);
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void health_loop_start(void) __banked
|
||||
{
|
||||
health_loops++;
|
||||
ph_last_t = ticks_lo();
|
||||
}
|
||||
|
||||
|
||||
void health_phase(uint8_t id) __banked
|
||||
{
|
||||
__xdata uint16_t now = ticks_lo();
|
||||
__xdata uint16_t d = now - ph_last_t;
|
||||
ph_last_t = now;
|
||||
if (d > 0xff)
|
||||
d = 0xff;
|
||||
if ((uint8_t)d > ph_max[id])
|
||||
ph_max[id] = d;
|
||||
if (d >= 2)
|
||||
ph_slow[id]++;
|
||||
}
|
||||
|
||||
|
||||
/* Fill the stack area above the current frame with a pattern; the dump scans
|
||||
* for how much of it survived. The 8051 stack grows upward, so everything
|
||||
* above SP is free at this point. Interrupts are held off so an ISR does not
|
||||
* push into the area mid-paint. */
|
||||
void health_stack_paint(void) __banked
|
||||
{
|
||||
__xdata uint8_t from = SP + 4;
|
||||
__xdata uint8_t ea = EA;
|
||||
EA = 0;
|
||||
for (uint8_t i = 0xff; i >= from; i--)
|
||||
*(__idata uint8_t *)i = 0xa5;
|
||||
EA = ea;
|
||||
}
|
||||
|
||||
|
||||
static void ph_line(__code const char *name, uint8_t id)
|
||||
{
|
||||
print_string(name);
|
||||
print_string(" max ");
|
||||
print_byte(ph_max[id]);
|
||||
print_string(" slow ");
|
||||
print_short(ph_slow[id]);
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
void health_show(void) __banked
|
||||
{
|
||||
__xdata uint8_t i;
|
||||
|
||||
print_string("up ");
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
print_string(" ticks ");
|
||||
print_long(ticks);
|
||||
print_string(" loops ");
|
||||
print_long(health_loops);
|
||||
print_string(" rx ");
|
||||
print_short(health_rx_frames);
|
||||
write_char('\n');
|
||||
|
||||
/* Phase timing: max duration seen (ticks of 5 ms) and slow-pass count */
|
||||
ph_line("link", HEALTH_PH_LINK);
|
||||
ph_line("sfp ", HEALTH_PH_SFP);
|
||||
ph_line("rx ", HEALTH_PH_RX);
|
||||
ph_line("tx ", HEALTH_PH_TX);
|
||||
ph_line("stp ", HEALTH_PH_STP);
|
||||
ph_line("cmd ", HEALTH_PH_CMD);
|
||||
|
||||
/* Stack: current depth plus how much of the painted area is untouched */
|
||||
print_string("sp ");
|
||||
print_byte(SP);
|
||||
print_string(" untouched ");
|
||||
i = 0;
|
||||
while (*(__idata uint8_t *)(0xff - i) == 0xa5 && i < 0x86)
|
||||
i++;
|
||||
print_byte(i);
|
||||
write_char('\n');
|
||||
|
||||
/* The TCP connection slot. One on this configuration; a build with more
|
||||
* has to say which slot each line is, so make that a visible decision. */
|
||||
#if UIP_CONNS != 1
|
||||
#error "health: the tcp dump prints a single slot, extend it for UIP_CONNS > 1"
|
||||
#endif
|
||||
i = 0;
|
||||
{
|
||||
print_string("tcp ");
|
||||
print_string("st ");
|
||||
print_byte(uip_conns[i].tcpstateflags);
|
||||
print_string(" tmr ");
|
||||
print_byte(uip_conns[i].timer);
|
||||
print_string(" rtx ");
|
||||
print_byte(uip_conns[i].nrtx);
|
||||
print_string(" rto ");
|
||||
print_byte(uip_conns[i].rto);
|
||||
print_string(" len ");
|
||||
print_short(uip_conns[i].len);
|
||||
print_string(" mss ");
|
||||
print_short(uip_conns[i].mss);
|
||||
write_char('\n');
|
||||
print_string(" lport ");
|
||||
print_short(HTONS(uip_conns[i].lport));
|
||||
print_string(" rport ");
|
||||
print_short(HTONS(uip_conns[i].rport));
|
||||
print_string(" rip ");
|
||||
print_short(HTONS(uip_conns[i].ripaddr[0]));
|
||||
write_char(' ');
|
||||
print_short(HTONS(uip_conns[i].ripaddr[1]));
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
/* httpd transfer state and the protocol flags */
|
||||
print_string("httpd left ");
|
||||
print_short(len_left);
|
||||
print_string(" entry ");
|
||||
print_byte(entry);
|
||||
print_string(" stp ");
|
||||
print_byte(stp_enabled);
|
||||
print_string(" mvlan ");
|
||||
print_short(management_vlan);
|
||||
write_char('\n');
|
||||
}
|
||||
#endif
|
||||
@@ -6,9 +6,36 @@
|
||||
#include "rtl837x_common.h"
|
||||
|
||||
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
extern __xdata uint8_t cmd_available;
|
||||
extern __bit __at(0x03) cmd_available;
|
||||
extern __xdata uint8_t err_status;
|
||||
|
||||
/* Health instrumentation, built with HEALTH=1. Without it the hooks below
|
||||
* compile to nothing and the "health" command does not exist. */
|
||||
#ifdef HEALTH
|
||||
/* Phase ids, in main-loop order */
|
||||
#define HEALTH_PH_LINK 0
|
||||
#define HEALTH_PH_SFP 1
|
||||
#define HEALTH_PH_RX 2
|
||||
#define HEALTH_PH_TX 3
|
||||
#define HEALTH_PH_STP 4
|
||||
#define HEALTH_PH_CMD 5
|
||||
#define HEALTH_PHASES 6
|
||||
#define HEALTH_LLDP 7
|
||||
|
||||
extern __xdata uint16_t health_rx_frames;
|
||||
#define health_rx_frame() health_rx_frames++
|
||||
|
||||
void health_loop_start(void) __banked; /* once per idle() pass, resets the phase baseline */
|
||||
void health_phase(uint8_t id) __banked; /* after each phase; accounts ticks since last checkpoint */
|
||||
void health_stack_paint(void) __banked; /* paint the unused stack area once at boot */
|
||||
void health_show(void) __banked; /* "health" CLI dump */
|
||||
#else
|
||||
#define health_rx_frame()
|
||||
#define health_loop_start()
|
||||
#define health_phase(id)
|
||||
#define health_stack_paint()
|
||||
#endif
|
||||
|
||||
void cmd_tokenize(void) __banked;
|
||||
void cmd_parser(void) __banked;
|
||||
void execute_config(void) __banked;
|
||||
|
||||
@@ -139,7 +139,6 @@ void dhcp_addopt_request_ip(void)
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
|
||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||
}
|
||||
|
||||
|
||||
@@ -151,13 +150,11 @@ void dhcp_addopt_server_id(void)
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
|
||||
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
|
||||
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
||||
}
|
||||
|
||||
|
||||
void dhcp_send_discover(void)
|
||||
{
|
||||
print_string("dhcp_send_discover called\n");
|
||||
dhcp_prepare_request();
|
||||
|
||||
dhcp_state.opt_ptr = 0;
|
||||
@@ -193,7 +190,6 @@ void dhcp_send_discover(void)
|
||||
|
||||
void dhcp_send_request(void)
|
||||
{
|
||||
print_string("dhcp_send_request called\n");
|
||||
dhcp_prepare_request();
|
||||
|
||||
dhcp_state.opt_ptr = 0;
|
||||
@@ -232,19 +228,21 @@ void ip_opt(__xdata uint8_t * ip)
|
||||
{
|
||||
dhcp_state.opt_ptr++;
|
||||
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
*ip++ = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
if (len >= 4)
|
||||
memcpy(ip, &DHCP_OPT[dhcp_state.opt_ptr], 4);
|
||||
// There may be more than one IP option, such as 2 DNS servers advertised
|
||||
dhcp_state.opt_ptr += len - 4;
|
||||
dhcp_state.opt_ptr += len;
|
||||
}
|
||||
|
||||
|
||||
void long_opt(void)
|
||||
uint8_t long_opt(void)
|
||||
{
|
||||
dhcp_state.opt_ptr++;
|
||||
dhcp_state.opt_ptr++;
|
||||
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
if (len < 4) {
|
||||
dhcp_state.opt_ptr += len;
|
||||
return 0;
|
||||
}
|
||||
long_value = DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
long_value <<= 8;
|
||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
@@ -252,6 +250,8 @@ void long_opt(void)
|
||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
long_value <<= 8;
|
||||
long_value |= DHCP_OPT[dhcp_state.opt_ptr++];
|
||||
dhcp_state.opt_ptr += len - 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -275,16 +275,16 @@ void parse_opts(void)
|
||||
ip_opt(&dhcp_state.broadcast[0]);
|
||||
break;
|
||||
case DHCP_LEASE:
|
||||
long_opt();
|
||||
dhcp_state.lease = long_value;
|
||||
if (long_opt())
|
||||
dhcp_state.lease = long_value;
|
||||
break;
|
||||
case DHCP_REBIND:
|
||||
long_opt();
|
||||
dhcp_state.rebind = long_value;
|
||||
if (long_opt())
|
||||
dhcp_state.rebind = long_value;
|
||||
break;
|
||||
case DHCP_RENEWAL:
|
||||
long_opt();
|
||||
dhcp_state.renewal = long_value;
|
||||
if (long_opt())
|
||||
dhcp_state.renewal = long_value;
|
||||
break;
|
||||
case DHCP_END:
|
||||
break;
|
||||
@@ -376,13 +376,11 @@ void dhcp_start(void) __banked
|
||||
*tid++ = SFR_DATA_8;
|
||||
*tid = SFR_DATA_0;
|
||||
dhcp_state.state = DHCP_START;
|
||||
print_string("dhcp_start done\n");
|
||||
}
|
||||
|
||||
|
||||
void dhcp_stop(void) __banked
|
||||
{
|
||||
print_string("dhcp_stop called\n");
|
||||
uip_udp_remove(dhcp_state.conn);
|
||||
dhcp_state.state = DHCP_OFF;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
### 2M-PCB23-V3.2
|
||||
|
||||
## Brands
|
||||
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|
||||
|---|---|---|---|---|---|
|
||||
| keepLINK | KP-9000-9XHML-X | Yes| 2M-PCB23-V3.2 | 2M (Winbond 25Q) | |
|
||||
|
||||
The original web interface reports this board as hardware version V3.2
|
||||
(original firmware V100.9.25, January 2026).
|
||||
|
||||
## PCB
|
||||
|
||||
<img src="photos/2M-PCB23-V3.2-managed/2M-PCB23-V3.2-top.jpeg" width="300" />
|
||||
|
||||
## Compared to V3.1
|
||||
|
||||
The component placement matches [2M-PCB23-V3.1](2M-PCB23-V3_1.md): same
|
||||
positions for the flash (U8), the T7/T8/T9/T10 headers, the SFP cage and its
|
||||
LED, and the unpopulated U7/U9 footprints. Build with
|
||||
`MACHINE=KP_9000_9XHML_X_V3_2`, which uses the V3.1 machine definition and
|
||||
only differs in the reported name.
|
||||
|
||||
## Tested
|
||||
|
||||
Installed from the original firmware through its web interface with
|
||||
`installer/output/rtlplayground_oem_upgrade.bin`, then:
|
||||
|
||||
- RJ45 ports link at 2.5G; LEDs: orange at 2.5G, green below
|
||||
- SFP port: module detected with vendor/model/serial and DOM readings
|
||||
(temperature, Vcc, TX bias, TX/RX power), link up at 10G
|
||||
- factory MAC read from flash (0x1FC000)
|
||||
- reset button (GPIO48): held for more than 10 s it restores the default config
|
||||
|
||||
## Flash access
|
||||
|
||||
Reading the flash in-circuit with a SOIC-8 clip did not work: the chip ID
|
||||
comes back as `EF FF FF` (only the manufacturer byte is right) and reads
|
||||
return 0xff, the same as on a V3.1 board. The switch chip is powered through
|
||||
the clip and keeps driving the SPI lines. Make sure a way back is acceptable
|
||||
before installing, or hold the switch chip in reset while reading.
|
||||
@@ -0,0 +1,70 @@
|
||||
# F7008-2.5
|
||||
|
||||
Documentation for the unmanaged 8 + 1 switch sold as `7018-2.5G` by Guangnianwei
|
||||
(光年微), board marking `F7008-2.5`, PCB `F7008-2.5GPOE-V1.2`.
|
||||
|
||||
### Brands
|
||||
|
||||
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||
|-------|------|---------|-----|-------|----------|
|
||||
| Guangnianwei (光年微) | 7018-2.5G | No | F7008-2.5GPOE-V1.2 | W25Q64JVSSIQ | 8373N + 8224N |
|
||||
|
||||
### What works
|
||||
|
||||
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||
- SFP+ port with 1G/2.5G/10G modules
|
||||
- LEDs of the eight RJ45 ports
|
||||
|
||||
### Not verified
|
||||
|
||||
- The LED pads for the SFP+ cage are not mapped yet. The SFP+ lamps are left
|
||||
undriven, so an inserted module lights nothing.
|
||||
- The UART header footprint is present but unpopulated, and no boot log could be
|
||||
captured from it, so the baud rate is unknown. There are most likely
|
||||
unpopulated 0-Ohm resistors next to the header; bridging those should bring
|
||||
the console to life.
|
||||
|
||||
### Build target
|
||||
|
||||
```
|
||||
make MACHINE=F7008_2_5
|
||||
```
|
||||
|
||||
### LED wiring
|
||||
|
||||
Measured pad to lamp map (`led_mux` index -> lamp):
|
||||
|
||||
| Port | green lamp | yellow lamp |
|
||||
|------|-----------|-------------|
|
||||
| 1 | pad 0 | pad 1 |
|
||||
| 2 | pad 2 | pad 3 |
|
||||
| 3 | pad 4 | pad 5 |
|
||||
| 4 | pad 6 | pad 8 |
|
||||
| 5 | pad 9 | pad 10 |
|
||||
| 6 | pad 12 | pad 15 |
|
||||
| 7 | pad 18 | pad 21 |
|
||||
| 8 | pad 24 | pad 25 |
|
||||
|
||||
Pads 7, 11, 13, 14, 16, 17, 19, 20, 22, 23, 26 and 27 do not drive an RJ45 lamp.
|
||||
|
||||
The front panel is silkscreened `2.5G: Green / 10/100M: Yellow`, and the target
|
||||
follows it: the green lamp is on while the port is linked at 2.5G, the yellow
|
||||
lamp blinks while data is flowing.
|
||||
|
||||
### PCB overview
|
||||
|
||||
The board is marked `F7008-2.5GPOE-V1.2`.
|
||||
|
||||
Top side:
|
||||
|
||||
<img src="photos/F7008-2.5/PCB-top.jpg" width="600" />
|
||||
|
||||
Bottom side:
|
||||
|
||||
<img src="photos/F7008-2.5/PCB-bottom.jpg" width="600" />
|
||||
|
||||
### Hardware notes
|
||||
|
||||
- 4 x `RT4802SNE` magnetics
|
||||
- Unpopulated UART header footprint, next to the magnetics
|
||||
- Power input 12V 1A, 180 x 84 x 29 mm metal case
|
||||
@@ -0,0 +1,75 @@
|
||||
# Hasivo S1100WP-8GT-1SX-SE
|
||||
|
||||
RTL8373-based 8×2.5G PoE + 1×SFP switch.
|
||||
|
||||
### Label specifications
|
||||
|
||||
- **Manufacturer**: Hasivo
|
||||
- **Model**: S1100WP-8GT-1SX-SE
|
||||
- **Ports**:
|
||||
- 8 × RJ45: 10/100/1000/2500 Mbps with PoE
|
||||
- 1 × SFP: 1G / 2.5G / 10G
|
||||
- **Power input**: DC 52V 2.5A
|
||||
- **Stock firmware defaults**: IP 192.168.0.1, user/password `admin`/`admin`
|
||||
|
||||
### 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 copper port; combined link/act on the SFP port
|
||||
|
||||
### Photos
|
||||
|
||||
Front panel:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/front.jpg" width="600" />
|
||||
|
||||
Label:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/label.jpg" width="600" />
|
||||
|
||||
### PCB overview
|
||||
|
||||
Top side:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/pcb_top.jpg" width="600" />
|
||||
|
||||
Bottom side:
|
||||
|
||||
<img src="photos/HASIVO_S1100WP-8GT-1SX-SE/pcb_bottom.jpg" width="600" />
|
||||
|
||||
### Port layout
|
||||
|
||||
| Logical port | Physical port | Type |
|
||||
|--------------|---------------|--------|
|
||||
| 1-8 | 1-8 | Copper |
|
||||
| 9 | 9 | SFP |
|
||||
|
||||
### LED configuration
|
||||
|
||||
Copper ports use LED SET0, the SFP port uses LED SET1.
|
||||
|
||||
| SET | LED0 | LED2 |
|
||||
|------|-----------------------------------------------|------------------------------------------------------|
|
||||
| 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 | — |
|
||||
|
||||
### SFP GPIO assignments
|
||||
|
||||
| SFP (logical 9) | pin_detect (ModAbs) | pin_los | pin_tx_disable | SerDes | I2C SDA | I2C SCL |
|
||||
|-----------------|---------------------|---------|----------------|--------|-----------------|---------------------|
|
||||
| SFP | GPIO30_ACL_BIT3_EN | GPIO37 | GPIO_NA | SDS1 | GPIO39_I2C_SDA4 | GPIO40_I2C_SCL3_MDC1 |
|
||||
|
||||
### Machine configuration
|
||||
|
||||
- `reset_pin`: GPIO54_ACL_BIT2_EN
|
||||
- High LEDs (pads 27-29): mux = `LED_27 | LED_28_SYS | LED_29`, enable = `LED_28_SYS | LED_29`
|
||||
|
||||
### PoE
|
||||
|
||||
The 8 copper ports support PoE powered by a DC 52V 2.5A input. Power management is handled by two HS104PTI chipsets over I2C (GPIO47_I2C_SDA0, GPIO46_I2C_SCL0):
|
||||
|
||||
* Chip 1 (I2C address 0x1A): 2.5G Ports 1–4
|
||||
* Chip 2 (I2C address 0x2A): 2.5G Ports 5–8
|
||||
|
||||
Note: The current implementation does not yet support PoE management. Consequently, PoE currently operates in standalone mode without software control.
|
||||
@@ -0,0 +1,122 @@
|
||||
# ONT-S207CW-62TS-SE / Binardat 2G06-04210GSM / Binardat 2G06-04210GS
|
||||
|
||||
## Overview
|
||||
|
||||
ONT-S207CW-62TS-SE, Binardat 2G06-04210GSM (managed), and Binardat 2G06-04210GS (unmanaged) are **switches with identical hardware**:
|
||||
- **CPU:** RTL8372N (confirmed via serial: "Detecting CPU: RTL8372N")
|
||||
- **Flash:** GD25Q128E (16MB)
|
||||
- **Ports:** 4x 2.5G RJ45 + 2x 10G SFP+
|
||||
- **Console:** 115200 baud (RTLPlayground firmware) / 9600 baud (stock firmware)
|
||||
|
||||
**Note:** These devices are **RTL8372N-based** with **LAN ports mounted upside-down on the PCB**, requiring a custom configuration. The `MACHINE_ONT_S207CW_62TS_SE` definition uses a **custom configuration** with:
|
||||
- Corrected port mapping (physical ports 1-4 = RJ45, 5-6 = SFP)
|
||||
- Optimized LED sets for different port wiring (RJ45 Ports 1-2 have reversed LED wiring)
|
||||
- Custom LED mux configuration
|
||||
|
||||
## Device Photos
|
||||
|
||||
### Binardat 2G06-04210GSM
|
||||
|
||||
**Front View:**
|
||||
<img src="photos/ONT-S207CW-Binardat-2G06-04210GSM/binardat-2g06-04210gsm-front.jpg" width="400" />
|
||||
|
||||
**Back View:**
|
||||
<img src="photos/ONT-S207CW-Binardat-2G06-04210GSM/binardat-2g06-04210gsm-back.jpg" width="400" />
|
||||
|
||||
**PCB View:**
|
||||
<img src="photos/ONT-S207CW-Binardat-2G06-04210GSM/binardat-2g06-04210gsm-pcb.jpg" width="400" />
|
||||
|
||||
*Photos courtesy of [andreas5232](https://github.com/andreas5232) from [emesix/ONT-S207CW-62TS-SE#1](https://github.com/emesix/ONT-S207CW-62TS-SE/issues/1)*
|
||||
|
||||
## Hardware Specification
|
||||
|
||||
| Feature | Value |
|
||||
|---|---|
|
||||
| **CPU** | RTL8372N |
|
||||
| **Flash** | GD25Q128E (16MB) |
|
||||
| **RAM** | Integrated in RTL8372N |
|
||||
| **RJ45 Ports** | 4x 2.5GBase-T (Ports 1-4) |
|
||||
| **SFP+ Ports** | 2x 10G (Ports 5-6) |
|
||||
| **Console** | UART (115200 baud for RTLPlayground, 9600 baud for stock) |
|
||||
| **Stock Web UI IP** | 192.168.2.1 |
|
||||
| **Loader Mode IP** | 192.168.10.247 |
|
||||
|
||||
## Port Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
|
||||
│ │RJ45 │ │RJ45 │ │RJ45 │ │RJ45 │ │SFP+ │ │SFP+ │ │
|
||||
│ │ 1 │ │ 2 │ │ 3 │ │ 4 │ │ 5 │ │ 6 │ │
|
||||
│ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ │
|
||||
│ │
|
||||
│ [System LEDs] │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## LED Behavior
|
||||
|
||||
### RJ45 Ports (Physical 1-4)
|
||||
|
||||
| LED Color | Speed |
|
||||
|---|---|
|
||||
| **Green** | 2.5G |
|
||||
| **Orange** | 1G / 100M / 10M |
|
||||
| **Off** | No link |
|
||||
|
||||
### SFP+ Ports (Physical 5-6)
|
||||
|
||||
| LED Color | Speed |
|
||||
|---|---|
|
||||
| **Green** | 10G |
|
||||
| **Orange** | 2.5G / 1G |
|
||||
| **Off** | No link / No SFP module |
|
||||
|
||||
## Port to Logical Mapping
|
||||
|
||||
Custom mapping for ONT-S207CW-62TS-SE:
|
||||
|
||||
| Physical Port | Logical Port | Type | LED Set |
|
||||
|---|---|---|---|
|
||||
| 1 | 7 | RJ45 | 2 |
|
||||
| 2 | 6 | RJ45 | 2 |
|
||||
| 3 | 5 | RJ45 | 0 |
|
||||
| 4 | 4 | RJ45 | 0 |
|
||||
| 5 | 3 | SFP+ (SDS0) | 3 |
|
||||
| 6 | 8 | SFP+ (SDS1) | 3 |
|
||||
|
||||
**Note:** Ports 1-2 (RJ45) have reversed LED wiring and use LED-Set 2. SFP Ports 5-6 use LED-Set 3 to account for wiring differences.
|
||||
|
||||
## Flashing Instructions
|
||||
|
||||
See the [README.md](../../README.md) for general flashing instructions.
|
||||
|
||||
## Stock Firmware Information
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| **Default IP** | 192.168.2.1 (ONT) / 192.168.10.247 (Loader Mode) |
|
||||
| **Default Login** | admin/admin (may vary by OEM) |
|
||||
| **Console Baud** | 9600 (stock) / 115200 (RTLPlayground) |
|
||||
| **CPU String** | "RTL8372N" |
|
||||
| **Loader Mode IP** | 192.168.10.247 |
|
||||
|
||||
## Configuration Details
|
||||
|
||||
- **CPU:** RTL8372N
|
||||
- **SFP:** SDS0 on logical port 3 (GPIO37), SDS1 on logical port 8 (GPIO38)
|
||||
- **Port Mapping:** Physical 1-4 → Logical 7-4, Physical 5-6 → Logical 3,8
|
||||
- **LED Wiring:** RJ45 Ports 1-2 and SFP Port 6 have reversed LED pins (orange/green swapped)
|
||||
- **LED Sets:** Set 0 for RJ45 Ports 3-4, Set 1 unused, Set 2 for RJ45 Ports 1-2, Set 3 for SFP Ports 5-6
|
||||
|
||||
## Notes
|
||||
|
||||
- ONT-S207CW-62TS-SE, Binardat 2G06-04210GSM (managed), and Binardat 2G06-04210GS (unmanaged) are **RTL8372N-based** with **LAN ports mounted upside-down on the PCB**
|
||||
- Web UI shows correct physical port order (1-2-3-4 for RJ45, 5-6 for SFP)
|
||||
- Loader Mode always remains accessible at `192.168.10.247` for recovery
|
||||
- Serial console: 9600 baud (stock) → 115200 baud (RTLPlayground)
|
||||
|
||||
## References
|
||||
|
||||
- [GitHub Issue: emesix/ONT-S207CW-62TS-SE#1](https://github.com/emesix/ONT-S207CW-62TS-SE/issues/1) - Original photos and discussion
|
||||
- [PR: logicog/RTLPlayground#465](https://github.com/logicog/RTLPlayground/pull/465) - Feedback and improvements
|
||||
@@ -0,0 +1,53 @@
|
||||
# IG108
|
||||
|
||||
Following is documentation for unmanaged switch marked as `IG108`.
|
||||
|
||||
Original software is running UART on 9600 baud rate.
|
||||
|
||||
Using SPI clamp in-board is the only method for initial installation.
|
||||
|
||||
### Brands
|
||||
|
||||
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|
||||
|---------|------------|---------|------------|-------------|---------------|
|
||||
| Goalake | IG108 | No | PB-2132 | cFeon Q32A | 8373N + 8224N |
|
||||
| Netcore | GS9 | No | PB-2132 | cFeon Q32A | 8373N + 8224N |
|
||||
|
||||
### What works
|
||||
|
||||
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
|
||||
- SFP port with 1G/2.5G/10G modules
|
||||
- LEDs
|
||||
|
||||
### PCB overview
|
||||
|
||||
**Board markings**
|
||||
|
||||
- Top silkscreen: PB-2132
|
||||
|
||||
Front Goalake:
|
||||
|
||||
<img src="photos/PB-2132/case.jpg" width="600" />
|
||||
|
||||
Label Goalake:
|
||||
|
||||
<img src="photos/PB-2132/label.jpg" width="600" />
|
||||
|
||||
Top side:
|
||||
|
||||
<img src="photos/PB-2132/PCB-top.jpg" width="600" />
|
||||
|
||||
Bottom:
|
||||
|
||||
<img src="photos/PB-2132/PCB-bottom.jpg" width="600" />
|
||||
|
||||
### Serial console
|
||||
|
||||
The PCB has unpopulated through-holes near the SFP Port, with description of each pin, works out of the box.
|
||||
|
||||
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
|
||||
|
||||
### Power supply
|
||||
|
||||
Input power is delivered via barell plug, `12V 1A` adapter was provided.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# SWTG018AS-A V2.0
|
||||
## Brands
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|--------|------------------|-------|------------------|-----------------|---------------|
|
||||
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
|
||||
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
|
||||
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|
||||
|---------|------------------|-------|------------------|-----------------|---------------|
|
||||
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
|
||||
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
|
||||
| GoodTop | GT-ST018M | Yes | SWTG018AS-A V2.0 | ? | 8273N + 8224N |
|
||||
|
||||
|
||||
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
|
||||
|
||||
|
After Width: | Height: | Size: 480 KiB |
|
After Width: | Height: | Size: 519 KiB |
|
After Width: | Height: | Size: 529 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 220 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 546 KiB |
|
After Width: | Height: | Size: 478 KiB |
|
After Width: | Height: | Size: 639 KiB |
|
After Width: | Height: | Size: 907 KiB |
|
After Width: | Height: | Size: 923 KiB |
|
After Width: | Height: | Size: 290 KiB |
|
After Width: | Height: | Size: 360 KiB |
@@ -0,0 +1,79 @@
|
||||
# The health command
|
||||
|
||||
`health` prints a one-page snapshot of the firmware's vital signs on the
|
||||
serial console. It exists for the situations where the switch misbehaves and
|
||||
every probe from the network measures the network instead of the device: the
|
||||
dump is taken from inside, costs one command, and works while HTTP does not.
|
||||
|
||||
```
|
||||
> health
|
||||
up 0000001f ticks 0x00001f4c loops 0x000016da rx 0x024e
|
||||
link max 01 slow 0x0000
|
||||
sfp max 74 slow 0x0001
|
||||
rx max 00 slow 0x0000
|
||||
tx max 00 slow 0x0000
|
||||
stp max 04 slow 0x0001
|
||||
cmd max 02 slow 0x0001
|
||||
sp 80 untouched 62
|
||||
tcp st 00 tmr 00 rtx 00 rto 00 len 0x0000 mss 0x05b4
|
||||
lport 0x0000 rport 0x0000 rip 0x0000 0x0000
|
||||
httpd left 0x0000 entry 00 stp 01 mvlan 0x0002
|
||||
```
|
||||
|
||||
The instrumentation is not part of a default build. It costs about 1.1 kB
|
||||
of bank 2, a few bytes of xdata and seven banked calls per main-loop pass,
|
||||
which is nothing a user needs unless they are chasing a problem, so it is
|
||||
switched on at build time:
|
||||
|
||||
```
|
||||
make MACHINE=SWTGW218AS HEALTH=1
|
||||
```
|
||||
|
||||
Without it the hooks compile to nothing and `health` is not a command.
|
||||
|
||||
All figures are raw hex. The counters are cumulative: take two dumps a known
|
||||
time apart and the differences give the rates.
|
||||
|
||||
## The first line
|
||||
|
||||
`up` is the seconds counter, `ticks` the system tick (200 per second),
|
||||
`loops` the number of main-loop passes and `rx` the frames handle_rx has
|
||||
taken off the NIC. A healthy loop completes one pass per tick, so the
|
||||
difference in `loops` tracks the difference in `ticks`; a loop that falls
|
||||
behind is being held up by one of the phases below. The `rx` rate separates
|
||||
a flooded CPU port from a stalled loop, which look identical from outside.
|
||||
|
||||
## Phases
|
||||
|
||||
Each line is one section of the main loop: the link poll, SFP handling,
|
||||
frame reception, TCP transmission, the STP timers and the command dispatch.
|
||||
`max` is the worst time that section has taken, in ticks of 5 ms; `slow`
|
||||
counts the passes that took two ticks or more. A misbehaving subsystem
|
||||
names itself here, which is the difference between knowing that the loop is
|
||||
slow and knowing why.
|
||||
|
||||
A dump of its own output takes the console some milliseconds, so running
|
||||
`health` repeatedly increments the `cmd` counters by itself. That is the
|
||||
instrument observing itself, not a fault.
|
||||
|
||||
## Stack
|
||||
|
||||
At boot the free stack area is painted with a pattern. `sp` is the live
|
||||
stack pointer; `untouched` counts the painted bytes still intact at the top,
|
||||
which is the closest thing to a high-water mark this hardware offers. A
|
||||
shrinking `untouched` across dumps means something is reaching deeper than
|
||||
anything before it.
|
||||
|
||||
## The TCP slot
|
||||
|
||||
The connection table is printed whole, one slot per pair of lines: TCP
|
||||
state (3 is ESTABLISHED, 0 closed), retransmission timer and counter, bytes
|
||||
in flight, negotiated MSS, then the ports and the peer address. With a
|
||||
single slot serving the entire web interface, one glance answers the
|
||||
question every management outage starts with: who is holding it. A slot
|
||||
showing state 3 with nothing in flight and a peer that no longer answers is
|
||||
a connection whose owner went away.
|
||||
|
||||
`httpd left` and `entry` describe the file transfer the web server believes
|
||||
it is in the middle of, and the trailing flags show whether STP is running
|
||||
and which VLAN carries management.
|
||||
@@ -0,0 +1,572 @@
|
||||
# LEDs HOWTO using firmware function tracing
|
||||
|
||||
This is a tutorial to show how to figure out the LED configuration for
|
||||
unmanaged switches (on managed ones one can just print out the registers
|
||||
from the command line) without using an I2C port on the device together
|
||||
an I2C-capable microcontroller. You will only need to have a SOIC clamp
|
||||
and will have to run ghidra to do a bit of reversing.
|
||||
|
||||
The additional advantage of this method is that it not only gives the LED
|
||||
configuration but also the full PHY configuration and SDS configuration e.g.
|
||||
in case of additional PHYs being used on the device.
|
||||
|
||||
We will use the ZoeRax HG0402XG V1.1 as an example device.
|
||||
|
||||
The first step is to read out the flash with a SOIC clamp.
|
||||
Save the image as
|
||||
`zoerax_hg0402xg.bin`
|
||||
|
||||
The next step is to use a decompiler such as ghidra to identify the
|
||||
functions used to write or read registers, SDS or to the PHY.
|
||||
|
||||
<img src="images/ghidra_open.png" width="300" />
|
||||
|
||||
First, load the code in BANK0 into ghidra. The type of code is
|
||||
8051 default big-endian. The code starts at offset 0x0002 in the file
|
||||
and has length 0x3ffd
|
||||
|
||||
<img src="images/ghidra_add_block.png" width="300" />
|
||||
Add BANK1 into ghidra by using File->Add to program...
|
||||
and add the code starting at 0x4000 in `zoerax_hg0402xg.bin` with length
|
||||
0xc000. Repeat for BANK2 (starts at 0x10000) and BANK3 (starts at 0x1c0000).
|
||||
They both have length 0xc000.
|
||||
|
||||
<img src="images/ghidra_search_read_reg.png" width="300" />
|
||||
|
||||
Now, find the read_reg function. An example of the read-register function
|
||||
is given below. Note the critical bit, namely the execution of the
|
||||
read-function of an ASIC register via an SFR:
|
||||
```
|
||||
CODE1::4dc9 75 a0 01 MOV SFR_EXEC_GO,#0x1
|
||||
```
|
||||
|
||||
This sequence of bytes is very specific. Replace 0x01 with 0x03 and you have
|
||||
the regster write SFR, 0x05 reads the SerDes, 0x07 writes it. 0x09 reads
|
||||
from the PHY and 0x0b writes to it.
|
||||
|
||||
|
||||
```
|
||||
**************************************************************
|
||||
* FUNCTION *
|
||||
**************************************************************
|
||||
undefined reg_read()
|
||||
undefined <UNASSIGNED> <RETURN>
|
||||
reg_read
|
||||
CODE1::4da9 ab 07 MOV R3,BANK0_R7 = ??
|
||||
CODE1::4dab aa 06 MOV R2,BANK0_R6 = ??
|
||||
CODE1::4dad e4 CLR A
|
||||
CODE1::4dae ff MOV R7,A
|
||||
CODE1::4daf fe MOV R6,A
|
||||
CODE1::4db0 fd MOV R5,A
|
||||
CODE1::4db1 fc MOV R4,A
|
||||
CODE1::4db2 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4db5 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4db8 e4 CLR A
|
||||
CODE1::4db9 ff MOV R7,A
|
||||
CODE1::4dba fe MOV R6,A
|
||||
CODE1::4dbb fd MOV R5,A
|
||||
CODE1::4dbc fc MOV R4,A
|
||||
CODE1::4dbd 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4dc0 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4dc3 ea MOV A,R2
|
||||
CODE1::4dc4 f5 a2 MOV SFR_A_ADDRH,A = ??
|
||||
CODE1::4dc6 eb MOV A,R3
|
||||
CODE1::4dc7 f5 a3 MOV SFR_A_ADDRL,A = ??
|
||||
CODE1::4dc9 75 a0 01 MOV SFR_EXEC_GO,#0x1 <<<<<<<< Executes READ REG
|
||||
LAB_CODE1__4dcc XREF[1]: CODE1::4dcf(j)
|
||||
CODE1::4dcc af a1 MOV R7,SFR_EXEC_STATUS = ??
|
||||
CODE1::4dce ef MOV A,R7
|
||||
CODE1::4dcf 70 fb JNZ LAB_CODE1__4dcc
|
||||
CODE1::4dd1 af a4 MOV R7,DAT_SFR_a4 = ??
|
||||
CODE1::4dd3 fc MOV R4,A
|
||||
CODE1::4dd4 fd MOV R5,A
|
||||
CODE1::4dd5 fe MOV R6,A
|
||||
CODE1::4dd6 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4dd9 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4ddc 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4ddf 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||
CODE1::4de2 c0 00 PUSH BANK0_R0
|
||||
CODE1::4de4 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4de7 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||
CODE1::4dea 78 18 MOV R0,#0x18
|
||||
CODE1::4dec 12 05 86 LCALL FUN_CODE_0586 undefined FUN_CODE_0586()
|
||||
CODE1::4def d0 00 POP BANK0_R0
|
||||
CODE1::4df1 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||
CODE1::4df4 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4df7 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4dfa af a5 MOV R7,DAT_SFR_a5 = ??
|
||||
CODE1::4dfc e4 CLR A
|
||||
CODE1::4dfd fc MOV R4,A
|
||||
CODE1::4dfe fd MOV R5,A
|
||||
CODE1::4dff fe MOV R6,A
|
||||
CODE1::4e00 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4e03 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4e06 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e09 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||
CODE1::4e0c c0 00 PUSH BANK0_R0
|
||||
CODE1::4e0e 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4e11 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||
CODE1::4e14 78 10 MOV R0,#0x10
|
||||
CODE1::4e16 12 05 86 LCALL FUN_CODE_0586 undefined FUN_CODE_0586()
|
||||
CODE1::4e19 d0 00 POP BANK0_R0
|
||||
CODE1::4e1b 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||
CODE1::4e1e 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e21 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4e24 af a6 MOV R7,DAT_SFR_a6 = ??
|
||||
CODE1::4e26 e4 CLR A
|
||||
CODE1::4e27 fc MOV R4,A
|
||||
CODE1::4e28 fd MOV R5,A
|
||||
CODE1::4e29 fe MOV R6,A
|
||||
CODE1::4e2a 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4e2d 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4e30 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e33 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||
CODE1::4e36 c0 00 PUSH BANK0_R0
|
||||
CODE1::4e38 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4e3b 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||
CODE1::4e3e 78 08 MOV R0,#0x8
|
||||
CODE1::4e40 12 05 86 LCALL FUN_CODE_0586 undefined FUN_CODE_0586()
|
||||
CODE1::4e43 d0 00 POP BANK0_R0
|
||||
CODE1::4e45 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||
CODE1::4e48 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e4b 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4e4e af a7 MOV R7,DAT_SFR_a7 = ??
|
||||
CODE1::4e50 e4 CLR A
|
||||
CODE1::4e51 fc MOV R4,A
|
||||
CODE1::4e52 fd MOV R5,A
|
||||
CODE1::4e53 fe MOV R6,A
|
||||
CODE1::4e54 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4e57 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4e5a 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e5d 12 05 dd LCALL read_xmem_32_b undefined read_xmem_32_b()
|
||||
CODE1::4e60 90 00 c9 MOV DPTR,#0xc9
|
||||
CODE1::4e63 12 05 f9 LCALL FUN_CODE_05f9 undefined FUN_CODE_05f9()
|
||||
CODE1::4e66 12 05 48 LCALL FUN_CODE_0548 undefined FUN_CODE_0548()
|
||||
CODE1::4e69 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e6c 12 06 15 LCALL FUN_CODE_0615 undefined FUN_CODE_0615()
|
||||
CODE1::4e6f 90 00 c5 MOV DPTR,#0xc5
|
||||
CODE1::4e72 02 05 dd LJMP read_xmem_32_b undefined read_xmem_32_b()
|
||||
-- Flow Override: CALL_RETURN (CALL_TERMINATOR)
|
||||
|
||||
```
|
||||
|
||||
INSERT ghidra_search_read_reg.png
|
||||
|
||||
Identify all the read and write function to the HW of the SoC using the find
|
||||
in memory function.
|
||||
|
||||
The next task is to adapt the intercept routines in a special assembler
|
||||
file. Don't worry, you do not need to understand assembler to do this.
|
||||
|
||||
```
|
||||
; Assembler file to intercept register writes/reads and PHY writes/reads
|
||||
; assemble with as31
|
||||
; Compile with
|
||||
; as31 -Fbyte -Orwintercept_zoerax_hg0402xg.hex rwintercept_zoerax_hg0402xg.asm
|
||||
; ./injector zoerax_hg0402xg.bin RTLPlayground/rwintercept_zoerax_hg0402xg.hex zoerax_hg0402xg_patched.bin
|
||||
; Start at 0x3b00, where there is always some space in BANK 0
|
||||
.equ valptr, 0x199
|
||||
|
||||
|
||||
.equ SFR_DATA_0, 0xa7
|
||||
.equ SFR_DATA_8, 0xa6
|
||||
.equ SFR_DATA_16, 0xa5
|
||||
.equ SFR_DATA_24, 0xa4
|
||||
|
||||
; Intercept Register Write
|
||||
.org 0x4d62
|
||||
lcall reg_write
|
||||
nop
|
||||
|
||||
; Intercept Register Read
|
||||
.org 0x4dad
|
||||
lcall reg_read_head
|
||||
.org 0x4e6f
|
||||
lcall reg_read_tail
|
||||
|
||||
; Intercept PHY write
|
||||
.org 0x522c
|
||||
lcall phy_write
|
||||
|
||||
; Intercept PHY read
|
||||
.org 0x526f
|
||||
lcall phy_read_head
|
||||
.org 0x5295
|
||||
ljmp phy_read_tail
|
||||
|
||||
; Intercept SDS write
|
||||
.org 0x503c
|
||||
lcall sds_write
|
||||
nop
|
||||
|
||||
; Intercept SDS read
|
||||
.org 0x5061
|
||||
lcall sds_read_head
|
||||
nop
|
||||
.org 0x507b
|
||||
ljmp sds_read_tail
|
||||
|
||||
;
|
||||
; BEGIN actual code at unused end of BANK0
|
||||
;
|
||||
.org 0x3b00
|
||||
|
||||
;
|
||||
; print the address of a register write. The address is in R6/R7. A and r4 can be scratched
|
||||
;
|
||||
reg_write:
|
||||
mov a, #'R'
|
||||
acall putc
|
||||
|
||||
mov a, r6
|
||||
acall wbyte
|
||||
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, #'-'
|
||||
acall putc
|
||||
|
||||
mov dptr, #valptr
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #valptr + 1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #valptr + 2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #valptr + 3
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov a, r7
|
||||
mov r5, a
|
||||
mov a, r6
|
||||
mov r4, a
|
||||
ret
|
||||
[...]
|
||||
```
|
||||
|
||||
The full assembler file can be found here: XXXXXXXXXX
|
||||
|
||||
|
||||
Once you have assembled the code, inject the bytes into the existing image,
|
||||
creating a patched version:
|
||||
```
|
||||
$ as31 -Fbyte -Orwintercept_zoerax_hg0402xg.hex rwintercept_zoerax_hg0402xg.asm
|
||||
Begin Pass #1
|
||||
Begin Pass #2
|
||||
./injector zoerax_hg0402xg.bin rwintercept_zoerax_hg0402xg.hex zoerax_hg0402xg_patched.bin
|
||||
Input file size: 1048576
|
||||
Bytes read:: 1048576
|
||||
Patched 417 bytes.
|
||||
```
|
||||
|
||||
Now flash `zoerax_hg0402xg_patched.bin` onto device.
|
||||
|
||||
Connect a serial adapter and plug in power. You will see:
|
||||
|
||||
```
|
||||
$ picocom -b 9600 /dev/ttyUSB0
|
||||
picocom v3.1
|
||||
|
||||
port is : /dev/ttyUSB0
|
||||
flowcontrol : none
|
||||
baudrate is : 9600
|
||||
parity is : none
|
||||
databits are : 8
|
||||
stopbits are : 1
|
||||
escape is : C-a
|
||||
local echo is : no
|
||||
noinit is : no
|
||||
noreset is : no
|
||||
hangup is : no
|
||||
nolock is : no
|
||||
send_cmd is : sz -vv
|
||||
receive_cmd is : rz -vv -E
|
||||
imap is :
|
||||
omap is :
|
||||
emap is : crcrlf,delbs,
|
||||
logfile is : none
|
||||
initstring : none
|
||||
exit_after is : not set
|
||||
exit is : no
|
||||
|
||||
Type [C-a] [C-h] to see available commands
|
||||
Terminal ready
|
||||
[The printout only starts once the serial peripherial has been set up. Initially its timing is off:]
|
||||
�.Ӛ�҂���������30-00005555 r6330:00005555 R6330-00005515 [RTL837X_REG_SMI_MAC_TYPE]
|
||||
[RTL837X_REG_SMI_PORT_POLLING: ]
|
||||
r6334:00000000 R6334-000000f0
|
||||
r6454:00000000 R6454-00007000
|
||||
|
||||
[Read SoC-Revision]
|
||||
r000c:00200000 R000c-002a0000 r000c:202a6818 r000c:202a6818 R000c-20206818
|
||||
p001e.000d:ffff R02f8-0000ffff R02f4-0000fffa P000001.1e00000d:fffa p001e.000d:ffff p001e.000d:ffff
|
||||
R02f8-0000ffff R02f4-0000fff0 P000001.1e00000d:fff0
|
||||
|
||||
[RTL837X_REG_LED_MODE being configured:]
|
||||
r6520:0021fdb0 R6520-0021e7b0 r6520:0021e7b0 R6520-0021e6b0
|
||||
|
||||
[RLDP Leds configured via RTL837X_REG_LED_RLDP_X:]
|
||||
r65f8:00000018 R65f8-0000001b R65fc-fffff000 r6600:00000000 R6600-0000000f
|
||||
|
||||
[RTL837X_REG_LED_GLB_IO_EN: ]
|
||||
r65dc:5fffff00 R65dc-7fffff00 r65dc:7fffff00 R65dc-77ffff00
|
||||
|
||||
[RTL837X_PIN_MUX_0, makes serial go out of sync:]
|
||||
r7f8c:30000000 R7f8c-30000000 r7f8c:300��.Ӛ�҂���������30-00005555
|
||||
|
||||
r6330:00005555 R6330-00005515 r6334:00000000 R6334-000000f0
|
||||
|
||||
r6454:00000000 R6454-00007000
|
||||
|
||||
[Read SoC-Revision (again)]
|
||||
r000c:00200000 R000c-002a0000 r000c:202a6818 r000c:202a6818 R000c-20206818
|
||||
p001e.000d:ffff R02f8-0000ffff R02f4-0000fffa P000001.1e00000d:fffa p001e.000d:ffff p001e.000d:ffff
|
||||
R02f8-0000ffff R02f4-0000fff0
|
||||
P000001.1e00000d:fff0
|
||||
|
||||
#### LED configuration ########
|
||||
[RTL837X_REG_LED_MODE being configured (final):]
|
||||
r6520:0021fdb0 R6520-0021e7b0 r6520:0021e7b0 R6520-0021e6b0
|
||||
|
||||
[More RTL837X_REG_LED_RLDP]
|
||||
r65f8:00000018 R65f8-0000001b R65fc-fffff000 r6600:00000000 R6600-0000000f
|
||||
|
||||
[RTL837X_REG_LED_GLB_IO_EN]
|
||||
r65dc:5fffff00 R65dc-7fffff00 r65dc:7fffff00 R65dc-77ffff00
|
||||
|
||||
[RTL837X_PIN_MUX_0
|
||||
r7f8c:30000000 R7f8c-30000000 r7f8c:30000000 R7f8c-38000000
|
||||
|
||||
[RTL837X_LED_PORT_SET_SEL]
|
||||
r654c:00000000 R654c-00010000
|
||||
|
||||
[RTL837X_REG_LED1_0_SET0]
|
||||
R6548-00000141
|
||||
|
||||
[RTL837X_REG_LED3_2_SET0]
|
||||
r6544:01411000 R6544-01410174
|
||||
|
||||
[RTL837X_REG_LED1_0_SET1]
|
||||
r6540:00440070 R6540-0044017f
|
||||
|
||||
[RTL837X_REG_LED3_0_SET1]
|
||||
r6528:00000000 R6528-000f0000
|
||||
|
||||
[SDS 0 being configure:]
|
||||
r7b20:00000bff R7b20-000003ff r7b20:000003ff R7b20-000003fa r7b20:000003fa R7b20-000003fa
|
||||
Q002110:4480 Q002113:0400 Q002118:6d02 Q00211b:424e Q00211d:0002 Q00361c:1390
|
||||
Q003614:003f Q003610:0200 Q002e04:0080 Q002e06:0408 Q002e07:020d Q002e09:0601
|
||||
Q002e0b:222c Q002e0c:a217 Q002e0d:fe40 Q002e15:f5c1 Q002e16:0443 Q002e1d:abb0
|
||||
Q000612:5078 Q000706:9401 Q000708:9401 Q00070a:9401 Q00070c:9401 Q001f0b:0003
|
||||
Q000603:c45c Q00061f:2100 q001f0b:0003 Q001f0b:000f q002000:0000 Q002000:0030
|
||||
q002000:0030 Q002000:0010 q002000:0010 Q002000:0050 q002000:0050 Q002000:00d0
|
||||
q002000:00d0 Q002000:0cd0 q002000:0cd0 Q002000:04d0 q002000:04d0 Q002000:04d0
|
||||
q002000:04d0 Q002000:0cd0 q002000:0cd0 Q002000:00d0 q002000:00d0 Q002000:00d0
|
||||
q002000:00d0 Q002000:0050 q002000:0050 Q002000:0010 q002000:0010 Q002000:0010
|
||||
q002000:0010 Q002000:0030 q002000:0030 Q002000:0000 q001f00:0000 Q001f00:000b
|
||||
q001f00:000b Q001f00:0000
|
||||
|
||||
[SDS 1 being configured]
|
||||
r7b20:000003fa R7b20-000003fa r7b20:000003fa R7b20-0000035a r7b20:0000035a R7b20-0000035a
|
||||
Q012110:4480 Q012113:0400 Q012118:6d02 Q01211b:424e Q01211d:0002 Q01361c:1390
|
||||
Q013614:003f Q013610:0200 Q012e04:0080 Q012e06:0408 Q012e07:020d Q012e09:0601
|
||||
Q012e0b:222c Q012e0c:a217 Q012e0d:fe40 Q012e15:f5c1 Q012e16:0443 Q012e1d:abb0
|
||||
Q010612:5078 Q010706:9401 Q010708:9401 Q01070a:9401 Q01070c:9401 Q011f0b:0003
|
||||
Q010603:c45c Q01061f:2100 q011f0b:0003 Q011f0b:000f q012000:0000 Q012000:0030
|
||||
q012000:0030 Q012000:0010 q012000:0010 Q012000:0050 q012000:0050 Q012000:00d0
|
||||
q012000:00d0 Q012000:0cd0 q012000:0cd0 Q012000:04d0 q012000:04d0 Q012000:04d0
|
||||
q012000:04d0 Q012000:0cd0 q012000:0cd0 Q012000:00d0 q012000:00d0 Q012000:00d0
|
||||
q012000:00d0 Q012000:0050 q012000:0050 Q012000:0010 q012000:0010 Q012000:0010
|
||||
q012000:0010 Q012000:0030 q012000:0030 Q012000:0000 q011f00:0000 Q011f00:000b
|
||||
q011f00:000b Q011f00:0000 q012100:4902 Q012100:4906 q013605:0000 Q013605:4000
|
||||
Q011f02:001f q011f15:0096 q002100:4902 Q002100:4906 q003605:0000 Q003605:4000
|
||||
Q001f02:001f q001f15:00a6
|
||||
|
||||
r0a90:000000f3 R0a90-000000fc P0000f0.1f00a610:2858 r5fd4:0002914a
|
||||
R5fd4-001a914a r1538:00000e33 R1538-00000e37 r1538:00000e37 R1538-00000e37
|
||||
r1538:00000e37 R1538-00000f37 r1638:00000e33 R1638-00000e37 r1638:00000e37
|
||||
R1638-00000e37 r1638:00000e37 R1638-00000f37 r1738:00000e33 R1738-00000e37
|
||||
r1738:00000e37 R1738-00000e37 r1738:00000e37 R1738-00000f37 r1838:00000e33
|
||||
R1838-00000e37 r1838:00000e37 R1838-00000e37 r1838:00000e37 R1838-00000f37
|
||||
r1938:00000e33 R1938-00000e37 r1938:00000e37 R1938-00000e37 r1938:00000e37
|
||||
R1938-00000f37 r1a38:00000e33 R1a38-00000e37 r1a38:00000e37 R1a38-00000e37
|
||||
r1a38:00000e37 R1a38-00000f37 r0b7c:000000d8 R0b7c-000000f8 R7124-00001050
|
||||
R7128-00001050 R712c-00001050 R7130-00001050 R7134-00001050 R7138-00001050
|
||||
R713c-00001050 R7140-00001050 R7144-00001050 R7148-00001050 r6040:00000030
|
||||
R6040-00000031 p041f.a436:8195 P000010.1f00a436:0005 p041f.a438:02d4
|
||||
P000010.1f00a436:801e p041f.a438:0000 p041f.b820:0000 P000010.1f00b820:0010
|
||||
p041f.b800:00c0 p041f.a436:801e P000010.1f00a436:8023 p041f.a438:0000
|
||||
P000010.1f00a438:1802 p041f.a436:8025
|
||||
|
||||
[PHY with ID 5 being patched] P000010.1f00a436:b82e p041f.a438:0000
|
||||
P000010.1f00a438:0001 p041f.b820:0010 P000010.1f00b820:0090
|
||||
P000010.1f00a436:a016 P000010.1f00a438:0000 P000010.1f00a436:a012
|
||||
P000010.1f00a438:0000 P000010.1f00a436:a014 P000010.1f00a438:1800
|
||||
P000010.1f00a438:8010 P000010.1f00a438:1800 P000010.1f00a438:8013
|
||||
P000010.1f00a438:1800 P000010.1f00a438:8026 P000010.1f00a438:1800
|
||||
P000010.1f00a438:802a P000010.1f00a438:1800 P000010.1f00a438:802e
|
||||
P000010.1f00a438:1800 P000010.1f00a438:802e P000010.1f00a438:1800
|
||||
P000010.1f00a438:802e P000010.1f00a438:1800 P000010.1f00a438:802e
|
||||
...
|
||||
```
|
||||
Where:
|
||||
```
|
||||
r: read-reg
|
||||
R: write-reg
|
||||
q: read SDS
|
||||
Q: write SDS
|
||||
p: read PHY
|
||||
P: write SDS
|
||||
```
|
||||
|
||||
The LED configuration has been marked above. We now write exactly those registers
|
||||
into the registers of `rtlplayground.c` on startup:
|
||||
|
||||
```
|
||||
[...]
|
||||
set_sys_led_state(SYS_LED_ON);
|
||||
|
||||
// [RTL837X_REG_LED_MODE being configured (final):]
|
||||
// r6520:0021fdb0 R6520-0021e7b0 r6520:0021e7b0 R6520-0021e6b0
|
||||
REG_SET(RTL837X_REG_LED_MODE, 0x0021e6b0);
|
||||
|
||||
// [More RTL837X_REG_LED_RLDP]
|
||||
// r65f8:00000018 R65f8-0000001b R65fc-fffff000 r6600:00000000 R6600-0000000f
|
||||
REG_SET(0x65f8, 0x0000001b);
|
||||
REG_SET(0x65fc, 0xfffff000);
|
||||
REG_SET(0x6600, 0x0000000f);
|
||||
|
||||
// [RTL837X_REG_LED_GLB_IO_EN]
|
||||
// r65dc:5fffff00 R65dc-7fffff00 r65dc:7fffff00 R65dc-77ffff00
|
||||
REG_SET(0x65dc, 0x77ffff00);
|
||||
|
||||
// [RTL837X_PIN_MUX_0
|
||||
// r7f8c:30000000 R7f8c-30000000 r7f8c:30000000 R7f8c-38000000
|
||||
REG_SET(0x7f8c, 0x38000000);
|
||||
|
||||
// [RTL837X_LED_PORT_SET_SEL]
|
||||
// r654c:00000000 R654c-00010000
|
||||
REG_SET(0x654c, 0x00010040);
|
||||
|
||||
// [RTL837X_REG_LED1_0_SET0]
|
||||
// R6548-00000141
|
||||
REG_SET(0x6548, 0x00000141);
|
||||
|
||||
// [RTL837X_REG_LED3_2_SET0]
|
||||
// r6544:01411000 R6544-01410174
|
||||
REG_SET(0x6544, 0x01410174);
|
||||
|
||||
// [RTL837X_REG_LED1_0_SET1]
|
||||
// r6540:00440070 R6540-0044017f
|
||||
REG_SET(0x6540, 0x0044017f);
|
||||
|
||||
// [RTL837X_REG_LED3_0_SET1]
|
||||
// r6528:00000000 R6528-000f0000
|
||||
REG_SET(0x6528, 0x000f0000);
|
||||
|
||||
cmd_editor_init();
|
||||
[...]
|
||||
```
|
||||
|
||||
Create an initial configuraiton for your device by copying over an existing one
|
||||
for the same device type, i.e. same port-configuraiton and same SoC,
|
||||
give it a new name. Make sure that the led_mux_custom and led_mux fields are not
|
||||
used, because our device does not customize the LED muxes.
|
||||
|
||||
Compile and flash onto your device.
|
||||
|
||||
Now, boot the switch and issue the `leds`command, which will print out:
|
||||
```
|
||||
RTL837X_PIN_MUX_0: 0x38000000
|
||||
RTL837X_REG_LED_GLB_IO_EN: 0x77ffff00
|
||||
RTL837X_REG_LED1_0_SET0: 0x00000141
|
||||
RTL837X_REG_LED3_2_SET0: 0x01410174
|
||||
RTL837X_REG_LED1_0_SET1: 0x0044017f
|
||||
RTL837X_REG_LED3_2_SET1: 0x18000040
|
||||
RTL837X_REG_LED1_0_SET2: 0x00000000
|
||||
RTL837X_REG_LED3_2_SET2: 0x00000000
|
||||
RTL837X_REG_LED1_0_SET3: 0x00000000
|
||||
RTL837X_REG_LED3_2_SET3: 0x00000000
|
||||
RTL837X_REG_LED3_0_SET1: 0x000f0000
|
||||
RTL837X_REG_LED3_0_SET3: 0x00000000
|
||||
RTL837X_LED_PORT_SET_SEL: 0x00010040
|
||||
RTL837X_REG_LED_GLB_MUX_1: 0x3fffffff
|
||||
RTL837X_REG_LED_GLB_MUX_2: 0x0c3fffff
|
||||
RTL837X_REG_LED_GLB_MUX_3: 0x1245038d
|
||||
RTL837X_REG_LED_GLB_MUX_4: 0x19616554
|
||||
RTL837X_REG_LED_GLB_MUX_5: 0x2079d71a
|
||||
RTL837X_REG_LED_GLB_MUX_6: 0x000238a1
|
||||
RTL837X_REG_LED_GLB_ACTIVE: 0x3ffbedff
|
||||
RTL837X_REG_LED_MODE: 0x0021e6b0
|
||||
LED pad Configuration:
|
||||
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b
|
||||
3f 3f 3f 3f 3f 3f 3f 3f 0f 0c 0d 0e 10 11 12 14 15 16 18 19 1a 1c 1d 1e 20 21 22 23
|
||||
LED-set Configuration:
|
||||
LED-ID 0 1 2 3
|
||||
SET 0: 000141 000000 000174 000141
|
||||
SET 1: 0f017f 000044 000040 001800
|
||||
SET 2: 000000 000000 000000 000000
|
||||
SET 3: 000000 000000 000000 000000
|
||||
Port 3: SET 1: ( 2G5 TWO_1G 1G 500M 100M 10M LINK ACT 10G TWO_5G 5G TWO_2G5), ( 1G LINK), ( LINK), ( COL DUPLEX),
|
||||
Port 4: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||
Port 5: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||
Port 6: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||
Port 7: SET 0: ( 2G5 LINK ACT), (), ( 1G 100M 10M LINK ACT), ( 2G5 LINK ACT),
|
||||
Port 8: SET 1: ( 2G5 TWO_1G 1G 500M 100M 10M LINK ACT 10G TWO_5G 5G TWO_2G5), ( 1G LINK), ( LINK), ( COL DUPLEX),
|
||||
|
||||
```
|
||||
Together with the GPIO information, this will give you the following machine configuration:
|
||||
```
|
||||
_code const struct machine machine = {
|
||||
.machine_name = "ZOERAX HG0402XG",
|
||||
.isRTL8373 = 0,
|
||||
.min_port = 3,
|
||||
.max_port = 8,
|
||||
.n_sfp = 2,
|
||||
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
|
||||
// Left SFP port (5)
|
||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.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 ),
|
||||
// Right SFP port (6)
|
||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
/* On Ethernet: Left led is orange, right green
|
||||
* 100M and 1G give right led green with activity
|
||||
* 2.5GBit adds solid left orange LED
|
||||
* LEDs for the SFP-ports are the same as for the Ethernet ports
|
||||
*/
|
||||
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT
|
||||
},
|
||||
{ LEDS_2G5 | LEDS_TWO_PAIR_1G | LEDS_1G | LEDS_500M | LEDS_100M | LEDS_10M |
|
||||
LEDS_LINK | LEDS_ACT | LEDS_10G | LEDS_TWO_PAIR_5G | LEDS_5G | LEDS_TWO_PAIR_2G5,
|
||||
LEDS_1G | LEDS_LINK,
|
||||
LEDS_LINK,
|
||||
LEDS_COL | LEDS_DUPLEX
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ The code currently provides the following functions:
|
||||
void igmp_setup(void) __banked;
|
||||
void igmp_enable(void) __banked;
|
||||
void igmp_router_port_set(uint16_t pmask) __banked;
|
||||
void igmp_packet_handler(void) __banked;
|
||||
uint8_t igmp_packet_handler(void) __banked;
|
||||
void igmp_show(void) __banked;
|
||||
```c
|
||||
`igmp_setup()` is called at boot-time and configures flooding of all IP-MC packets by
|
||||
@@ -80,7 +80,11 @@ of IP-MC packets to be limited to only subscribed ports.
|
||||
|
||||
`igmp_router_port_set()`configures forwarding ports for IGMP messages.
|
||||
|
||||
`igmp_packet_handler()` implements handling of trapped IGMP packets by the CPU.
|
||||
`igmp_packet_handler()` implements handling of trapped IGMP packets by the CPU. It is called
|
||||
for frames to 01:00:5e:xx:xx:xx and returns 0 when the frame is not a trapped IGMP packet,
|
||||
so that it is passed on to the IP stack. IGMPv1/v2 reports (0x12, 0x16) join the group given
|
||||
in the IGMP header, IGMPv2 leaves (0x17) leave it, IGMPv3 reports use the first group record
|
||||
(type 4 joins, type 3 leaves). Trapped IGMP frames arrive without a VLAN tag.
|
||||
|
||||
`igmp_show()` prints out the IGMP configuration on the CLI.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 120 KiB |
@@ -0,0 +1,54 @@
|
||||
# Storm Control
|
||||
Storm control limits the rate at which a port admits broadcast, multicast,
|
||||
unknown unicast and unknown multicast frames. Frames of a type above its limit
|
||||
are dropped at ingress, so a loop or a misbehaving host cannot flood the rest
|
||||
of the network through that port. Known unicast traffic is not affected.
|
||||
|
||||
## Commands
|
||||
```
|
||||
storm <port> bcast|mcast|ucast|umcast <rate> pps
|
||||
storm <port> bcast|mcast|ucast|umcast <rate> kbps
|
||||
storm <port> bcast|mcast|ucast|umcast off
|
||||
storm
|
||||
```
|
||||
`ucast` is unicast to a MAC address the switch has not learned yet, and
|
||||
`umcast` is multicast without an entry in the address table. Multicast groups
|
||||
get their entries from IGMP snooping, so without `igmp on` all multicast is
|
||||
unknown and only the `umcast` limit applies to it; `mcast` covers the groups
|
||||
IGMP has learned. A limit in
|
||||
packets per second goes from 1 to 1048575, a limit in kbit/s from 1 to
|
||||
10000000. `storm` without arguments prints the limits of every port. The
|
||||
limits are kept in the configuration like any other setting, and the Bandwidth
|
||||
page of the web interface has a Storm control card to set them.
|
||||
|
||||
## Registers
|
||||
Each port and type has an enable bit and a meter index, and each limit uses
|
||||
one of the 64 shared meters of the switch. RTLPlayground gives every port and
|
||||
type its own meter, index `24 + port * 4 + type`, so one port's storm does not
|
||||
eat into the limit of another. Storm control uses meters 24 to 63 and leaves
|
||||
0 to 23 to the ACL. The limit of a meter is in `RTL837X_METER_RATE + 4 *
|
||||
meter`, and bit `meter % 32` of `RTL837X_METER_MODE + 4 * (meter / 32)`
|
||||
selects pps instead of kbit/s.
|
||||
```
|
||||
#define RTL837X_STORM_CTRL 0x54e4 /* + 4 * type, bit = port */
|
||||
#define RTL837X_STORM_MIDX 0x54f4 /* + 8 * type + 4 * (port / 5), 6 bits per port */
|
||||
#define RTL837X_METER_RATE 0x5cf0 /* + 4 * meter, 24 bits, kbit/s or pps */
|
||||
#define RTL837X_METER_MODE 0x5ef0 /* + 4 * (meter / 32), bit set = pps */
|
||||
```
|
||||
In kbit/s mode one step of the rate is 1 kbit/s. Measured with 100 and 1000 byte
|
||||
frames, the meter counts a frame with its FCS, but without preamble and
|
||||
interframe gap. Every meter has a bit that adds them, in `0x5f08 + 4 * (meter
|
||||
/ 32)`, which storm control leaves cleared. `IGBW_INC_IFG` and `EGBW_INC_IFG`
|
||||
are the matching bits of the bandwidth control.
|
||||
|
||||
An ingress bandwidth limit on the same port works on the same arriving frames
|
||||
as the storm limit rather than after it, and the two together pass far less
|
||||
than either one: a 1 Mbit/s `umcast` limit with a 10 Mbit/s ingress limit let
|
||||
0.12 to 0.16 Mbit/s of a 1.4 Gbit/s stream through, where each alone passed
|
||||
1.17 and 10.2 Mbit/s.
|
||||
|
||||
The type is 0 for broadcast, 1 for multicast, 2 for unknown unicast and 3 for
|
||||
unknown multicast. The burst size of a meter (0x5df0 + 4 * meter) counts packets
|
||||
in pps mode; its default of 0x2000 lets 8192 frames through before a pps limit
|
||||
bites, so a pps limit sets the burst to one second of traffic. A kbit/s limit
|
||||
puts back the default.
|
||||
@@ -6,6 +6,9 @@ The following devices have been tested and are fully working:
|
||||
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
|
||||
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
|
||||
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
|
||||
| Goalake | IG108 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||
| GoodTop | GT-ST018M | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | ? | 8 + 1 |
|
||||
| Hasivo | S1100WP_8GT_1SX_SE | Yes | [S1100WP_8GT_1SX_SE-V1.05](devices/HASIVO_S1100WP_8GT_1SX_SE.md) | 2M | 8 + 1 |
|
||||
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
|
||||
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
|
||||
@@ -19,11 +22,16 @@ The following devices have been tested and are fully working:
|
||||
| Keeplink | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
|
||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 |
|
||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
|
||||
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 |
|
||||
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
|
||||
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
|
||||
| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
|
||||
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
|
||||
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
|
||||
| Binardat | 2G06-04210GSM | 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 |
|
||||
| Netcore | GS9 | No | [PB-2132](devices/PB-2132.md) | 4M | 8 + 1 |
|
||||
| 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 |
|
||||
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||
@@ -33,7 +41,7 @@ The following devices have been tested and are fully working:
|
||||
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
|
||||
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
|
||||
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
|
||||
| Lianguo | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 |
|
||||
| Guangnianwei | 7018-2.5G | No | [F7008-2.5GPOE-V1.2](devices/F7008-2.5.md) | 8M | 8 + 1 |
|
||||
|
||||
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
|
||||
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
var LANG={
|
||||
en:{
|
||||
nav_dash:"Dashboard",nav_ports:"Ports",nav_stp:"Spanning tree",nav_stats:"Statistics",
|
||||
nav_vlan:"VLANs",nav_l2:"MAC table",nav_mirror:"Mirroring",nav_lag:"LAG",nav_eee:"EEE",
|
||||
nav_bw:"Bandwidth",nav_system:"System",nav_fw:"Firmware",
|
||||
nav_vlan:"VLANs",nav_l2:"MAC table",nav_mirror:"Mirroring",nav_isolate:"Isolation",nav_lag:"LAG",nav_eee:"EEE",
|
||||
nav_bw:"Bandwidth",nav_system:"System",nav_fw:"Firmware",nav_lldp:"LLDP",
|
||||
hdr_dirty:"unsaved changes",hdr_dirty_t:"Running config differs from startup config",
|
||||
hdr_save:"Save to flash",hdr_save_t:"Persist running configuration to flash",
|
||||
th_auto:"System",th_auto_sel:"System (Selenized)",sy_display:"Display",sy_theme:"Theme",sy_display_note:"Stored in this browser only.",th_light:"Light",th_dark:"Dark",
|
||||
@@ -15,7 +15,7 @@ c_full:"full",c_half:"half",c_devices:"devices",c_yes:"yes",c_no:"no",
|
||||
d_ports:"Ports",d_ports_h:"click a port for details",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",
|
||||
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_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_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",
|
||||
@@ -40,6 +40,7 @@ stp_en_q:"Enable spanning tree?",
|
||||
stp_en_d:"Ports start blocked and take up to twice the forward delay to reach forwarding; edge ports recover immediately.",
|
||||
stp_dis_q:"Disable spanning tree?",stp_dis_d:"All ports go straight to forwarding; loop protection is lost.",
|
||||
stp_cost_err:"Path cost must be 0-200000000",
|
||||
lldp_enabled: "LLDP Enabled",lldp_title:"Service Status",lldp_portname:"Name",lldp_enable:"Send Frames",
|
||||
st_title:"Port statistics",st_h:"totals since boot",st_txg:"TX good",st_txb:"TX bad",st_rxg:"RX good",
|
||||
st_rxb:"RX bad",st_details:"Details",st_counters:"MIB counters",st_nonzero:"non-zero only",
|
||||
st_autoref:"auto-refresh",st_counter:"Counter",st_value:"Value",st_fail:"failed to load counters",
|
||||
@@ -62,6 +63,9 @@ l2_learned:"learned",l2_loading:"loading...",l2_failed:"load failed",l2_entries:
|
||||
l2_del_t:"Delete entry",l2_flush_q:"Flush all learned MAC entries?",
|
||||
m_title:"Port mirroring",m_active:"active",m_monitor:"Monitor port",m_mirror:"Mirror",m_both:"Both",
|
||||
m_note:"Both = mirror RX and TX of the port to the monitor port.",m_none:"Select at least one mirrored port",
|
||||
iso_title:"Port isolation",iso_from:"From port",iso_to:"To port",iso_all:"Allow all",
|
||||
iso_intro:"A frame entering a port may only leave through the ports ticked in its row. Isolation is decided before forwarding, so a port that is not ticked is unreachable directly, whatever the address table says.",
|
||||
iso_legend:"The cell of the port itself is always allowed. A port number in red marks a port that is not fully open.",
|
||||
lag_hash:"Hash:",lag_note:"A LAG needs at least one member to be saved in the startup config; applying an empty group clears it.",
|
||||
lag_clear_q:"Clear LAG {n}?",lag_clear_d:"All member ports return to normal operation.",
|
||||
e_title:"Energy Efficient Ethernet",e_adv:"Advertised",e_lp:"Link partner",e_active:"Active",e_enable:"Enable",
|
||||
@@ -70,8 +74,12 @@ e_idle:"idle",e_na:"n/a",
|
||||
bw_title:"Bandwidth limits",bw_h:"Mbit/s, 0.016-10000",bw_in:"Ingress limit",bw_out:"Egress limit",
|
||||
bw_exceed:"When exceeded",bw_fc:"Flow control",bw_drop:"Drop",
|
||||
bw_in_err:"Ingress limit must be 0.016-10000 Mbit/s",bw_out_err:"Egress limit must be 0.016-10000 Mbit/s",
|
||||
sc_title:"Storm control",sc_h:"per port and traffic type, empty = off",sc_bcast:"Broadcast",sc_mcast:"Multicast",
|
||||
sc_ucast:"Unknown unicast",sc_umcast:"Unknown multicast",sc_err:"Storm limit must be 1-1048575 pps or 1-10000000 kbit/s",
|
||||
sc_note:"Frames of a type above its limit are dropped where they enter the switch.",
|
||||
sy_network:"Network",sy_dhcp:"Use DHCP",sy_dhcp_t:"Request address via DHCP",sy_services:"Services",
|
||||
sy_igmp:"IGMP snooping",sy_sysip:"server IP",sy_server:"Server",sy_port:"Port",
|
||||
sy_sesstmo:"Session timeout (s)",sy_sesstmo_err:"Session timeout must be 1-65535 s",
|
||||
sy_services_note:"Service state reflects the startup config; runtime state is not readable.",
|
||||
sy_password:"Admin password",sy_newpw:"New password",sy_repeat:"Repeat",sy_pwapply:"Change password",
|
||||
sy_pw_note:"Takes effect immediately; save to flash to keep it after reboot.",sy_console:"Console",
|
||||
@@ -90,6 +98,7 @@ sy_rebooting:"Rebooting, reconnect in about 20 s",sy_bytes:"bytes",
|
||||
cw_title:"Write this startup configuration?",cw_save_title:"Save running configuration to flash?",
|
||||
cw_info:"{n} / 2048 bytes, replayed line by line on every boot",
|
||||
cw_toolarge:"Too large: the config sector accepts at most 2048 bytes. Remove lines first.",
|
||||
cw_longline:"Line {n} is {m} bytes long: the switch can only replay lines up to 126 bytes and would skip it on boot, so the write is refused. Shorten it first.",
|
||||
cw_unknown:"Not in the known config grammar (will still be written): ",cw_empty:"(empty)",
|
||||
cw_writing:"Writing configuration...",cw_failed:"config write failed: HTTP {n}",
|
||||
cw_verify_fail:"Verification failed: flash content differs from what was sent. Command log NOT cleared.",
|
||||
@@ -126,7 +135,7 @@ c_full:"全二重",c_half:"半二重",c_devices:"デバイス",c_yes:"はい",c_
|
||||
d_ports:"ポート",d_ports_h:"ポートをクリックすると詳細を表示",d_system:"システム",d_traffic:"トラフィック",
|
||||
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_built:"ビルド日",i_hw:"ハードウェア",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_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:"アドバタイズ",
|
||||
@@ -183,6 +192,7 @@ bw_exceed:"超過時の動作",bw_fc:"フロー制御",bw_drop:"破棄",
|
||||
bw_in_err:"入力制限は 0.016〜10000 Mbit/s の範囲で指定してください",bw_out_err:"出力制限は 0.016〜10000 Mbit/s の範囲で指定してください",
|
||||
sy_network:"ネットワーク",sy_dhcp:"DHCP を使用",sy_dhcp_t:"DHCP でアドレスを取得",sy_services:"サービス",
|
||||
sy_igmp:"IGMP スヌーピング",sy_sysip:"サーバー IP",sy_server:"サーバー",sy_port:"ポート",
|
||||
sy_sesstmo:"セッションタイムアウト (秒)",sy_sesstmo_err:"セッションタイムアウトは 1〜65535 秒で指定してください",
|
||||
sy_services_note:"サービスの状態は起動設定を反映しています。実行時の状態は読み取れません。",
|
||||
sy_password:"管理者パスワード",sy_newpw:"新しいパスワード",sy_repeat:"再入力",sy_pwapply:"パスワードを変更",
|
||||
sy_pw_note:"即時に反映されます。再起動後も保持するにはフラッシュに保存してください。",sy_console:"コンソール",
|
||||
@@ -201,6 +211,7 @@ sy_rebooting:"再起動中です。約 20 秒後に再接続してください",
|
||||
cw_title:"この起動設定を書き込みますか?",cw_save_title:"実行中の設定をフラッシュに保存しますか?",
|
||||
cw_info:"{n} / 2048 バイト、起動のたびに 1 行ずつ実行されます",
|
||||
cw_toolarge:"サイズ超過: 設定セクタは最大 2048 バイトです。先に行を削除してください。",
|
||||
cw_longline:"{n} 行目は {m} バイトです: スイッチが起動時に実行できる行は 126 バイトまでで、この行は読み飛ばされるため、書き込みを拒否します。先に短くしてください。",
|
||||
cw_unknown:"既知の設定文法に含まれない行 (そのまま書き込まれます): ",cw_empty:"(空)",
|
||||
cw_writing:"設定を書き込み中...",cw_failed:"設定の書き込みに失敗しました: HTTP {n}",
|
||||
cw_verify_fail:"検証失敗: フラッシュの内容が送信内容と異なります。コマンドログは消去されていません。",
|
||||
@@ -237,7 +248,7 @@ c_full:"全双工",c_half:"半双工",c_devices:"台设备",c_yes:"是",c_no:"
|
||||
d_ports:"端口",d_ports_h:"点击端口查看详情",d_system:"系统",d_traffic:"流量",
|
||||
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_built:"构建日期",i_hw:"硬件",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_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:"通告能力",
|
||||
@@ -294,6 +305,7 @@ bw_exceed:"超限动作",bw_fc:"流量控制",bw_drop:"丢弃",
|
||||
bw_in_err:"入方向限速范围为 0.016-10000 Mbit/s",bw_out_err:"出方向限速范围为 0.016-10000 Mbit/s",
|
||||
sy_network:"网络",sy_dhcp:"使用 DHCP",sy_dhcp_t:"通过 DHCP 获取地址",sy_services:"服务",
|
||||
sy_igmp:"IGMP 侦听",sy_sysip:"服务器 IP",sy_server:"服务器",sy_port:"端口",
|
||||
sy_sesstmo:"会话超时(秒)",sy_sesstmo_err:"会话超时必须为 1-65535 秒",
|
||||
sy_services_note:"服务状态反映启动配置;运行时状态无法读取。",
|
||||
sy_password:"管理员密码",sy_newpw:"新密码",sy_repeat:"重复输入",sy_pwapply:"修改密码",
|
||||
sy_pw_note:"立即生效;如需重启后保留请保存到 Flash。",sy_console:"控制台",
|
||||
@@ -312,6 +324,7 @@ sy_rebooting:"正在重启,约 20 秒后重新连接",sy_bytes:"字节",
|
||||
cw_title:"写入此启动配置?",cw_save_title:"将运行配置保存到 Flash?",
|
||||
cw_info:"{n} / 2048 字节,每次启动时逐行执行",
|
||||
cw_toolarge:"过大: 配置扇区最多容纳 2048 字节。请先删除部分行。",
|
||||
cw_longline:"第 {n} 行有 {m} 字节: 交换机启动时只能执行不超过 126 字节的行,该行会被跳过,因此拒绝写入。请先缩短该行。",
|
||||
cw_unknown:"不属于已知配置语法的行 (仍会写入): ",cw_empty:"(空)",
|
||||
cw_writing:"正在写入配置...",cw_failed:"配置写入失败: HTTP {n}",
|
||||
cw_verify_fail:"校验失败: Flash 内容与发送内容不一致。命令日志未清除。",
|
||||
@@ -332,6 +345,347 @@ fw_applied:"升级已应用",fw_done_t:"固件已升级",
|
||||
fw_done:"交换机已校验镜像并以新镜像重启。会话已重置,需要重新登录。",
|
||||
fw_login:"前往登录",fw_rebooting:"交换机正在重启...",
|
||||
fw_timeout:"150 秒后交换机仍未恢复: 请检查电源 / 串口控制台"
|
||||
},
|
||||
es:{
|
||||
nav_dash:"Panel",nav_ports:"Puertos",nav_stp:"Árbol de expansión",nav_stats:"Estadísticas",
|
||||
nav_vlan:"VLAN",nav_l2:"Tabla MAC",nav_mirror:"Duplicación",nav_lag:"LAG",nav_eee:"EEE",
|
||||
nav_bw:"Ancho de banda",nav_system:"Sistema",nav_fw:"Firmware",
|
||||
hdr_dirty:"cambios sin guardar",hdr_dirty_t:"La configuración en ejecución difiere de la guardada",
|
||||
hdr_save:"Guardar en flash",hdr_save_t:"Persistir la configuración en ejecución a flash",
|
||||
th_auto:"Sistema",th_auto_sel:"Sistema (Selenized)",sy_display:"Pantalla",sy_theme:"Tema",sy_display_note:"Se almacena solo en este navegador.",th_light:"Claro",th_dark:"Oscuro",
|
||||
th_sel_light:"Selenized claro",th_sel_dark:"Selenized oscuro",
|
||||
c_port:"Puerto",c_name:"Nombre",c_link:"Enlace",c_apply:"Aplicar",c_cancel:"Cancelar",c_confirm:"Confirmar",
|
||||
c_close:"Cerrar",c_refresh:"Actualizar",c_off:"apagado",c_offc:"Apagado",c_down:"caído",c_on:"Encendido",c_auto:"Auto",c_delete:"Eliminar",
|
||||
c_type:"Tipo",c_state:"Estado",c_enabled:"Habilitado",c_load:"Cargar",c_disable:"Deshabilitar",c_sfp:"SFP",
|
||||
c_full:"dúplex completo",c_half:"semidúplex",c_devices:"dispositivos",c_yes:"sí",c_no:"no",
|
||||
d_ports:"Puertos",d_ports_h:"pulsa un puerto para ver detalles",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",
|
||||
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",
|
||||
p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo",p_txgb:"TX correctos / erróneos",p_rxgb:"RX correctos / erróneos",
|
||||
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",
|
||||
pt_title:"Configuración de puerto",pt_conn:"Conectado",pt_speed:"Velocidad",pt_mtu:"MTU",
|
||||
pt_sfp_note:"La velocidad del SFP se ajusta por ranura y no se guarda en la configuración de inicio.",
|
||||
pt_name_err:"Nombre de puerto: 1-15 caracteres, sin espacios",pt_mtu_err:"El MTU debe estar entre 64 y 16383",
|
||||
stp_title:"Árbol de expansión",stp_h:"RSTP, 802.1w",stp_version:"Versión",stp_v_stp:"STP compatible",
|
||||
stp_prio:"Prioridad del puente",stp_hello:"Hello [s]",stp_maxage:"Edad máxima [s]",stp_fwd:"Retardo de reenvío [s]",
|
||||
stp_txhold:"Retención TX",stp_bridge_apply:"Aplicar ajustes del puente",
|
||||
stp_off_msg:"El árbol de expansión está deshabilitado: todos los puertos reenvían.",stp_bridge:"Puente",stp_root:"Raíz",
|
||||
stp_root_self:"este puente es la raíz",stp_via:"vía puerto",stp_cost:"coste de ruta",stp_tc:"cambios de topología",
|
||||
stp_prio_note:"La prioridad más baja gana la elección de raíz (8 por defecto = 32768). Los ajustes se aplican inmediatamente; usa Guardar en flash para conservarlos.",
|
||||
stp_portcfg:"Configuración de puertos",stp_edge:"Borde",stp_pcost:"Coste de ruta",stp_pprio:"Prioridad",
|
||||
stp_guard:"Protección",stp_filter:"Filtro BPDU",stp_p2p:"Punto a punto",
|
||||
stp_port_note:"Los puertos de borde reenvían inmediatamente y no causan cambios de topología; Auto trata un puerto como de borde tras 3 s sin BPDUs, y cualquier BPDU recibido lo revoca. Coste de ruta 0 = automático.",
|
||||
stp_status:"Estado de puertos",stp_role:"Rol",stp_db:"Puente designado",stp_dp:"Puerto designado",
|
||||
stp_dc:"Coste designado",stp_oedge:"Borde operativo",stp_op2p:"P2P operativo",
|
||||
stp_s0:"deshabilitado",stp_s1:"bloqueo",stp_s2:"aprendizaje",stp_s3:"reenvío",
|
||||
stp_r1:"Raíz",stp_r2:"Designado",stp_r3:"Alternativo",stp_trip:"protección disparada",
|
||||
stp_g_none:"Ninguno",stp_g_bpdu:"BPDU",stp_g_root:"Raíz",
|
||||
stp_en_q:"¿Habilitar el árbol de expansión?",
|
||||
stp_en_d:"Los puertos empiezan bloqueados y tardan hasta el doble del retardo de reenvío en alcanzar el reenvío; los puertos de borde se recuperan inmediatamente.",
|
||||
stp_dis_q:"¿Deshabilitar el árbol de expansión?",stp_dis_d:"Todos los puertos pasan directamente a reenviar; se pierde la protección contra bucles.",
|
||||
stp_cost_err:"El coste de ruta debe estar entre 0 y 200000000",
|
||||
st_title:"Estadísticas de puertos",st_h:"totales desde el arranque",st_txg:"TX correctos",st_txb:"TX erróneos",st_rxg:"RX correctos",
|
||||
st_rxb:"RX erróneos",st_details:"Detalles",st_counters:"Contadores MIB",st_nonzero:"solo no nulos",
|
||||
st_autoref:"actualización automática",st_counter:"Contador",st_value:"Valor",st_fail:"error al cargar contadores",
|
||||
v_title:"VLANs",v_vid:"VID",v_members:"Miembros",v_tagged:"Etiquetados",v_untagged:"Sin etiquetar",v_pvid_on:"PVID activo",
|
||||
v_empty:"No hay VLANs configuradas.",v_mgmt:"VLAN de gestión",v_mgmt_none:"sin etiquetar",v_editor:"Editor de VLANs",
|
||||
v_optional:"opcional",v_setmgmt:"Establecer como VLAN de gestión",v_setmgmt_t:"Hacer esta la VLAN de gestión",
|
||||
v_member:"Miembro",v_pvid:"PVID",
|
||||
v_legend:"U = miembro sin etiquetar, T = miembro etiquetado, - = no miembro. PVID asigna esta VLAN al tráfico entrante sin etiquetar.",
|
||||
v_ingress:"Filtrado de entrada",v_ingress_h:"solo escritura: el estado no se puede leer desde el switch",
|
||||
v_accept:"Aceptar",v_ing_all:"Todos",v_ing_apply:"Aplicar modos de entrada",v_del_t:"Eliminar VLAN",
|
||||
v_del_q:"¿Eliminar VLAN {n}?",v_del_d:"Los puertos conservan su PVID hasta que se reasignen.",
|
||||
v_vid_err:"Introduce un ID de VLAN (1-4094)",v_name_err:"El nombre debe empezar por una letra (letras, dígitos, _)",
|
||||
v_loaded:"VLAN {n} cargada",v_notfound:"VLAN {n} no encontrada (aún se puede crear una nueva)",
|
||||
v_nomember:"Selecciona al menos un puerto miembro (o elimina la VLAN)",
|
||||
v_ing_none:"Elige un modo de entrada para al menos un puerto",v_vid_first:"Introduce primero un ID de VLAN",
|
||||
v_mgmt_q:"¿Establecer VLAN {n} como VLAN de gestión?",
|
||||
v_mgmt_d:"El switch empezará a etiquetar su propio tráfico con esa VLAN. Si el puerto por el que te conectas no la transporta, esta página dejará de ser accesible y el ajuste solo podrá deshacerse por la consola.",
|
||||
l2_title:"Tabla de direcciones MAC",l2_filter:"filtrar...",l2_flush:"Vaciar entradas aprendidas",l2_static:"estática",
|
||||
l2_learned:"aprendida",l2_loading:"cargando...",l2_failed:"error de carga",l2_entries:"entradas",
|
||||
l2_del_t:"Eliminar entrada",l2_flush_q:"¿Vaciar todas las entradas MAC aprendidas?",
|
||||
m_title:"Duplicación de puertos",m_active:"activa",m_monitor:"Puerto monitor",m_mirror:"Duplicar",m_both:"Ambos",
|
||||
m_note:"Ambos = duplica RX y TX del puerto al puerto monitor.",m_none:"Selecciona al menos un puerto duplicado",
|
||||
lag_hash:"Hash:",lag_note:"Un LAG necesita al menos un miembro para guardarse en la configuración de inicio; aplicar un grupo vacío lo borra.",
|
||||
lag_clear_q:"¿Borrar LAG {n}?",lag_clear_d:"Todos los puertos miembros vuelven a la operación normal.",
|
||||
e_title:"Ethernet de bajo consumo",e_adv:"Anunciado",e_lp:"Par de enlace",e_active:"Activo",e_enable:"Habilitar",
|
||||
e_note:"Banderas anunciadas y del socio de enlace por velocidad: 100M, 1G, 2.5G. Los puertos SFP no soportan EEE.",
|
||||
e_idle:"inactivo",e_na:"n/d",
|
||||
bw_title:"Límites de ancho de banda",bw_h:"Mbit/s, 0.016-10000",bw_in:"Límite de entrada",bw_out:"Límite de salida",
|
||||
bw_exceed:"Al excederse",bw_fc:"Control de flujo",bw_drop:"Descartar",
|
||||
bw_in_err:"El límite de entrada debe estar entre 0.016 y 10000 Mbit/s",bw_out_err:"El límite de salida debe estar entre 0.016 y 10000 Mbit/s",
|
||||
sy_network:"Red",sy_dhcp:"Usar DHCP",sy_dhcp_t:"Solicitar dirección mediante DHCP",sy_services:"Servicios",
|
||||
sy_igmp:"IGMP snooping",sy_sysip:"IP del servidor",sy_server:"Servidor",sy_port:"Puerto",
|
||||
sy_sesstmo:"Tiempo de sesión (s)",sy_sesstmo_err:"El tiempo de sesión debe estar entre 1 y 65535 s",
|
||||
sy_services_note:"El estado del servicio refleja la configuración de inicio; el estado en ejecución no es legible.",
|
||||
sy_password:"Contraseña de administrador",sy_newpw:"Nueva contraseña",sy_repeat:"Repetir",sy_pwapply:"Cambiar contraseña",
|
||||
sy_pw_note:"Toma efecto inmediatamente; guarda en flash para conservarla tras el reinicio.",sy_console:"Consola",
|
||||
sy_cmd:"Comando de CLI...",sy_send:"Enviar",sy_startup:"Configuración de inicio",sy_replayed:"reaplicada en cada arranque",
|
||||
sy_reload:"Recargar desde flash",sy_write:"Escribir en flash",sy_unknown_note:"Las líneas desconocidas se resaltan antes de escribir.",
|
||||
sy_maint:"Mantenimiento",sy_reboot:"Reiniciar switch",sy_lang:"Idioma",
|
||||
sy_ip_err:"IP / máscara / puerta de enlace no válidos",sy_host_err:"Nombre de host: 1-23 caracteres imprimibles, sin espacios ni comillas",
|
||||
sy_net_q:"¿Aplicar ajustes de red?",sy_net_d:"La IP de gestión cambia a {ip}: esta página deberá reabrirse allí.",
|
||||
sy_ip_changed:"IP cambiada, reconecta en http://{ip}/",sy_dhcp_q:"¿Cambiar a DHCP?",
|
||||
sy_dhcp_d:"El switch solicita una dirección mediante DHCP. Deberás encontrar su nueva IP para reconectar.",
|
||||
sy_sysip_err:"IP del servidor syslog no válida",sy_sysport_err:"El puerto de syslog debe estar entre 1 y 65535",
|
||||
sy_pw_len:"Contraseña: 1-20 caracteres",sy_pw_space:"La contraseña no puede contener espacios",sy_pw_match:"Las contraseñas no coinciden",
|
||||
sy_pw_q:"¿Cambiar la contraseña de administrador?",sy_pw_d:"Toma efecto inmediatamente para los nuevos inicios de sesión. Guarda en flash para persistir.",
|
||||
sy_reboot_q:"¿Reiniciar el switch?",sy_reboot_d:"Hay cambios SIN GUARDAR y se perderán. Guarda en flash primero si quieres conservarlos.",
|
||||
sy_rebooting:"Reiniciando, reconecta en unos 20 s",sy_bytes:"bytes",
|
||||
cw_title:"¿Escribir esta configuración de inicio?",cw_save_title:"¿Guardar la configuración en ejecución en flash?",
|
||||
cw_info:"{n} / 2048 bytes, reaplicada línea a línea en cada arranque",
|
||||
cw_toolarge:"Demasiado grande: el sector de configuración admite como máximo 2048 bytes. Elimina líneas primero.",
|
||||
cw_unknown:"No está en la gramática de configuración conocida (aun así se escribirá): ",cw_empty:"(vacío)",
|
||||
cw_writing:"Escribiendo configuración...",cw_failed:"error al escribir la configuración: HTTP {n}",
|
||||
cw_verify_fail:"Verificación fallida: el contenido de la flash difiere de lo enviado. El registro de comandos NO se ha borrado.",
|
||||
cw_saved:"Configuración de inicio guardada y verificada",cw_collect:"Recopilando cambios en ejecución...",
|
||||
t_applied:"Aplicado: {c}",t_cmds:"{n} comando(s) aplicado(s)",t_rejected:"comando rechazado: {c}",t_failed:"fallo: {c}",
|
||||
fw_title:"Actualización de firmware",
|
||||
fw_intro:"Sube una imagen de RTLPlayground (512 KiB .bin). La imagen se almacena provisionalmente en flash y se comprueba con CRC; si es correcta, el switch se reinicia, vuelve a verificar la imagen y la aplica. La configuración de inicio se conserva.",
|
||||
fw_upload:"Subir",fw_checking:"{f}: {n} bytes. Comprobando...",fw_size_err:"el tamaño es {n}, se esperaban 524288 (512 KiB)",
|
||||
fw_magic_err:"falta la cabecera de banco / magia LJMP: no es una imagen de firmware",fw_crc_err:"comprobación CRC16 fallida: imagen corrupta",
|
||||
fw_valid:"imagen de RTLPlayground válida (tamaño, magia y CRC16 correctos)",fw_q:"¿Subir firmware?",
|
||||
fw_d:"Si la suma de comprobación es correcta, el switch se reinicia y aplica la imagen durante el arranque (la configuración de inicio se conserva). No lo apagues hasta que vuelva.",
|
||||
fw_finishing:"terminando escritura en flash... {s} s",fw_uploading:"subiendo... {p}% / {s} s",
|
||||
fw_verified:"suma de comprobación verificada, el switch se está reiniciando...",
|
||||
fw_rejected:"el switch rechazó la imagen (suma de comprobación incorrecta), no se aplicó nada",
|
||||
fw_lost:"error de subida: conexión perdida durante la transferencia",
|
||||
fw_noreboot:"no se detectó reinicio: lo más probable es que la imagen fuera rechazada. Si actualizas desde un firmware antiguo, verifica la versión en la barra lateral tras volver a iniciar sesión.",
|
||||
fw_applied:"actualización aplicada",fw_done_t:"Firmware actualizado",
|
||||
fw_done:"El switch verificó la imagen y se reinició con ella. La sesión se restableció, así que se te pedirá que vuelvas a iniciar sesión.",
|
||||
fw_login:"Ir al inicio de sesión",fw_rebooting:"el switch se está reiniciando...",
|
||||
fw_timeout:"el switch no ha vuelto tras 150 s: comprueba la alimentación / consola serie"
|
||||
},
|
||||
fr:{
|
||||
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_bw:"Bande passante",nav_system:"Système",nav_fw:"Micro logiciel",
|
||||
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",
|
||||
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_sel_light:"Clair (sélénisé)",th_sel_dark:"Sombre (sélénisé)",
|
||||
c_port:"Port",c_name:"Nom",c_link:"Lien",c_apply:"Appliquer",c_cancel:"Annuler",c_confirm:"Confirmer",
|
||||
c_close:"Fermer",c_refresh:"Raffraichir",c_off:"arrêt",c_offc:"Arrêt",c_down:"arrêt",c_on:"Marche",c_auto:"Auto",c_delete:"Supprimer",
|
||||
c_type:"Type",c_state:"Etat",c_enabled:"Activé",c_load:"Charger",c_disable:"Désactivé",c_sfp:"SFP",
|
||||
c_full:"full",c_half:"half",c_devices:"Equipements",c_yes:"oui",c_no:"non",
|
||||
d_ports:"Ports",d_ports_h:"Cliquez ou survollez pour plus de détails",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",
|
||||
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",
|
||||
p_state:"Etat",p_disabled:"Inactif",p_up:"Actif",p_txgb:"TX bon / mauvais",p_rxgb:"RX bon / mauvais",
|
||||
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",
|
||||
pt_title:"Configuration du port",pt_conn:"Connecté à",pt_speed:"Vitesse",pt_mtu:"MTU",
|
||||
pt_sfp_note:"La vitesse SFP est paramétrée pour le port et n'est pas enregistrée dans la configuration de démarrage.",
|
||||
pt_name_err:"Nom du port: 1 à 15 caractères, sans espaces",pt_mtu_err:"MTU doit être comrpis entre 64 et 16383",
|
||||
stp_title:"Arborescence",stp_h:"RSTP, 802.1w",stp_version:"Protocole",stp_v_stp:"Compatible STP",
|
||||
stp_prio:"Priorité",stp_hello:"Bonjour [s]",stp_maxage:"Age max [s]",stp_fwd:"Délai de transmission [s]",
|
||||
stp_txhold:"TX en attente",stp_bridge_apply:"Appliquer les paramètres du pont",
|
||||
stp_off_msg:"Arborescence désactivée: Tous les ports sont retransmis.",stp_bridge:"Pont",stp_root:"Racine",
|
||||
stp_root_self:"Ce pont est la racine",stp_via:"via le port",stp_cost:"coût du chemin",stp_tc:"changements de topologie",
|
||||
stp_prio_note:"La priorité la plus basse devient la racine (défaut 8 à 32768). Les paramètres s'appliquent immediatement; utiliser Sauvegarder en flash pour les conserver.",
|
||||
stp_portcfg:"Configuration du port",stp_edge:"Port terminal",stp_pcost:"Coût du chemin",stp_pprio:"Priorité",
|
||||
stp_guard:"Protection",stp_filter:"Filtre BPDU",stp_p2p:"Point-à-point",
|
||||
stp_port_note:"Les ports en bordure sont transmis immediatemment et ne change pas la topologie; Auto traite le port comme une bordure après 3s sans BPDUs, et chaque BPDU reçu le révoque. Le coût du chemin 0 = automatique.",
|
||||
stp_status:"Statut du port",stp_role:"Rôle",stp_db:"Pont désigné",stp_dp:"Port désigné",
|
||||
stp_dc:"Coût désigné",stp_oedge:"Oper. terminales",stp_op2p:"Oper. en P2P",
|
||||
stp_s0:"désactivé",stp_s1:"bloquage",stp_s2:"apprentissage",stp_s3:"retransmission",
|
||||
stp_r1:"Racine",stp_r2:"Designé",stp_r3:"Alternatif",stp_trip:"protection déclenchée",
|
||||
stp_g_none:"Aucun",stp_g_bpdu:"BPDU",stp_g_root:"Racine",
|
||||
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_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",
|
||||
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_autoref:"rafraichissement automatique",st_counter:"Compteur",st_value:"Valeur",st_fail:"Erreur au chargement des compteurs",
|
||||
v_title:"VLANs",v_vid:"VID",v_members:"Membres",v_tagged:"Tagué",v_untagged:"Détagué",v_pvid_on:"PVID on",
|
||||
v_empty:"Aucun VLANs configuré.",v_mgmt:"VLAN de management",v_mgmt_none:"détagué",v_editor:"Editeur de VLAN",
|
||||
v_optional:"optionel",v_setmgmt:"Mette en VLAN de management",v_setmgmt_t:"Mettre celui-ci en VLAN de management",
|
||||
v_member:"Membre",v_pvid:"PVID",
|
||||
v_legend:"U = Membre détagué (UnTagged), T = membre tagué (Tagged), - = non membre. PVID (Port VLan ID) assigne ce VLAN au trafic entrant non tagué.",
|
||||
v_ingress:"Filtrage entrant",v_ingress_h:"en ériture seule: cet état n'est pas lisible depuis le communtateur réseau",
|
||||
v_accept:"Accepté",v_ing_all:"Tous",v_ing_apply:"Appliquer les filtes",v_del_t:"Supprimer le VLAN",
|
||||
v_del_q:"Supprimer le VLAN {n}?",v_del_d:"Les ports conservent leur PVID tant qu'ils ne sont pas réassignés.",
|
||||
v_vid_err:"Entrez un identifiant VLAN (1-4094)",v_name_err:"Le nom doit commencer par une lettre (lettre, chiffres, _)",
|
||||
v_loaded:"VLAN chargés {n}",v_notfound:"VLAN {n} non trouvé (un nouveau peut toutefois être créé)",
|
||||
v_nomember:"Selectionnez au moins un port membre (ou supprimez le VLAN)",
|
||||
v_ing_none:"Sélectionnez le mode entrant pour au moins un port",v_vid_first:"Entrez un identifiant VLAN d'abord",
|
||||
v_mgmt_q:"Mettre ce VLAN {n} en tant que VLAN de management?",
|
||||
v_mgmt_d:"Ce commutateur commencera par taguer son propre trafic avec ce VLAN. Si le port avec lequel vous êtes connecté ne le permet pas, cette page deviendra inaccessible et les paramètres ne pourront plus être changés que via la console.",
|
||||
l2_title:"Table des adresses MAC",l2_filter:"filtre...",l2_flush:"Effacer les entrées apprises",l2_static:"static",
|
||||
l2_learned:"appris",l2_loading:"chargement...",l2_failed:"chargement non réussi",l2_entries:"entrées",
|
||||
l2_del_t:"Supprimer l'entrée",l2_flush_q:"Effacer toutes les entrées MAC apprises?",
|
||||
m_title:"Duplication de ports",m_active:"actif",m_monitor:"Port de supervision",m_mirror:"Mirroir",m_both:"RX&TX",
|
||||
m_note:"RX&TX = duplique RX et TX du port vers le port de supervision.",m_none:"Selectionnez au moins un port à dupliquer",
|
||||
lag_hash:"Hachage:",lag_note:"Un groupe d'agrégation de Lien (LAG) nécessite au moins un membre pour être sauvegardé dans la configuration de démarrage; Utiliser un groupe vide fait office de remise à zero.",
|
||||
lag_clear_q:"Effacer l'agrégation {n}?",lag_clear_d:"Tous les ports membres vont redevenir normaux.",
|
||||
e_title:"Gestion énergétique des ports",e_adv:"Capacités",e_lp:"Capacité du partenaire",e_active:"Actif",e_enable:"Basse consommation",
|
||||
e_note:"Capacité de l'hôte et des partenaires : 100M, 1G, 2.5G. Les ports SFP ne peuvent pas bénéficier de l'EEE.",
|
||||
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_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",
|
||||
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_sesstmo:"Temps mort de session (s)",sy_sesstmo_err:"Le temps morts de session doit être compris en 1-65535 s",
|
||||
sy_services_note:"L'état de service dépend de la configuration de démarrage; Le temps de fonctionnement n'est pas consultable.",
|
||||
sy_password:"Gestion de l'accès",sy_newpw:"Mot de passe",sy_repeat:"Confirmation",sy_pwapply:"Changer le mot de passe",
|
||||
sy_pw_note:"Prends effet immédiatement; Sauvegardez en flash afin de conserver la configuration lors du redémarrage.",sy_console:"Console",
|
||||
sy_cmd:"Ligne de commande...",sy_send:"Envoyer",sy_startup:"Configuration de démarrage",sy_replayed:"Rejouée à chaque redémarrage",
|
||||
sy_reload:"Recharger depuis la mémoire flash",sy_write:"Ecrire en mémoire flash",sy_unknown_note:"Les lignes incorrectes sont mises en évidence avant l'écriture.",
|
||||
sy_maint:"Maintenance",sy_reboot:"Redémarre le commutateur",sy_lang:"Langage",
|
||||
sy_ip_err:"Erreur d'IP / masque réseau / passerelle",sy_host_err:"Nom d'hôte : 1 à 23 caractères, sans espace ni apostrophes",
|
||||
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_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_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_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_rebooting:"Redémarrage, reconnectez-vous d'ici 20s",sy_bytes:"bytes",
|
||||
cw_title:"Enregistrer cette configuration de démarrage?",cw_save_title:"Enregistrer la configuration active en mémoire flash?",
|
||||
cw_info:"{n} / 2048 bytes, qui seront rejouées ligne par ligne à chaque redémarrage",
|
||||
cw_toolarge:"Trop grand : La quota du secteur de démarrage ne peut excéder 2048 bytes. Supprimez des lignes.",
|
||||
cw_longline:"La ligne {n} est longue de {m} bytes: Le commutateur ne peut exécuter des lignes de plus de 126 bytes et les omettra donc au démarragee, l'écriture est refusé. Raccourcissez les d'abord.",
|
||||
cw_unknown:"Ne respecte pas la grammaire de configuration (sera néanmoins sauvegardé): ",cw_empty:"(vide)",
|
||||
cw_writing:"Configuration enregistrée...",cw_failed:"Echec de l'enregistrement de la configuration: HTTP {n}",
|
||||
cw_verify_fail:"Verification erronée: La mémoire flash présente des différences par rapport à ce qui a été transmis. Le log de commande ne sera pas éffacé.",
|
||||
cw_saved:"Configuration de démarrage sauvegardée et vérifiée",cw_collect:"Récolement des modification des paramètres courants...",
|
||||
t_applied:"Appliqué: {c}",t_cmds:"{n} commande(s) appliquée(s)",t_rejected:"commandes rejetées: {c}",t_failed:"échecs: {c}",
|
||||
fw_title:"Mise à jour du micro-logiciel",
|
||||
fw_intro:"Charge une image RTLPlayground (512 KiB .bin). L'image est envoée en mémoire flash, analysée et sa somme de contrôle est vérifiée; en cas de succès le commutateur va redémarrer, re-verifiez l'image et appliquez-là. LA configuration de démarrage est conservée.",
|
||||
fw_upload:"Charger",fw_checking:"{f}: {n} bytes. Vérification...",fw_size_err:"la taille est {n} alors que nous attendons 524288 (512 KiB)",
|
||||
fw_magic_err:"Entête de banque de donnée manquant / contrôle LJMP: ce n'est pas une image de firmware",fw_crc_err:"Somme de contrôle erronée: image corrompue",
|
||||
fw_valid:"Image RTLPlayground valide (taille, LJMP et somme de contrôle OK)",fw_q:"Chargement du firmware?",
|
||||
fw_d:"Si la somme de contrôle est correcte, le commutateur va redémarrer tout seul et charger la nouvelle image lors du démarrage (la configuration est préservée). Ne pas éteindre l'appareil avant que les voyants ne s'éteignent.",
|
||||
fw_finishing:"Fin d'écriture en mémoire flash... {s} s",fw_uploading:"Chargement... {p}% / {s} s",
|
||||
fw_verified:"Somme de contrôle vérifiée, le commutateur redémarre...",
|
||||
fw_rejected:"L'image est rejettée en raison d'une somme de contrôle incorrecte, rien n'a été appliqué",
|
||||
fw_lost:"Erreur lors du chargement: connection perdue à mi-transfert",
|
||||
fw_noreboot:"Pas de redemarrage détecté: l'image a certainement été refusée. Si vous chargesz un ancien firmware, verifiez la version affichée après l'écran de connection.",
|
||||
fw_applied:"Mise à jour effectuée",fw_done_t:"Firmware mis à jour",
|
||||
fw_done:"Le commutateur a vérifié l'image et vient de redémarrer. La session a été remise à zero, vous devez vous reconnecter.",
|
||||
fw_login:"Vers l'écran de connection",fw_rebooting:"Le commutateur redémarre...",
|
||||
fw_timeout:"Le commutateur n'est plus joignable depuis 150 s: verifiez l'alimentation ou utilisez la console série"
|
||||
},
|
||||
de:{
|
||||
nav_dash:"Übersicht",nav_ports:"Ports",nav_stp:"Spanning Tree",nav_stats:"Statistik",
|
||||
nav_vlan:"VLANs",nav_l2:"MAC-Tabelle",nav_mirror:"Spiegelung",nav_lag:"LAG",nav_eee:"EEE",
|
||||
nav_bw:"Bandbreite",nav_system:"System",nav_fw:"Firmware",
|
||||
hdr_dirty:"ungespeicherte Änderungen",hdr_dirty_t:"Laufende Konfiguration weicht von der Startkonfiguration ab",
|
||||
hdr_save:"Im Flash speichern",hdr_save_t:"Laufende Konfiguration dauerhaft im Flash speichern",
|
||||
th_auto:"System",th_auto_sel:"System (Selenized)",sy_display:"Anzeige",sy_theme:"Farbschema",sy_display_note:"Wird nur in diesem Browser gespeichert.",th_light:"Hell",th_dark:"Dunkel",
|
||||
th_sel_light:"Selenized Hell",th_sel_dark:"Selenized Dunkel",
|
||||
c_port:"Port",c_name:"Name",c_link:"Link",c_apply:"Übernehmen",c_cancel:"Abbrechen",c_confirm:"Bestätigen",
|
||||
c_close:"Schliessen",c_refresh:"Aktualisieren",c_off:"aus",c_offc:"Aus",c_down:"getrennt",c_on:"Ein",c_auto:"Auto",c_delete:"Löschen",
|
||||
c_type:"Typ",c_state:"Zustand",c_enabled:"Aktiviert",c_load:"Laden",c_disable:"Deaktivieren",c_sfp:"SFP",
|
||||
c_full:"voll",c_half:"halb",c_devices:"Geräte",c_yes:"ja",c_no:"nein",
|
||||
d_ports:"Ports",d_ports_h:"Port anklicken für Details",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",
|
||||
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",
|
||||
p_state:"Zustand",p_disabled:"deaktiviert",p_up:"verbunden",p_txgb:"TX gut / fehlerhaft",p_rxgb:"RX gut / fehlerhaft",
|
||||
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",
|
||||
pt_title:"Port-Konfiguration",pt_conn:"Verbunden",pt_speed:"Geschwindigkeit",pt_mtu:"MTU",
|
||||
pt_sfp_note:"Die SFP-Geschwindigkeit wird pro Steckplatz gesetzt und nicht in der Startkonfiguration gespeichert.",
|
||||
pt_name_err:"Port-Name: 1-15 Zeichen, keine Leerzeichen",pt_mtu_err:"MTU muss zwischen 64 und 16383 liegen",
|
||||
stp_title:"Spanning Tree",stp_h:"RSTP, 802.1w",stp_version:"Version",stp_v_stp:"STP-kompatibel",
|
||||
stp_prio:"Bridge-Priorität",stp_hello:"Hello [s]",stp_maxage:"Max. Alter [s]",stp_fwd:"Forward Delay [s]",
|
||||
stp_txhold:"TX Hold",stp_bridge_apply:"Bridge-Einstellungen übernehmen",
|
||||
stp_off_msg:"Spanning Tree ist deaktiviert: Alle Ports leiten weiter.",stp_bridge:"Bridge",stp_root:"Root",
|
||||
stp_root_self:"diese Bridge ist Root",stp_via:"über Port",stp_cost:"Pfadkosten",stp_tc:"Topologieänderungen",
|
||||
stp_prio_note:"Die niedrigere Priorität gewinnt die Root-Wahl (Standard 8 = 32768). Einstellungen wirken sofort; mit „Im Flash speichern“ bleiben sie erhalten.",
|
||||
stp_portcfg:"Port-Konfiguration",stp_edge:"Edge",stp_pcost:"Pfadkosten",stp_pprio:"Priorität",
|
||||
stp_guard:"Guard",stp_filter:"BPDU-Filter",stp_p2p:"Punkt-zu-Punkt",
|
||||
stp_port_note:"Edge-Ports leiten sofort weiter und lösen keine Topologieänderung aus; bei Auto gilt ein Port nach 3 s ohne BPDUs als Edge, jede empfangene BPDU hebt das wieder auf. Pfadkosten 0 = automatisch.",
|
||||
stp_status:"Port-Status",stp_role:"Rolle",stp_db:"Designated Bridge",stp_dp:"Designated Port",
|
||||
stp_dc:"Designated Cost",stp_oedge:"Edge (aktiv)",stp_op2p:"P2P (aktiv)",
|
||||
stp_s0:"deaktiviert",stp_s1:"blockiert",stp_s2:"lernt",stp_s3:"leitet weiter",
|
||||
stp_r1:"Root",stp_r2:"Designated",stp_r3:"Alternate",stp_trip:"Guard ausgelöst",
|
||||
stp_g_none:"Keiner",stp_g_bpdu:"BPDU",stp_g_root:"Root",
|
||||
stp_en_q:"Spanning Tree aktivieren?",
|
||||
stp_en_d:"Die Ports starten blockiert und brauchen bis zum doppelten Forward Delay, bis sie weiterleiten; Edge-Ports sind sofort wieder aktiv.",
|
||||
stp_dis_q:"Spanning Tree deaktivieren?",stp_dis_d:"Alle Ports leiten sofort weiter; der Schutz vor Netzwerkschleifen entfällt.",
|
||||
stp_cost_err:"Pfadkosten müssen zwischen 0 und 200000000 liegen",
|
||||
st_title:"Port-Statistik",st_h:"Summen seit dem Start",st_txg:"TX gut",st_txb:"TX fehlerhaft",st_rxg:"RX gut",
|
||||
st_rxb:"RX fehlerhaft",st_details:"Details",st_counters:"MIB-Zähler",st_nonzero:"nur ungleich null",
|
||||
st_autoref:"automatisch aktualisieren",st_counter:"Zähler",st_value:"Wert",st_fail:"Zähler konnten nicht geladen werden",
|
||||
v_title:"VLANs",v_vid:"VID",v_members:"Mitglieder",v_tagged:"Tagged",v_untagged:"Untagged",v_pvid_on:"PVID auf",
|
||||
v_empty:"Keine VLANs konfiguriert.",v_mgmt:"Management-VLAN",v_mgmt_none:"untagged",v_editor:"VLAN-Editor",
|
||||
v_optional:"optional",v_setmgmt:"Als Management-VLAN",v_setmgmt_t:"Dieses VLAN zum Management-VLAN machen",
|
||||
v_member:"Mitglied",v_pvid:"PVID",
|
||||
v_legend:"U = Mitglied untagged, T = Mitglied tagged, - = kein Mitglied. PVID ordnet eingehenden Verkehr ohne Tag diesem VLAN zu.",
|
||||
v_ingress:"Ingress-Filter",v_ingress_h:"nur schreibbar: der Zustand lässt sich vom Switch nicht auslesen",
|
||||
v_accept:"Annehmen",v_ing_all:"Alle",v_ing_apply:"Ingress-Modi übernehmen",v_del_t:"VLAN löschen",
|
||||
v_del_q:"VLAN {n} löschen?",v_del_d:"Die Ports behalten ihre PVID, bis sie neu zugewiesen wird.",
|
||||
v_vid_err:"VLAN-ID eingeben (1-4094)",v_name_err:"Der Name muss mit einem Buchstaben beginnen (Buchstaben, Ziffern, _)",
|
||||
v_loaded:"VLAN {n} geladen",v_notfound:"VLAN {n} nicht gefunden (es kann neu angelegt werden)",
|
||||
v_nomember:"Mindestens einen Mitglieds-Port wählen (oder das VLAN stattdessen löschen)",
|
||||
v_ing_none:"Für mindestens einen Port einen Ingress-Modus wählen",v_vid_first:"Zuerst eine VLAN-ID eingeben",
|
||||
v_mgmt_q:"VLAN {n} als Management-VLAN setzen?",
|
||||
v_mgmt_d:"Der Switch versieht dann seinen eigenen Verkehr mit diesem VLAN-Tag. Führt der Port, über den du verbunden bist, dieses VLAN nicht, ist diese Seite nicht mehr erreichbar und die Einstellung lässt sich nur noch über die serielle Konsole zurücknehmen.",
|
||||
l2_title:"MAC-Adresstabelle",l2_filter:"filtern...",l2_flush:"Gelernte Einträge löschen",l2_static:"statisch",
|
||||
l2_learned:"gelernt",l2_loading:"lädt...",l2_failed:"Laden fehlgeschlagen",l2_entries:"Einträge",
|
||||
l2_del_t:"Eintrag löschen",l2_flush_q:"Alle gelernten MAC-Einträge löschen?",
|
||||
m_title:"Port-Spiegelung",m_active:"aktiv",m_monitor:"Monitor-Port",m_mirror:"Spiegeln",m_both:"Beide",
|
||||
m_note:"Beide = RX und TX des Ports auf den Monitor-Port spiegeln.",m_none:"Mindestens einen zu spiegelnden Port wählen",
|
||||
lag_hash:"Hash:",lag_note:"Eine LAG braucht mindestens ein Mitglied, um in der Startkonfiguration gespeichert zu werden; eine leere Gruppe zu übernehmen löscht sie.",
|
||||
lag_clear_q:"LAG {n} auflösen?",lag_clear_d:"Alle Mitglieds-Ports kehren in den Normalbetrieb zurück.",
|
||||
e_title:"Energy Efficient Ethernet",e_adv:"Angeboten",e_lp:"Gegenstelle",e_active:"Aktiv",e_enable:"Aktivieren",
|
||||
e_note:"Angebotene und von der Gegenstelle unterstützte Stufen je Geschwindigkeit: 100M, 1G, 2.5G. SFP-Ports unterstützen kein EEE.",
|
||||
e_idle:"inaktiv",e_na:"k. A.",
|
||||
bw_title:"Bandbreitenbegrenzung",bw_h:"Mbit/s, 0.016-10000",bw_in:"Eingangslimit",bw_out:"Ausgangslimit",
|
||||
bw_exceed:"Bei Überschreitung",bw_fc:"Flusskontrolle",bw_drop:"Verwerfen",
|
||||
bw_in_err:"Eingangslimit muss zwischen 0.016 und 10000 Mbit/s liegen",bw_out_err:"Ausgangslimit muss zwischen 0.016 und 10000 Mbit/s liegen",
|
||||
sc_title:"Storm Control",sc_h:"pro Port und Verkehrsart, leer = aus",sc_bcast:"Broadcast",sc_mcast:"Multicast",
|
||||
sc_ucast:"Unbekannter Unicast",sc_umcast:"Unbekannter Multicast",sc_err:"Grenzwert muss 1-1048575 pps oder 1-10000000 kbit/s betragen",
|
||||
sc_note:"Pakete einer Verkehrsart über ihrem Grenzwert werden beim Eintritt in den Switch verworfen.",
|
||||
sy_network:"Netzwerk",sy_dhcp:"DHCP verwenden",sy_dhcp_t:"Adresse per DHCP beziehen",sy_services:"Dienste",
|
||||
sy_igmp:"IGMP Snooping",sy_sysip:"Server-IP",sy_server:"Server",sy_port:"Port",
|
||||
sy_sesstmo:"Sitzungs-Timeout (s)",sy_sesstmo_err:"Sitzungs-Timeout muss zwischen 1 und 65535 s liegen",
|
||||
sy_services_note:"Der Dienststatus entspricht der Startkonfiguration; der laufende Zustand ist nicht auslesbar.",
|
||||
sy_password:"Admin-Passwort",sy_newpw:"Neues Passwort",sy_repeat:"Wiederholen",sy_pwapply:"Passwort ändern",
|
||||
sy_pw_note:"Wirkt sofort; im Flash speichern, damit es nach einem Neustart erhalten bleibt.",sy_console:"Konsole",
|
||||
sy_cmd:"CLI-Befehl...",sy_send:"Senden",sy_startup:"Startkonfiguration",sy_replayed:"wird bei jedem Start ausgeführt",
|
||||
sy_reload:"Aus dem Flash neu laden",sy_write:"In den Flash schreiben",sy_unknown_note:"Unbekannte Zeilen werden vor dem Schreiben hervorgehoben.",
|
||||
sy_maint:"Wartung",sy_reboot:"Switch neu starten",sy_lang:"Sprache",
|
||||
sy_ip_err:"Ungültige IP / Netzmaske / Gateway",sy_host_err:"Hostname: 1-23 druckbare Zeichen, keine Leerzeichen oder Anführungszeichen",
|
||||
sy_net_q:"Netzwerkeinstellungen übernehmen?",sy_net_d:"Die Management-IP ändert sich auf {ip}: Diese Seite muss dort neu geöffnet werden.",
|
||||
sy_ip_changed:"IP geändert, neu verbinden unter http://{ip}/",sy_dhcp_q:"Auf DHCP umstellen?",
|
||||
sy_dhcp_d:"Der Switch bezieht seine Adresse per DHCP. Du musst seine neue IP herausfinden, um dich wieder zu verbinden.",
|
||||
sy_sysip_err:"Ungültige IP des Syslog-Servers",sy_sysport_err:"Syslog-Port muss zwischen 1 und 65535 liegen",
|
||||
sy_pw_len:"Passwort: 1-20 Zeichen",sy_pw_space:"Das Passwort darf keine Leerzeichen enthalten",sy_pw_match:"Die Passwörter stimmen nicht überein",
|
||||
sy_pw_q:"Admin-Passwort ändern?",sy_pw_d:"Gilt sofort für neue Anmeldungen. Im Flash speichern, damit es erhalten bleibt.",
|
||||
sy_reboot_q:"Switch neu starten?",sy_reboot_d:"Es gibt UNGESPEICHERTE Änderungen, sie gehen verloren. Zuerst im Flash speichern, wenn du sie behalten willst.",
|
||||
sy_rebooting:"Neustart läuft, in etwa 20 s neu verbinden",sy_bytes:"Bytes",
|
||||
cw_title:"Diese Startkonfiguration schreiben?",cw_save_title:"Laufende Konfiguration im Flash speichern?",
|
||||
cw_info:"{n} / 2048 Bytes, wird bei jedem Start Zeile für Zeile ausgeführt",
|
||||
cw_toolarge:"Zu gross: Der Konfigurationssektor fasst höchstens 2048 Bytes. Zuerst Zeilen entfernen.",
|
||||
cw_longline:"Zeile {n} ist {m} Bytes lang: Der Switch kann beim Start nur Zeilen bis 126 Bytes ausführen und würde sie überspringen, deshalb wird das Schreiben abgelehnt. Zuerst kürzen.",
|
||||
cw_unknown:"Nicht in der bekannten Konfigurationssyntax (wird trotzdem geschrieben): ",cw_empty:"(leer)",
|
||||
cw_writing:"Konfiguration wird geschrieben...",cw_failed:"Schreiben der Konfiguration fehlgeschlagen: HTTP {n}",
|
||||
cw_verify_fail:"Prüfung fehlgeschlagen: Der Flash-Inhalt weicht vom Gesendeten ab. Befehlsprotokoll wurde NICHT gelöscht.",
|
||||
cw_saved:"Startkonfiguration gespeichert und geprüft",cw_collect:"Laufende Änderungen werden gesammelt...",
|
||||
t_applied:"Übernommen: {c}",t_cmds:"{n} Befehl(e) übernommen",t_rejected:"Befehl abgelehnt: {c}",t_failed:"fehlgeschlagen: {c}",
|
||||
fw_title:"Firmware-Update",
|
||||
fw_intro:"Ein RTLPlayground-Image hochladen (.bin, 512 KiB). Das Image wird im Flash abgelegt und per CRC geprüft; ist es in Ordnung, startet der Switch neu, prüft das Image erneut und übernimmt es. Die Startkonfiguration bleibt erhalten.",
|
||||
fw_upload:"Hochladen",fw_checking:"{f}: {n} Bytes. Wird geprüft...",fw_size_err:"Grösse ist {n}, erwartet 524288 (512 KiB)",
|
||||
fw_magic_err:"Bank-Header / LJMP-Kennung fehlt: kein Firmware-Image",fw_crc_err:"CRC16-Prüfung fehlgeschlagen: Image beschädigt",
|
||||
fw_valid:"gültiges RTLPlayground-Image (Grösse, Kennung und CRC16 in Ordnung)",fw_q:"Firmware hochladen?",
|
||||
fw_d:"Ist die Prüfsumme korrekt, startet der Switch neu und übernimmt das Image beim Hochfahren (die Startkonfiguration bleibt erhalten). Nicht vom Strom trennen, bis er wieder erreichbar ist.",
|
||||
fw_finishing:"Flash wird fertig beschrieben... {s} s",fw_uploading:"wird hochgeladen... {p}% / {s} s",
|
||||
fw_verified:"Prüfsumme bestätigt, der Switch startet neu...",
|
||||
fw_rejected:"der Switch hat das Image abgelehnt (falsche Prüfsumme), es wurde nichts übernommen",
|
||||
fw_lost:"Hochladen fehlgeschlagen: Verbindung während der Übertragung abgebrochen",
|
||||
fw_noreboot:"kein Neustart erkannt: Das Image wurde sehr wahrscheinlich abgelehnt. Bei einem Update von alter Firmware nach dem erneuten Anmelden die Version in der Seitenleiste prüfen.",
|
||||
fw_applied:"Update übernommen",fw_done_t:"Firmware aktualisiert",
|
||||
fw_done:"Der Switch hat das Image geprüft und damit neu gestartet. Die Sitzung wurde zurückgesetzt, du wirst erneut zur Anmeldung aufgefordert.",
|
||||
fw_login:"Zur Anmeldung",fw_rebooting:"Switch startet neu...",
|
||||
fw_timeout:"Der Switch ist nach 150 s nicht zurück: Stromversorgung / serielle Konsole prüfen"
|
||||
}
|
||||
};
|
||||
var rtlLang=(function(){
|
||||
@@ -427,6 +781,7 @@ var CONF_CMDS=[
|
||||
/^ip\s+(\d{1,3}\.){3}\d{1,3}$/,/^ip\s+dhcp$/,
|
||||
/^gw\s+(\d{1,3}\.){3}\d{1,3}$/,/^netmask\s+(\d{1,3}\.){3}\d{1,3}$/,
|
||||
/^syslog\s+(on|off)$/,/^syslog\s+ip\s+(\d{1,3}\.){3}\d{1,3}$/,/^syslog\s+port\s+\d{1,5}$/,
|
||||
/^session\s+\d{1,5}$/,
|
||||
/^passwd\s+\S+$/,/^hostname\s+\S{1,23}$/,
|
||||
/^vlan\s+\d{1,4}\s+d$/,/^vlan\s+\d{1,4}\s+mgmt$/,
|
||||
/^vlan\s+\d{1,4}(\s+[a-zA-Z]\w*)?(\s+\d{1,2}t?)+$/,
|
||||
@@ -434,7 +789,8 @@ var CONF_CMDS=[
|
||||
/^ingress(\s+\d{1,2}[tua])+$/,/^ingress\s+[tua]$/,
|
||||
/^port\s+\d{1,2}\s+(10m|100m|1g|2g5|5g|10g|auto|on|off)(\s+(half|full))?$/,
|
||||
/^port\s+\d{1,2}\s+name\s+\S+$/,
|
||||
/^eee(\s+\d{1,2})?\s+(on|off)$/,
|
||||
/^port\s+\d{1,2}\s+lldp\s+(permit|block)+$/,
|
||||
/^eee\s+(on|off)(\s+\d{1,2})?(\s+(100m|1g|2g5))?$/,
|
||||
/^mirror(\s+\d{1,2})(\s+\d{1,2}[tr]?)+$/,/^mirror\s+off$/,
|
||||
/^lag\s+[1-4](\s+\d{1,2})+$/,/^lag\s+[1-4]\s+d$/,/^laghash\s+[1-4](\s+\w+)+$/,
|
||||
/^isolate\s+\d{1,2}(\s+(off|\d{1,2}))+$/,
|
||||
@@ -444,8 +800,9 @@ var CONF_CMDS=[
|
||||
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+cost\s+\d{1,9}$/,/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+prio\s+\d{1,3}$/,
|
||||
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+guard\s+(none|bpdu|root)$/,/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+filter\s+(on|off)$/,
|
||||
/^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+p2p\s+(auto|on|off)$/,
|
||||
/^igmp\s+(on|off)$/,/^mtu\s+\d{1,2}\s+\d+$/,
|
||||
/^igmp\s+(on|off)$/,/^mtu\s+\d{1,2}\s+\d+$/,/^lldp\s+(on|off)$/,
|
||||
/^bw\s+(in|out)\s+\d{1,2}\s+\S+$/,
|
||||
/^storm\s+\d{1,2}\s+(bcast|mcast|ucast|umcast)\s+(off|\d{1,8}\s+(pps|kbps))$/,
|
||||
];
|
||||
function isConfCmd(line){
|
||||
for(var i=0;i<CONF_CMDS.length;i++)if(CONF_CMDS[i].test(line))return true;
|
||||
@@ -503,7 +860,9 @@ var TABS=[
|
||||
{id:"vlan", icon:"M12 3v6M12 9l-7 5M12 9l7 5M5 14v5M19 14v5M3 21h4M17 21h4"},
|
||||
{id:"l2", icon:"M4 5h16M4 12h16M4 19h10"},
|
||||
{id:"mirror",icon:"M12 3v18M7 8l-4 4 4 4M17 8l4 4-4 4"},
|
||||
{id:"isolate",icon:"M4 4h6v6H4zM14 14h6v6h-6zM14 4h6v6h-6zM4 14h6v6H4z"},
|
||||
{id:"lag", icon:"M7 8a4 4 0 100 8h3M17 8a4 4 0 110 8h-3M9 12h6"},
|
||||
{id:"lldp", icon:"M11 12a1 1 0 002 0 1 1 0 00-2 0M8.5 8.5a5 5 0 000 7M15.5 8.5a5 5 0 010 7M5.6 5.6a9 9 0 000 12.8M18.4 5.6a9 9 0 010 12.8"},
|
||||
{id:"eee", icon:"M13 2L4 14h6l-1 8 9-12h-6z"},
|
||||
{id:"bw", icon:"M4 18a8 8 0 0116 0M12 18l4-6"},
|
||||
{id:"system",icon:"M12 8a4 4 0 100 8 4 4 0 000-8zM4 12h2M18 12h2M12 4v2M12 18v2M6 6l1.5 1.5M16.5 16.5L18 18M18 6l-1.5 1.5M7.5 16.5L6 18"},
|
||||
@@ -533,13 +892,18 @@ TABS.forEach(function(tb){
|
||||
});
|
||||
$("burger").addEventListener("click",function(){$("nav").classList.toggle("open")});
|
||||
|
||||
var IDLE_STOP_MS=600000,lastInput=Date.now();
|
||||
["mousemove","mousedown","keydown","touchstart","wheel"].forEach(function(ev){
|
||||
addEventListener(ev,function(){lastInput=Date.now()},{passive:true});
|
||||
});
|
||||
function Poller(fn,ms){this.fn=fn;this.ms=ms;this.on=false;this.t=null}
|
||||
Poller.prototype.start=function(){if(this.on)return;this.on=true;this.tick()};
|
||||
Poller.prototype.stop=function(){this.on=false;clearTimeout(this.t)};
|
||||
Poller.prototype.tick=function(){
|
||||
var self=this;
|
||||
if(!self.on)return;
|
||||
var run=document.hidden?Promise.resolve():Promise.resolve().then(self.fn).catch(function(){});
|
||||
var quiet=document.hidden||Date.now()-lastInput>IDLE_STOP_MS;
|
||||
var run=quiet?Promise.resolve():Promise.resolve().then(self.fn).catch(function(){});
|
||||
run.then(function(){ if(self.on)self.t=setTimeout(function(){self.tick()},self.ms); });
|
||||
};
|
||||
|
||||
@@ -680,7 +1044,7 @@ function portDetail(i){
|
||||
function renderInfo(){
|
||||
var m=[["i_host","hostname"],["i_ip","ip_address"],["i_mask","ip_netmask"],
|
||||
["i_gw","ip_gateway"],["i_mac","mac_address"],["i_fw","sw_ver"],["i_built","build_date"],
|
||||
["i_hw","hw_ver"],["i_flash","flash_size"],["i_syslog","syslog_server"]];
|
||||
["i_hw","hw_ver"],["i_temp","chip_temp"],["i_flash","flash_size"],["i_syslog","syslog_server"]];
|
||||
var tb=$("sysinfo");tb.innerHTML="";
|
||||
m.forEach(function(r){
|
||||
var v=S.info[r[1]];
|
||||
@@ -723,6 +1087,7 @@ tabHooks.dash={
|
||||
var SPEEDS=[["auto","c_auto"],["2g5","2.5G"],["1g","1G"],["100m full","100M full"],
|
||||
["100m half","100M half"],["10m full","10M full"],["10m half","10M half"]];
|
||||
var SFPRATES=[["auto","c_auto"],["10g","10G"],["2g5","2.5G"],["1g","1G"],["100m","100M"]];
|
||||
var ADVSEL={63:"auto",31:"auto",32:"2g5",16:"1g",8:"100m full",4:"100m half",2:"10m full",1:"10m half"};
|
||||
function speedLabel(s){
|
||||
if(s==="c_auto")return t("c_auto");
|
||||
return s.replace(" full"," "+t("c_full")).replace(" half"," "+t("c_half"));
|
||||
@@ -785,6 +1150,8 @@ function portsStatus(){
|
||||
S.ports.forEach(function(p){
|
||||
var i=p.portNum-1,el=$("plink"+i);
|
||||
if(el)el.innerHTML=linkBadge(p);
|
||||
var sel=$("pspd"+i),v=p.isSFP?0:ADVSEL[parseInt(p.adv,2)];
|
||||
if(sel&&v&&document.activeElement!==sel)sel.value=v;
|
||||
});
|
||||
}
|
||||
function applyPort(i){
|
||||
@@ -1350,6 +1717,76 @@ $("moff").addEventListener("click",function(){
|
||||
});
|
||||
tabHooks.mirror={enter:function(){needPorts(function(){buildMirror();mirrorLoad().catch(function(){})})}};
|
||||
|
||||
var isoAllow=[];
|
||||
function isoBox(r,c){return $("iso"+r+"_"+c)}
|
||||
function isoMark(){
|
||||
for(var r=1;r<=S.n;r++){
|
||||
var full=true;
|
||||
for(var c=1;c<=S.n+1;c++){var b=isoBox(r,c);if(b&&!b.checked)full=false;}
|
||||
$("isoh"+r).style.color=full?"":"var(--bad)";
|
||||
}
|
||||
}
|
||||
function isoTouch(){$("isotbl").dataset.dirty="1";isoMark()}
|
||||
function isoTh(row,txt,attrs){var e=h("th",attrs);e.textContent=txt;row.appendChild(e);return e}
|
||||
function buildIso(){
|
||||
var tb=$("isotbl");
|
||||
if(tb.tBodies[0].rows.length)return;
|
||||
var h1=tb.tHead.insertRow(),h2=tb.tHead.insertRow();
|
||||
isoTh(h1,t("iso_from"),{rowspan:"2"});isoTh(h1,t("iso_to"),{colspan:String(S.n),style:"text-align:center"});isoTh(h1,"CPU",{rowspan:"2"});
|
||||
for(var c=1;c<=S.n;c++)isoTh(h2,String(c),{style:"text-align:center"});
|
||||
for(var r=1;r<=S.n;r++){
|
||||
var tr=tb.tBodies[0].insertRow();
|
||||
isoTh(tr,String(r),{id:"isoh"+r});
|
||||
for(c=1;c<=S.n+1;c++){
|
||||
var td=tr.insertCell();
|
||||
td.style.textAlign="center";
|
||||
if(r===c){td.className="mut";td.textContent="\u2022";continue;}
|
||||
td.appendChild(h("input",{type:"checkbox",id:"iso"+r+"_"+c,onchange:isoTouch}));
|
||||
}
|
||||
}
|
||||
}
|
||||
function isoLoad(){
|
||||
return getJSON("/isolation.json").then(function(s){
|
||||
isoAllow=s;
|
||||
if($("isotbl").dataset.dirty)return;
|
||||
s.forEach(function(e){
|
||||
var m=parseInt(e.allow,16);
|
||||
for(var c=1;c<=S.n;c++){var b=isoBox(e.portNum,c);if(b)b.checked=!!((m>>S.physToLog[c-1])&1);}
|
||||
var cpu=isoBox(e.portNum,S.n+1);
|
||||
if(cpu)cpu.checked=!!(m&0x200);
|
||||
});
|
||||
isoMark();
|
||||
});
|
||||
}
|
||||
function isoMask(r){
|
||||
var m=0;
|
||||
for(var c=1;c<=S.n;c++){var b=isoBox(r,c);if(r===c||(b&&b.checked))m|=1<<S.physToLog[c-1];}
|
||||
var cpu=isoBox(r,S.n+1);
|
||||
if(cpu&&cpu.checked)m|=0x200;
|
||||
return m;
|
||||
}
|
||||
$("isoapply").addEventListener("click",function(){
|
||||
var cmds=[];
|
||||
for(var r=1;r<=S.n;r++){
|
||||
var cur=-1;
|
||||
isoAllow.forEach(function(e){if(e.portNum===r)cur=parseInt(e.allow,16)});
|
||||
if(isoMask(r)===cur)continue;
|
||||
var cmd="isolate "+r;
|
||||
for(var c=1;c<=S.n;c++){var b=isoBox(r,c);if(r===c||(b&&b.checked))cmd+=" "+c;}
|
||||
var cpu=isoBox(r,S.n+1);
|
||||
if(cpu&&cpu.checked)cmd+=" 0";
|
||||
cmds.push(cmd);
|
||||
}
|
||||
delete $("isotbl").dataset.dirty;
|
||||
if(!cmds.length){isoLoad().catch(function(){});return;}
|
||||
postCmds(cmds).then(isoLoad).catch(function(){});
|
||||
});
|
||||
$("isoall").addEventListener("click",function(){
|
||||
for(var r=1;r<=S.n;r++)for(var c=1;c<=S.n+1;c++){var b=isoBox(r,c);if(b)b.checked=true;}
|
||||
isoTouch();
|
||||
});
|
||||
tabHooks.isolate={enter:function(){needPorts(function(){buildIso();isoLoad().catch(function(){})})}};
|
||||
|
||||
var HASHF=["spa","smac","dmac","sip","dip","sport","dport"];
|
||||
function buildLag(){
|
||||
var w=$("lagwrap");
|
||||
@@ -1401,6 +1838,32 @@ function lagApply(g){
|
||||
}
|
||||
tabHooks.lag={enter:function(){needPorts(function(){buildLag();lagLoad().catch(function(){})})}};
|
||||
|
||||
|
||||
function lldpLoad(){
|
||||
return getJSON("/lldp.json").then(function(s){
|
||||
$("lldp_en").checked=s.on;
|
||||
var tb=$("lldp_table").tBodies[0];tb.innerHTML="";
|
||||
byPort(s.portStatus).forEach(function(p){
|
||||
var tr=tb.insertRow();
|
||||
tr.insertCell().textContent=p.portNum;
|
||||
tr.insertCell().textContent=p.name;
|
||||
var sw=h("label",{class:"switch"},[
|
||||
h("input",{type:"checkbox",onchange:function(){
|
||||
postCmd("port "+p.portNum+" lldp "+(this.checked?"permit":"block"))
|
||||
.then(function(){setTimeout(lldpLoad,300)}).catch(function(){});
|
||||
}}),h("i")]);
|
||||
sw.firstChild.checked=p.permitted;
|
||||
tr.insertCell().appendChild(sw);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$("lldp_en").addEventListener("change",function(){
|
||||
var el=this;
|
||||
postCmd("lldp "+(el.checked?"on":"off")).catch(function(){el.checked=!el.checked});
|
||||
});
|
||||
tabHooks.lldp={enter:lldpLoad};
|
||||
|
||||
function eeeFlags(bits){
|
||||
var b=parseInt(bits,2);
|
||||
return["100M","1G","2.5G"].map(function(s,i){
|
||||
@@ -1424,7 +1887,7 @@ function eeeLoad(){
|
||||
var on=parseInt(p.eee,2)!==0;
|
||||
var sw=h("label",{class:"switch"},[
|
||||
h("input",{type:"checkbox",onchange:function(){
|
||||
postCmd("eee "+p.portNum+" "+(this.checked?"on":"off"))
|
||||
postCmd("eee "+(this.checked?"on":"off")+" "+p.portNum)
|
||||
.then(function(){setTimeout(eeeLoad,300)}).catch(function(){});
|
||||
}}),h("i")]);
|
||||
sw.firstChild.checked=on;
|
||||
@@ -1486,7 +1949,61 @@ function bwApply(n){
|
||||
}else cmds.push("bw out "+n+" off");
|
||||
postCmds(cmds).then(bwLoad).catch(function(){});
|
||||
}
|
||||
tabHooks.bw={enter:function(){needPorts(function(){bwLoad().catch(function(){})})}};
|
||||
var SC_TYPES=["bcast","mcast","ucast","umcast"],scSig="";
|
||||
function scLoad(){
|
||||
return getJSON("/storm.json").then(function(s){
|
||||
var tb=$("sctable").tBodies[0];
|
||||
byPort(s);
|
||||
var sig=s.map(function(p){return p.portNum}).join();
|
||||
if(sig!==scSig){
|
||||
scSig=sig;tb.innerHTML="";
|
||||
s.forEach(function(p){
|
||||
var n=p.portNum,tr=tb.insertRow();
|
||||
tr.id="scr"+n;
|
||||
tr.addEventListener("input",function(){tr.dataset.dirty="1"});
|
||||
tr.addEventListener("change",function(){tr.dataset.dirty="1"});
|
||||
tr.insertCell().textContent=n;
|
||||
SC_TYPES.forEach(function(ty){
|
||||
tr.insertCell().appendChild(h("span",{style:"display:flex;gap:4px"},[
|
||||
h("input",{class:"in sm",id:"scv"+ty+n,type:"number",min:"1",step:"1"}),
|
||||
h("select",{class:"in",id:"scu"+ty+n},[
|
||||
h("option",{value:"pps",text:"pps"}),
|
||||
h("option",{value:"kbps",text:"kbit/s"}),
|
||||
]),
|
||||
]));
|
||||
});
|
||||
tr.insertCell().appendChild(h("button",{class:"ctl",text:t("c_apply"),onclick:function(){scApply(n)}}));
|
||||
});
|
||||
}
|
||||
s.forEach(function(p){
|
||||
var n=p.portNum;
|
||||
if($("scr"+n).dataset.dirty)return;
|
||||
SC_TYPES.forEach(function(ty,k){
|
||||
var on=p.en.charAt(k)==="1",pps=p.pps.charAt(k)==="1",raw=parseInt(p.rate.substr(k*6,6),16);
|
||||
var inp=$("scv"+ty+n),sel=$("scu"+ty+n);
|
||||
inp.value=on?raw:"";
|
||||
sel.value=on&&!pps?"kbps":"pps";
|
||||
inp.dataset.cur=on?inp.value+" "+sel.value:"off";
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
function scApply(n){
|
||||
var cmds=[];
|
||||
for(var k=0;k<SC_TYPES.length;k++){
|
||||
var ty=SC_TYPES[k],inp=$("scv"+ty+n),u=$("scu"+ty+n).value,v=inp.value.trim(),want="off";
|
||||
if(v!==""&&v!=="0"){
|
||||
var x=Number(v);
|
||||
if(!Number.isInteger(x)||x<1||(u==="pps"&&x>1048575)||(u==="kbps"&&x>10000000)){toast(t("sc_err"),"err");return;}
|
||||
want=x+" "+u;
|
||||
}
|
||||
if(want!==inp.dataset.cur)cmds.push("storm "+n+" "+ty+" "+want);
|
||||
}
|
||||
delete $("scr"+n).dataset.dirty;
|
||||
if(!cmds.length)return;
|
||||
postCmds(cmds).then(scLoad).catch(function(){});
|
||||
}
|
||||
tabHooks.bw={enter:function(){needPorts(function(){bwLoad().then(scLoad).catch(function(){})})}};
|
||||
|
||||
var IPRE=/^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
function okIp(s){
|
||||
@@ -1502,6 +2019,7 @@ function sysLoad(){
|
||||
var sl=(S.info.syslog_server||"").split(":");
|
||||
if(sl[0]&&sl[0]!=="0.0.0.0")$("sy-sysip").value=sl[0];
|
||||
if(sl[1])$("sy-sysport").value=sl[1];
|
||||
if(S.info.session_timeout)$("sy-sesstmo").value=S.info.session_timeout;
|
||||
}).catch(function(){});
|
||||
cfgReload();
|
||||
}
|
||||
@@ -1526,7 +2044,7 @@ $("sy-apply").addEventListener("click",function(){
|
||||
if(!/^[\x21-\x7e]{1,23}$/.test(hn)||/["\\]/.test(hn)){toast(t("sy_host_err"),"err");return;}
|
||||
cmds.push("hostname "+hn);
|
||||
}
|
||||
cmds.push("ip "+ip,"netmask "+mask,"gw "+gw);
|
||||
cmds.push("ip "+ip+"\nnetmask "+mask+"\ngw "+gw);
|
||||
var changingIp=ip!==S.info.ip_address;
|
||||
confirmModal(t("sy_net_q"),changingIp?t("sy_net_d",{ip:ip}):"",function(){
|
||||
postCmds(cmds).then(function(){
|
||||
@@ -1554,6 +2072,11 @@ $("sy-syslog").addEventListener("change",function(){
|
||||
}else cmds.push("syslog off");
|
||||
postCmds(cmds).catch(function(){});
|
||||
});
|
||||
$("sy-sesstmo").addEventListener("change",function(){
|
||||
var v=+this.value;
|
||||
if(!(v>=1&&v<=65535)){toast(t("sy_sesstmo_err"),"err");sysLoad();return;}
|
||||
postCmd("session "+v).catch(function(){sysLoad()});
|
||||
});
|
||||
$("sy-pwapply").addEventListener("click",function(){
|
||||
var a=$("sy-pw1").value,b=$("sy-pw2").value;
|
||||
if(a.length<1||a.length>20){toast(t("sy_pw_len"),"err");return;}
|
||||
@@ -1596,11 +2119,16 @@ function cfgReload(){
|
||||
cfgParseKnown(x);
|
||||
}).catch(function(){});
|
||||
}
|
||||
function cfgLongLine(v){
|
||||
var ls=v.split("\n");
|
||||
for(var i=0;i<ls.length;i++){var n=new Blob([ls[i]]).size;if(n>126)return{n:i+1,m:n};}
|
||||
return null;
|
||||
}
|
||||
function cfgBytes(){
|
||||
var n=new Blob([$("cfgedit").value]).size;
|
||||
var v=$("cfgedit").value,n=new Blob([v]).size;
|
||||
var el=$("cfgbytes");
|
||||
el.textContent=n+" / 2048 "+t("sy_bytes");
|
||||
el.style.color=n>2048?"var(--bad)":"";
|
||||
el.style.color=(n>2048||cfgLongLine(v))?"var(--bad)":"";
|
||||
return n;
|
||||
}
|
||||
$("cfgedit").addEventListener("input",cfgBytes);
|
||||
@@ -1612,15 +2140,15 @@ tabHooks.system={enter:sysLoad};
|
||||
|
||||
var CONF_OVERWRITE=[
|
||||
/^ip\b/,/^gw\b/,/^netmask\b/,/^hostname\b/,
|
||||
/^syslog\s+ip\b/,/^syslog\s+port\b/,/^passwd\b/,
|
||||
/^syslog\s+ip\b/,/^syslog\s+port\b/,/^passwd\b/,/^session\b/,
|
||||
/^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/,
|
||||
/^pvid\s+\d{1,2}\b/,/^ingress\b/,
|
||||
/^pvid\s+\d{1,2}\b/,
|
||||
/^port\s+\d{1,2}(?!\s+name\b)/,/^port\s+\d{1,2}\s+name\b/,
|
||||
/^eee\s+\d{1,2}\b/,/^eee\b/,/^mirror\b/,
|
||||
/^mirror\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+(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/,
|
||||
/^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)$/,/^(stp)\s+(on|off)$/,/^(stp\s+(port\s+\d{1,2}|lag\s+[1-4]))\s+(on|off)$/];
|
||||
function mergeConf(base,texts){
|
||||
@@ -1633,8 +2161,28 @@ function mergeConf(base,texts){
|
||||
var m;
|
||||
if((m=line.match(/^vlan (\d{1,4}) d$/))){drop(new RegExp("^vlan "+m[1]+"( |$)"));return;}
|
||||
if((m=line.match(/^lag (\d) d$/))){drop(new RegExp("^lag(hash)? "+m[1]+"( |$)"));return;}
|
||||
if((m=line.match(/^eee (on|off)(?: (\d{1,2}))?(?: (?:100m|1g|2g5))?$/))){
|
||||
if(m[2])drop(new RegExp("^eee (on|off) "+m[2]+"\\b"));
|
||||
else drop(/^eee /);
|
||||
conf.push(line);return;
|
||||
}
|
||||
if(line==="mirror off"){drop(/^mirror /);return;}
|
||||
if(!isConfCmd(line))return;
|
||||
if((m=line.match(/^ingress (.+)$/))){
|
||||
if(/^[tua]$/.test(m[1])){drop(/^ingress /);conf.push(line);return;}
|
||||
var ports={},order=[],last=-1;
|
||||
conf.forEach(function(c,i){if(/^ingress [tua]$/.test(c))last=i;});
|
||||
conf.forEach(function(c,i){
|
||||
var cm=c.match(/^ingress (.+)$/);
|
||||
if(!cm||/^[tua]$/.test(cm[1])||i<last)return;
|
||||
cm[1].split(" ").forEach(function(tk){var n=tk.slice(0,-1);if(!(n in ports))order.push(n);ports[n]=tk;});
|
||||
});
|
||||
m[1].split(" ").forEach(function(tk){var n=tk.slice(0,-1);if(!(n in ports))order.push(n);ports[n]=tk;});
|
||||
conf=conf.filter(function(c){var cm=c.match(/^ingress (.+)$/);return!cm||/^[tua]$/.test(cm[1])});
|
||||
order.sort(function(a,b){return a-b});
|
||||
conf.push("ingress "+order.map(function(n){return ports[n]}).join(" "));
|
||||
return;
|
||||
}
|
||||
if((m=line.match(/^bw (in|out) (\d{1,2}) (\S+)$/))){
|
||||
var pre="^bw "+m[1]+" "+m[2]+" ";
|
||||
if(m[1]==="out"||m[3]==="off")drop(new RegExp(pre));
|
||||
@@ -1662,18 +2210,18 @@ function mergeConf(base,texts){
|
||||
});
|
||||
return conf;
|
||||
}
|
||||
function writeConfig(txt,title){
|
||||
function writeConfig(txt,title,fromLog){
|
||||
var info=h("p",{class:"small mut"}),warn=h("p",{class:"small"});
|
||||
var ed=h("textarea",{class:"cfg",spellcheck:"false",placeholder:t("cw_empty"),style:"min-height:45vh"});
|
||||
ed.value=txt.replace(/\r\n/g,"\n");
|
||||
var ok=h("button",{class:"ctl pri",text:t("sy_write"),onclick:function(){closeModal();doWriteConfig(cfgText(ed.value))}});
|
||||
var ok=h("button",{class:"ctl pri",text:t("sy_write"),onclick:function(){closeModal();doWriteConfig(cfgText(ed.value),fromLog)}});
|
||||
function refresh(){
|
||||
var v=cfgText(ed.value),bytes=new Blob([v]).size;
|
||||
var v=cfgText(ed.value),bytes=new Blob([v]).size,long=cfgLongLine(v);
|
||||
var unknown=v.split("\n").filter(function(l){return l.trim()&&!isConfCmd(l.trim().replace(/\s+/g," "))});
|
||||
info.textContent=t("cw_info",{n:bytes});
|
||||
ok.disabled=bytes>2048;
|
||||
ok.disabled=bytes>2048||!!long;
|
||||
warn.style.color=ok.disabled?"var(--bad)":"var(--warn)";
|
||||
warn.textContent=ok.disabled?t("cw_toolarge"):(unknown.length?t("cw_unknown")+unknown.join(" | "):"");
|
||||
warn.textContent=bytes>2048?t("cw_toolarge"):long?t("cw_longline",long):(unknown.length?t("cw_unknown")+unknown.join(" | "):"");
|
||||
}
|
||||
ed.addEventListener("input",refresh);refresh();
|
||||
modal(title,h("div",null,[info,warn,ed]),[h("button",{class:"ctl",text:t("c_cancel"),onclick:closeModal}),ok]);
|
||||
@@ -1682,7 +2230,7 @@ function cfgText(txt){
|
||||
txt=txt.replace(/\r\n/g,"\n");
|
||||
return txt&&txt.slice(-1)!=="\n"?txt+"\n":txt;
|
||||
}
|
||||
function doWriteConfig(txt){
|
||||
function doWriteConfig(txt,fromLog){
|
||||
var form=new FormData();
|
||||
form.append("configuration",new Blob([txt],{type:"application/octet-stream"}),"config.txt");
|
||||
toast(t("cw_writing"));
|
||||
@@ -1692,9 +2240,10 @@ function doWriteConfig(txt){
|
||||
}).then(function(back){
|
||||
back=back.replace(/\0[\s\S]*$/,"").replace(/\r\n/g,"\n").trim();
|
||||
if(back!==txt.trim())throw new Error(t("cw_verify_fail"));
|
||||
return api("/cmd_log_clear").catch(function(){});
|
||||
}).then(function(){
|
||||
setDirty(false);
|
||||
if(!fromLog)return false;
|
||||
return api("/cmd_log_clear").then(function(){return true},function(){return true});
|
||||
}).then(function(cleared){
|
||||
if(cleared)setDirty(false);
|
||||
$("cfgedit").value=txt;cfgBytes();cfgParseKnown(txt);
|
||||
toast(t("cw_saved"),"ok");
|
||||
}).catch(function(e){toast(e.message||String(e),"err")});
|
||||
@@ -1705,9 +2254,9 @@ $("saveBtn").addEventListener("click",function(){
|
||||
getText("/config").catch(function(){return""}),
|
||||
getText("/cmd_log").catch(function(){return""}),
|
||||
]).then(function(r){
|
||||
var cur=r[0].replace(/\0[\s\S]*$/,"");
|
||||
var merged=mergeConf([],[cur,r[1].replace(/\0[\s\S]*$/,"")]);
|
||||
writeConfig(merged.join("\n"),t("cw_save_title"));
|
||||
var cur=r[0].replace(/\0[\s\S]*$/,"").split(/\r?\n/).map(function(l){return l.trim().replace(/\s+/g," ")}).filter(Boolean);
|
||||
var merged=mergeConf(cur,[r[1].replace(/\0[\s\S]*$/,"")]);
|
||||
writeConfig(merged.join("\n"),t("cw_save_title"),true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -331,6 +331,29 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-lldp">
|
||||
<div class="card"><h2 data-i18n="lldp_title">LLDP</h2>
|
||||
<label class="row"><span class="lb" data-i18n="lldp_enabled">Enabled</span>
|
||||
<span class="switch"><input type="checkbox" id="lldp_en"><i></i></span>
|
||||
</label>
|
||||
<div class="scrollx"><table class="t" id="lldp_table">
|
||||
<thead><tr><th data-i18n="c_port">Port Number</th><th data-i18n="lldp_portname">Name</th><th data-i18n="lldp_enable">Send Frames</th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-isolate">
|
||||
<div class="card"><h2 data-i18n="iso_title">Port isolation</h2>
|
||||
<p class="small mut" style="margin-bottom:10px" data-i18n="iso_intro">A frame entering a port may only leave through the ports ticked in its row.</p>
|
||||
<div class="scrollx"><table class="t" id="isotbl" style="width:auto"><thead></thead><tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:6px" data-i18n="iso_legend">The cell of the port itself is always allowed.</p>
|
||||
<div style="display:flex;gap:12px;margin-top:10px">
|
||||
<button class="ctl pri" id="isoapply" data-i18n="c_apply">Apply</button>
|
||||
<button class="ctl" id="isoall" data-i18n="iso_all">Allow all</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-lag">
|
||||
<div id="lagwrap" class="grid2"></div>
|
||||
<p class="small mut" style="margin-top:10px" data-i18n="lag_note">A LAG needs at least one member to be saved in the startup config; applying an empty group clears it.</p>
|
||||
@@ -351,6 +374,12 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="bw_in">Ingress limit</th><th>Mbit/s</th><th data-i18n="bw_exceed">When exceeded</th><th data-i18n="bw_out">Egress limit</th><th>Mbit/s</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
</div>
|
||||
<div class="card"><h2><span data-i18n="sc_title">Storm control</span> <span class="hint" data-i18n="sc_h">per port and traffic type, empty = off</span></h2>
|
||||
<div class="scrollx"><table class="t" id="sctable">
|
||||
<thead><tr><th data-i18n="c_port">Port</th><th data-i18n="sc_bcast">Broadcast</th><th data-i18n="sc_mcast">Multicast</th><th data-i18n="sc_ucast">Unknown unicast</th><th data-i18n="sc_umcast">Unknown multicast</th><th></th></tr></thead>
|
||||
<tbody></tbody></table></div>
|
||||
<p class="small mut" style="margin-top:8px" data-i18n="sc_note">Frames of a type above its limit are dropped where they enter the switch.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="tab" id="tab-system">
|
||||
@@ -375,6 +404,8 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
<input class="in" id="sy-sysip" style="flex:1;min-width:0;width:0" data-i18n-p="sy_sysip">
|
||||
<span class="small mut" data-i18n="sy_port">Port</span>
|
||||
<input class="in" id="sy-sysport" style="width:64px" type="number" min="1" max="65535"></div>
|
||||
<label class="row" style="justify-content:space-between"><span data-i18n="sy_sesstmo">Session timeout (s)</span>
|
||||
<input class="in" id="sy-sesstmo" style="width:80px" type="number" min="1" max="65535"></label>
|
||||
<p class="small mut" data-i18n="sy_services_note">Service state reflects the startup config; runtime state is not readable.</p>
|
||||
</div>
|
||||
<div class="card"><h2 data-i18n="sy_password">Admin password</h2>
|
||||
@@ -393,9 +424,13 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}
|
||||
<div class="card"><h2 data-i18n="sy_display">Display</h2>
|
||||
<label class="row"><span class="lb" data-i18n="sy_lang">Language</span>
|
||||
<select class="in" id="langSel">
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="en">English</option>
|
||||
<option value="es">Español</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="ja">日本語</option>
|
||||
<option value="zh">中文</option>
|
||||
|
||||
</select></label>
|
||||
<label class="row"><span class="lb" data-i18n="sy_theme">Theme</span>
|
||||
<select class="in" id="themeSel">
|
||||
|
||||
@@ -81,9 +81,12 @@ button:hover{filter:brightness(1.1)}
|
||||
<script>
|
||||
(function(){
|
||||
var L={
|
||||
de:["Switch-Anmeldung","RTLPlayground-Verwaltungsoberfläche","Passwort","Anmelden","Falsches Passwort, bitte erneut versuchen."],
|
||||
en:["Switch Login","RTLPlayground management interface","Password","Sign in","Wrong password, try again."],
|
||||
ja:["スイッチ ログイン","RTLPlayground 管理インターフェース","パスワード","ログイン","パスワードが違います。もう一度お試しください。"],
|
||||
zh:["交换机登录","RTLPlayground 管理界面","密码","登录","密码错误,请重试。"]
|
||||
zh:["交换机登录","RTLPlayground 管理界面","密码","登录","密码错误,请重试。"],
|
||||
es:["Inicio de sesión del switch","Interfaz de gestión de RTLPlayground","Contraseña","Iniciar sesión","Contraseña incorrecta, inténtalo de nuevo."],
|
||||
fr:["Utilisateur du commutateur","Interface de management RTLPlayground","Mot de passe","Se connecter","Mot de passe erronné, essayez à nouveau."]
|
||||
};
|
||||
var l=null;
|
||||
try{l=localStorage.getItem("rtl_lang");}catch(e){}
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
#include "debug.h"
|
||||
|
||||
#define SESSION_ID_LENGTH 12
|
||||
#define SESSION_TIMEOUT 200
|
||||
#define SESSION_TIMEOUT_DEFAULT 200
|
||||
|
||||
/* Seconds of inactivity after which a session cookie stops validating.
|
||||
* Configurable with the "session" command, see cmd_parser.c. */
|
||||
__xdata uint16_t session_timeout = SESSION_TIMEOUT_DEFAULT;
|
||||
|
||||
#define CMARK_S 6
|
||||
|
||||
@@ -22,9 +26,9 @@
|
||||
extern volatile __xdata uint8_t sfr_data[4];
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern __xdata uint8_t cmd_capture; /* owned by rtlplayground.c, see write_char_no_syslog() */
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code struct f_data f_data[];
|
||||
extern __code char * __code mime_strings[];
|
||||
extern __code const uint8_t * __code const hex;
|
||||
extern __code const struct f_data f_data[];
|
||||
extern __code const char * __code const mime_strings[];
|
||||
extern __xdata struct flash_region_t flash_region;
|
||||
extern __xdata uint32_t flash_size;
|
||||
|
||||
@@ -37,6 +41,7 @@ __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
__xdata uint8_t entry;
|
||||
__xdata uint16_t slen;
|
||||
__xdata uint16_t o_idx;
|
||||
__xdata uint16_t sent_len;
|
||||
__xdata uint16_t len_left;
|
||||
__xdata uint16_t cont_len;
|
||||
__xdata uint32_t cont_addr;
|
||||
@@ -126,7 +131,7 @@ uint8_t find_entry(__xdata uint8_t *e)
|
||||
}
|
||||
|
||||
|
||||
bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
bool is_word(__xdata uint8_t *xdata_str_p, __code const uint8_t * __xdata code_str_p)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
@@ -148,7 +153,7 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
|
||||
|
||||
|
||||
/* name must be lower-case, starting with the '\n' of the previous line's end */
|
||||
__xdata uint8_t *header_value(__xdata uint8_t *p, __code uint8_t *name)
|
||||
__xdata uint8_t *header_value(__xdata uint8_t *p, __code const uint8_t *name)
|
||||
{
|
||||
uint8_t u, c;
|
||||
|
||||
@@ -341,14 +346,15 @@ __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
|
||||
read_reg_timer(&now);
|
||||
|
||||
if (session && session_id[0]) {
|
||||
if (now - last_session_use > SESSION_TIMEOUT) {
|
||||
if (now - last_session_use > session_timeout) {
|
||||
dbg_string("Session expired\n");
|
||||
} else {
|
||||
if (is_word_x(session, session_id)) {
|
||||
authenticated = 1;
|
||||
last_session_use = now;
|
||||
} else
|
||||
} else {
|
||||
dbg_string("Invalid session cookie!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return p;
|
||||
@@ -375,8 +381,8 @@ void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
|
||||
static uint8_t config_take(void)
|
||||
{
|
||||
// #386: needs static, otherwise it still lands in SRAM/DSEG
|
||||
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
|
||||
__xdata uint8_t cfg_bl;
|
||||
static __xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last, cfg_i;
|
||||
__xdata uint8_t cfg_bl, cfg_run;
|
||||
|
||||
cfg_bl = strlen_x(boundary);
|
||||
|
||||
@@ -418,6 +424,13 @@ static uint8_t config_take(void)
|
||||
// the payload plus its terminator must fit the sector
|
||||
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
|
||||
return 2;
|
||||
cfg_run = 0;
|
||||
for (cfg_i = cfg_body; cfg_i < cfg_end; cfg_i++) {
|
||||
if (config_buf[cfg_i] == '\n')
|
||||
cfg_run = 0;
|
||||
else if (++cfg_run >= CMD_BUF_SIZE - 1)
|
||||
return 2;
|
||||
}
|
||||
config_buf[cfg_end] = 0;
|
||||
flash_region.addr = CONFIG_START;
|
||||
flash_sector_erase();
|
||||
@@ -530,6 +543,19 @@ uint8_t stream_upload(void)
|
||||
crc16_bank1(upload_settings.p + upload_settings.bptr);
|
||||
flash_buf[write_len++] = upload_settings.p[upload_settings.bptr++];
|
||||
if (write_len >= FLASH_PAGE_SIZE) {
|
||||
/* The staged image spans FIRMWARE_UPLOAD_START to twice that,
|
||||
* the span check_and_flash_update_image() reads back. Nothing
|
||||
* else bounds uptr: a body whose closing boundary never arrives
|
||||
* keeps writing, and on a flash exactly this size the address
|
||||
* wraps onto the running image at zero. */
|
||||
if (uptr >= (uint32_t)FIRMWARE_UPLOAD_START * 2) {
|
||||
print_string("Upload runs past the image area! Aborting.\n");
|
||||
slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 30\r\n"
|
||||
"Content-Type: text/plain\r\n\r\n"
|
||||
"NO: upload exceeds image area\n");
|
||||
s->tstate = TSTATE_NONE;
|
||||
return 0;
|
||||
}
|
||||
dbg_string("len: "); dbg_short(write_len); dbg_char(' ');
|
||||
dbg_string("CRC16: "); dbg_short(crc_value); dbg_char('\n');
|
||||
if (uptr % FLASH_SECTOR_SIZE == 0) {
|
||||
@@ -559,7 +585,7 @@ static void handle_config_fragment(__xdata uint8_t *p)
|
||||
__xdata uint16_t frag_len;
|
||||
uint8_t taken;
|
||||
|
||||
frag_len = uip_len - (p - uip_appdata);
|
||||
frag_len = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Configuration too large, aborting.\n");
|
||||
config_upload = 0;
|
||||
@@ -589,7 +615,7 @@ static void handle_firmware_fragment(__xdata uint8_t *p)
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
__xdata uint16_t frag_len, payload_start;
|
||||
|
||||
frag_len = uip_len - (p - uip_appdata);
|
||||
frag_len = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||
if (pre_acc + frag_len >= CONFIG_UPLOAD_BUF) {
|
||||
print_string("Firmware upload header too large, aborting.\n");
|
||||
config_upload = 0;
|
||||
@@ -684,7 +710,7 @@ static uint8_t post_body_take(__xdata uint8_t *p)
|
||||
send_bad_request();
|
||||
return 0;
|
||||
}
|
||||
have = uip_len - (p - uip_appdata);
|
||||
have = uip_len - (p - (__xdata uint8_t *)uip_appdata);
|
||||
if (have >= content_length) {
|
||||
p[content_length] = NUL;
|
||||
return 1;
|
||||
@@ -750,6 +776,10 @@ void handle_post(void)
|
||||
return;
|
||||
}
|
||||
if (is_word(request_path, "upload")) {
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
if (flash_size < FIRMWARE_UPLOAD_START*2)
|
||||
{
|
||||
print_string("Flash too small for firmware upload!\n");
|
||||
@@ -777,7 +807,23 @@ void handle_post(void)
|
||||
dbg_string("Multipart request\n");
|
||||
}
|
||||
|
||||
if (is_word(request_path, "cmd")) {
|
||||
if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
dbg_string("POST upload/config request\n");
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
if (!boundary[0]) {
|
||||
dbg_string("Bad request, no boundary!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
if (config_upload)
|
||||
handle_config_fragment(p);
|
||||
else
|
||||
handle_firmware_fragment(p);
|
||||
return;
|
||||
} else if (is_word(request_path, "cmd")) {
|
||||
p += 4;
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
@@ -803,22 +849,6 @@ void handle_post(void)
|
||||
return;
|
||||
run_login_body(p);
|
||||
return;
|
||||
} else if (s->tstate == TSTATE_MULTIPART || is_word(request_path, "upload") || is_word(request_path, "config")) {
|
||||
dbg_string("POST upload/config request\n");
|
||||
if (!authenticated) {
|
||||
send_unauthorized();
|
||||
return;
|
||||
}
|
||||
if (!boundary[0]) {
|
||||
dbg_string("Bad request, no boundary!\n");
|
||||
send_bad_request();
|
||||
return;
|
||||
}
|
||||
if (config_upload)
|
||||
handle_config_fragment(p);
|
||||
else
|
||||
handle_firmware_fragment(p);
|
||||
return;
|
||||
} else {
|
||||
send_not_found();
|
||||
return;
|
||||
@@ -826,6 +856,13 @@ void handle_post(void)
|
||||
}
|
||||
|
||||
|
||||
static void tx_send(uint16_t len)
|
||||
{
|
||||
sent_len = len;
|
||||
uip_send(outbuf + o_idx, len);
|
||||
}
|
||||
|
||||
|
||||
void httpd_appcall(void)
|
||||
{
|
||||
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
|
||||
@@ -861,9 +898,9 @@ void httpd_appcall(void)
|
||||
}
|
||||
} else if (uip_acked() && s->tstate == TSTATE_TX) {
|
||||
dbg_string("ACK\n");
|
||||
if (slen > uip_mss()) {
|
||||
slen -= uip_mss();
|
||||
o_idx += uip_mss();
|
||||
if (slen > sent_len) {
|
||||
slen -= sent_len;
|
||||
o_idx += sent_len;
|
||||
} else {
|
||||
slen = 0;
|
||||
}
|
||||
@@ -872,11 +909,11 @@ void httpd_appcall(void)
|
||||
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
tx_send(uip_mss());
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (slen > 0) {
|
||||
dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
tx_send(slen);
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (cont_len) {
|
||||
dbg_string("CONT cont_len: "); dbg_short(cont_len);
|
||||
@@ -887,7 +924,7 @@ void httpd_appcall(void)
|
||||
flash_region.len = slen;
|
||||
flash_read_bulk(outbuf);
|
||||
o_idx = 0;
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
tx_send(slen);
|
||||
cont_len -= slen;
|
||||
cont_addr += slen;
|
||||
s->tstate = TSTATE_TX;
|
||||
@@ -898,8 +935,9 @@ void httpd_appcall(void)
|
||||
reset_chip();
|
||||
}
|
||||
} else if (uip_newdata() && s->tstate == TSTATE_POST) {
|
||||
// Check here maxupload by subtracting uip_len and close socekt if fails!
|
||||
if (max_upload - uip_len > 0) {
|
||||
if (config_upload || uip_len <= max_upload) {
|
||||
if (!config_upload)
|
||||
max_upload -= uip_len;
|
||||
upload_settings.p = uip_appdata;
|
||||
upload_settings.bptr = 0;
|
||||
upload_settings.plen = uip_len;
|
||||
@@ -978,6 +1016,8 @@ void httpd_appcall(void)
|
||||
send_eee();
|
||||
} else if (is_word(q, "/bandwidth.json")) {
|
||||
send_bandwidth();
|
||||
} else if (is_word(q, "/storm.json")) {
|
||||
send_storm();
|
||||
} else if (is_word(q, "/l2.json")) {
|
||||
parse_short(q + 13); // e.g.: /l2.json?idx=10
|
||||
send_l2(short_parsed);
|
||||
@@ -986,12 +1026,16 @@ void httpd_appcall(void)
|
||||
l2_delete(short_parsed);
|
||||
} else if (is_word(q, "/mirror.json")) {
|
||||
send_mirror();
|
||||
} else if (is_word(q, "/isolation.json")) {
|
||||
send_isolation();
|
||||
} else if (is_word(q, "/mtu.json")) {
|
||||
send_mtu();
|
||||
} else if (is_word(q, "/lag.json")) {
|
||||
send_lag();
|
||||
} else if (is_word(q, "/stp.json")) {
|
||||
send_stp();
|
||||
} else if (is_word(q, "/lldp.json")) {
|
||||
send_lldp();
|
||||
} else if (is_word(q, "/vlanlist")) {
|
||||
send_vlanlist();
|
||||
} else if (is_word(q, "/config")) {
|
||||
@@ -1045,24 +1089,20 @@ do_send:
|
||||
o_idx = 0;
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
tx_send(uip_mss());
|
||||
dbg_string("Sending a done\n");
|
||||
} else {
|
||||
dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
tx_send(slen);
|
||||
dbg_string("Sending b done\n");
|
||||
}
|
||||
s->tstate = TSTATE_TX;
|
||||
} else if (uip_rexmit()) { // Connection established, need to rexmit?
|
||||
dbg_string("RETRANSMIT requested\n");
|
||||
if (slen > uip_mss()) {
|
||||
dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, uip_mss());
|
||||
if (sent_len) {
|
||||
dbg_string("Sending C: "); dbg_short(sent_len); dbg_char('\n');
|
||||
tx_send(sent_len);
|
||||
dbg_string("Sending C done\n");
|
||||
} else if (slen > 0) {
|
||||
dbg_string("Sending D: "); dbg_short(slen); dbg_char('\n');
|
||||
uip_send(outbuf + o_idx, slen);
|
||||
dbg_string("Sending D done\n");
|
||||
}
|
||||
s->tstate = TSTATE_TX;
|
||||
uip_len = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "rtl837x_pins.h"
|
||||
@@ -28,9 +29,10 @@ extern __code const struct machine machine;
|
||||
extern __xdata uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
extern __xdata uint16_t slen;
|
||||
extern __xdata uint16_t management_vlan;
|
||||
extern __xdata uint16_t session_timeout;
|
||||
extern __xdata uint16_t cont_len;
|
||||
extern __xdata uint32_t cont_addr;
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
extern __xdata uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
@@ -47,8 +49,11 @@ extern __xdata char sfp_module_model[2][17];
|
||||
extern __xdata char sfp_module_serial[2][17];
|
||||
extern __xdata uint8_t sfp_options[2];
|
||||
|
||||
__code uint8_t * __code HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||
__code uint8_t * __code HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
||||
extern __xdata uint16_t lldp_logical_port_status;
|
||||
extern __xdata bool lldp_enabled;
|
||||
|
||||
__code const uint8_t * __code const HTTP_RESPONCE_JSON = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: application/json\r\n\r\n";
|
||||
__code const uint8_t * __code const HTTP_RESPONCE_TXT = "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n";
|
||||
|
||||
// Convert uint8_t to ascii HEX char push on html-buffer.
|
||||
void charhex_to_html(char c)
|
||||
@@ -70,6 +75,21 @@ void char_to_html(char c)
|
||||
}
|
||||
|
||||
|
||||
static void str_x_to_html(__xdata const char *s)
|
||||
{
|
||||
while (*s)
|
||||
outbuf[slen++] = *s++;
|
||||
}
|
||||
|
||||
|
||||
void json_char_to_html(uint8_t c)
|
||||
{
|
||||
if (c < 0x20 || c > 0x7e || c == '"' || c == '\\')
|
||||
c = '.';
|
||||
outbuf[slen++] = c;
|
||||
}
|
||||
|
||||
|
||||
// Convert uint8_t to ascii HEX char.
|
||||
void byte_to_html(uint8_t val)
|
||||
{
|
||||
@@ -99,12 +119,14 @@ void itoa_html(uint8_t v)
|
||||
char_to_html('0' + (v % 10));
|
||||
}
|
||||
|
||||
void itoa16_html(uint16_t v) /* sufficient for VLAN IDs (max 4094) */
|
||||
void itoa16_html(uint16_t v) /* up to five digits (65535) */
|
||||
{
|
||||
uint8_t print_zeros = 0;
|
||||
uint8_t d;
|
||||
d = v / 1000;
|
||||
d = v / 10000;
|
||||
if (d) { char_to_html('0' + d); print_zeros = 1; }
|
||||
d = (v / 1000) % 10;
|
||||
if (d || print_zeros) { char_to_html('0' + d); print_zeros = 1; }
|
||||
d = (v / 100) % 10;
|
||||
if (d || print_zeros) { char_to_html('0' + d); print_zeros = 1; }
|
||||
d = (v / 10) % 10;
|
||||
@@ -112,11 +134,28 @@ void itoa16_html(uint16_t v) /* sufficient for VLAN IDs (max 4094) */
|
||||
char_to_html('0' + (v % 10));
|
||||
}
|
||||
|
||||
void string_to_html(__code char *s)
|
||||
void string_to_html(__code const char *s)
|
||||
{
|
||||
while (*s) char_to_html(*s++);
|
||||
}
|
||||
|
||||
static void temp_to_html(void)
|
||||
{
|
||||
int16_t v;
|
||||
|
||||
reg_read(RTL837X_TM_RESULT);
|
||||
v = SFR_DATA_U16;
|
||||
if (v < 0) {
|
||||
char_to_html('-');
|
||||
v = -v;
|
||||
}
|
||||
itoa_html(v >> 7);
|
||||
char_to_html('.');
|
||||
itoa_html(((v & 0x7f) * 10) >> 7);
|
||||
char_to_html(' ');
|
||||
char_to_html('C');
|
||||
}
|
||||
|
||||
uint16_t stat_content(void)
|
||||
{
|
||||
dbg_string("stat_content called\n");
|
||||
@@ -175,6 +214,20 @@ void reg_to_html_long(uint16_t reg)
|
||||
}
|
||||
|
||||
|
||||
/* The 64-bit counter of the last STAT_GET as one number: the low word keeps
|
||||
* its leading zeros whenever the high word is set. */
|
||||
void counter_to_html(void)
|
||||
{
|
||||
reg_read_m(RTL837X_STAT_V_HIGH);
|
||||
if (SFR_DATA_24 | SFR_DATA_16 | SFR_DATA_8 | SFR_DATA_0) {
|
||||
sfr_data_to_html();
|
||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||
} else {
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_sfp_info(uint8_t sfp)
|
||||
{
|
||||
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
|
||||
@@ -184,8 +237,8 @@ void send_sfp_info(uint8_t sfp)
|
||||
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
|
||||
continue;
|
||||
uint8_t c = sfp_buf[i & 0xf];
|
||||
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
|
||||
char_to_html(c);
|
||||
if (c)
|
||||
json_char_to_html(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +282,9 @@ void send_basic_info(void)
|
||||
itoa_html(syslog_state.server_ip[2]); char_to_html('.');
|
||||
itoa_html(syslog_state.server_ip[3]); char_to_html(':');
|
||||
itoa16_html(syslog_state.server_port);
|
||||
slen += strtox(outbuf + slen, "\",\"mac_address\":\"");
|
||||
slen += strtox(outbuf + slen, "\",\"session_timeout\":");
|
||||
itoa16_html(session_timeout);
|
||||
slen += strtox(outbuf + slen, ",\"mac_address\":\"");
|
||||
byte_to_html(uip_ethaddr.addr[0]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[1]); char_to_html(':');
|
||||
byte_to_html(uip_ethaddr.addr[2]); char_to_html(':');
|
||||
@@ -248,6 +303,8 @@ void send_basic_info(void)
|
||||
slen += strtox(outbuf + slen, BUILD_DATE);
|
||||
slen += strtox(outbuf + slen, "\",\"hw_ver\":\"");
|
||||
slen += strtox(outbuf + slen, machine.machine_name);
|
||||
slen += strtox(outbuf + slen, "\",\"chip_temp\":\"");
|
||||
temp_to_html();
|
||||
slen += strtox(outbuf + slen, "\",\"flash_size\":\"");
|
||||
string_to_html(get_flash_size_str());
|
||||
|
||||
@@ -279,7 +336,7 @@ void send_vlan(uint16_t vlan)
|
||||
dbg_string("VLAN has no name\n");
|
||||
} else {
|
||||
while(vlan_names[n] && vlan_names[n] != ' ')
|
||||
char_to_html(vlan_names[n++]);
|
||||
json_char_to_html(vlan_names[n++]);
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\",\"pvid\":\"0x");
|
||||
uint16_t pvid_mask = 0;
|
||||
@@ -311,8 +368,7 @@ bool send_counters(uint8_t phys_port)
|
||||
for (uint8_t counter = 0; counter < 0x37; counter++) {
|
||||
STAT_GET(counter, log_port);
|
||||
slen += strtox(outbuf + slen, "\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html_long(RTL837X_STAT_V_LOW);
|
||||
counter_to_html();
|
||||
char_to_html('\"');
|
||||
if (counter != 0x36)
|
||||
char_to_html(',');
|
||||
@@ -432,8 +488,6 @@ void l2_delete(uint16_t idx)
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
dbg_string("L2 DELETE\n");
|
||||
dbg_short(idx);
|
||||
__xdata uint8_t entries_left = L2_MAX_TRANSFER;
|
||||
|
||||
do {
|
||||
reg_read(RTL837X_TBL_CTRL);
|
||||
} while (SFR_DATA_0 & TBL_EXECUTE);
|
||||
@@ -568,7 +622,6 @@ static void bridge_to_html(void)
|
||||
byte_to_html(pi_mac[i]);
|
||||
}
|
||||
|
||||
|
||||
void send_stp(void)
|
||||
{
|
||||
uint8_t i, j, st, dsg;
|
||||
@@ -683,8 +736,37 @@ void send_stp(void)
|
||||
slen += strtox(outbuf + slen, "]}");
|
||||
}
|
||||
|
||||
void send_lldp(void)
|
||||
{
|
||||
dbg_string("send_lldp called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
|
||||
slen += strtox(outbuf + slen, "{\"on\":");
|
||||
bool_to_html(lldp_enabled);
|
||||
slen += strtox(outbuf + slen, ",\"portStatus\":[");
|
||||
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
|
||||
slen += strtox(outbuf + slen, ",\"logPort\":");
|
||||
itoa_html(i);
|
||||
slen += strtox(outbuf + slen, ",\"name\":\"");
|
||||
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
||||
json_char_to_html(port_names[i][j]);
|
||||
}
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"permitted\":");
|
||||
bool_to_html(1 & (lldp_logical_port_status >> i));
|
||||
slen += strtox(outbuf + slen, "}");
|
||||
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
char_to_html('}');
|
||||
}
|
||||
|
||||
void send_eee(void)
|
||||
{
|
||||
@@ -778,6 +860,63 @@ void send_bandwidth(void)
|
||||
}
|
||||
|
||||
|
||||
void send_storm(void)
|
||||
{
|
||||
__xdata uint8_t i, t, idx;
|
||||
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
char_to_html('[');
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
slen += strtox(outbuf + slen, ",\"en\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++)
|
||||
char_to_html(reg_bit_test(RTL837X_STORM_CTRL + (t << 2), i) ? '1' : '0');
|
||||
slen += strtox(outbuf + slen, "\",\"pps\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
idx = STORM_METER(i, t);
|
||||
char_to_html(reg_bit_test(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f) ? '1' : '0');
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\",\"rate\":\"");
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
reg_read_m(RTL837X_METER_RATE + (STORM_METER(i, t) << 2));
|
||||
byte_to_html(sfr_data[1]);
|
||||
byte_to_html(sfr_data[2]);
|
||||
byte_to_html(sfr_data[3]);
|
||||
}
|
||||
char_to_html('"');
|
||||
char_to_html('}');
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
else
|
||||
char_to_html(']');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_isolation(void)
|
||||
{
|
||||
__xdata uint16_t allow;
|
||||
|
||||
dbg_string("send_isolation called\n");
|
||||
slen = strtox(outbuf, HTTP_RESPONCE_JSON);
|
||||
char_to_html('[');
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
slen += strtox(outbuf + slen, "{\"portNum\":");
|
||||
itoa_html(machine.log_to_phys_port[i]);
|
||||
slen += strtox(outbuf + slen, ",\"allow\":\"");
|
||||
allow = port_isolation_get(i);
|
||||
byte_to_html(allow >> 8);
|
||||
byte_to_html(allow & 0xff);
|
||||
char_to_html('"');
|
||||
char_to_html('}');
|
||||
if (i < machine.max_port)
|
||||
char_to_html(',');
|
||||
}
|
||||
char_to_html(']');
|
||||
}
|
||||
|
||||
|
||||
void send_mtu(void)
|
||||
{
|
||||
dbg_string("send_mtu called\n");
|
||||
@@ -814,7 +953,7 @@ void send_status(void)
|
||||
itoa_html(i);
|
||||
slen += strtox(outbuf + slen, ",\"name\":\"");
|
||||
for (uint8_t j = 0; j < PORT_NAME_SIZE && port_names[i][j]; j++) {
|
||||
char_to_html(port_names[i][j]);
|
||||
json_char_to_html(port_names[i][j]);
|
||||
}
|
||||
slen += strtox(outbuf + slen, "\"");
|
||||
|
||||
@@ -853,14 +992,11 @@ void send_status(void)
|
||||
sfp_send_data(sfp, 238, 1);
|
||||
}
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_vendor[sfp][s];
|
||||
str_x_to_html(sfp_module_vendor[sfp]);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_model[sfp][s];
|
||||
str_x_to_html(sfp_module_model[sfp]);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
|
||||
for (uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
|
||||
outbuf[slen++] = sfp_module_serial[sfp][s];
|
||||
str_x_to_html(sfp_module_serial[sfp]);
|
||||
slen += strtox(outbuf + slen,"\",\"sfp_los\":");
|
||||
if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
|
||||
slen += strtox(outbuf + slen,"null");
|
||||
@@ -914,8 +1050,7 @@ void send_status(void)
|
||||
|
||||
STAT_GET(STAT_COUNTER_TX_PKTS, i);
|
||||
slen += strtox(outbuf + slen, ",\"txG\":\"0x");
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
counter_to_html();
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"txB\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
@@ -923,8 +1058,7 @@ void send_status(void)
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"rxG\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_RX_PKTS, i);
|
||||
reg_to_html(RTL837X_STAT_V_HIGH);
|
||||
reg_to_html(RTL837X_STAT_V_LOW);
|
||||
counter_to_html();
|
||||
|
||||
slen += strtox(outbuf + slen, "\",\"rxB\":\"0x");
|
||||
STAT_GET(STAT_COUNTER_ERR_PKTS, i);
|
||||
@@ -990,7 +1124,7 @@ void send_cmd_log(void)
|
||||
__xdata uint8_t found_begin = 0;
|
||||
dbg_string("History ptr: ");
|
||||
dbg_short(cmd_history_ptr); dbg_char('\n');
|
||||
while (p != cmd_history_ptr) {
|
||||
while (p != cmd_history_ptr && slen < TCP_OUTBUF_SIZE) {
|
||||
if (!cmd_history[p] || cmd_history[p] == '\n')
|
||||
found_begin = 1;
|
||||
if (found_begin && cmd_history[p])
|
||||
@@ -1015,8 +1149,7 @@ void send_vlanlist(void)
|
||||
slen += strtox(outbuf + slen, ",\"vlan\":[");
|
||||
|
||||
for (i = 1; i < 4095; i++) {
|
||||
if (vlan_get(i) < 0)
|
||||
continue;
|
||||
vlan_get(i);
|
||||
if (!(sfr_data[0] & 0x02)) /* bit 1: VLAN table entry valid */
|
||||
continue;
|
||||
|
||||
@@ -1034,7 +1167,7 @@ void send_vlanlist(void)
|
||||
n = vlan_name(i);
|
||||
if (n != 0xffff) {
|
||||
while (vlan_names[n] && vlan_names[n] != ' ')
|
||||
char_to_html(vlan_names[n++]);
|
||||
json_char_to_html(vlan_names[n++]);
|
||||
}
|
||||
|
||||
slen += strtox(outbuf + slen, "\"}");
|
||||
|
||||
@@ -3,22 +3,27 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern __code uint8_t * __code HTTP_RESPONCE_TXT;
|
||||
extern __code const uint8_t * __code const HTTP_RESPONCE_TXT;
|
||||
|
||||
void itoa16_html(uint16_t v);
|
||||
|
||||
bool send_counters(uint8_t phys_port);
|
||||
void send_status(void);
|
||||
void send_vlan(uint16_t vlan);
|
||||
void send_basic_info(void);
|
||||
void send_bandwidth(void);
|
||||
void send_storm(void);
|
||||
void send_eee(void);
|
||||
void send_l2(uint16_t idx);
|
||||
void l2_delete(uint16_t idx);
|
||||
void send_mirror(void);
|
||||
void send_mtu(void);
|
||||
void send_isolation(void);
|
||||
void send_config(void);
|
||||
void send_cmd_log(void);
|
||||
void send_lag(void);
|
||||
void send_stp(void);
|
||||
void send_lldp(void);
|
||||
void send_vlanlist(void);
|
||||
|
||||
/* Convert only the lower nibble to ascii HEX char.
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
__xdata uint8_t buffer[0x1000];
|
||||
__xdata uint8_t dio_enabled;
|
||||
|
||||
__code uint8_t * __code hex = "0123456789abcdef";
|
||||
__code const uint8_t * __code const hex = "0123456789abcdef";
|
||||
|
||||
void isr_timer0(void) __interrupt(1)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ void write_char(char c)
|
||||
}
|
||||
|
||||
|
||||
void print_string(__code char *p)
|
||||
void print_string(__code const char *p)
|
||||
{
|
||||
while (*p)
|
||||
write_char(*p++);
|
||||
|
||||
@@ -5,6 +5,29 @@
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_common.h"
|
||||
|
||||
#define I2CBUS_INVALID (7)
|
||||
// This is a MACRO to check if I2C_BUS_FROM_SDA_PIN or I2C_BUS_FROM_SCL_PIN don't return I2CBUS_INVALID.
|
||||
// When I2CBUS_INVALID is returned, compiler stops with "machine.c:<line>: error 176: sizeof applied to an incomplete type"
|
||||
#define I2CBUS_VALID(bus) (0 * sizeof(char[(bus) != I2CBUS_INVALID ? 1 : 0]))
|
||||
#define I2CBUS(sda, scl) \
|
||||
((uint8_t)((I2C_BUS_FROM_SCL_PIN(scl) << RTL837X_REG_I2C_SCL_SHIFT) | \
|
||||
(I2C_BUS_FROM_SDA_PIN(sda) << RTL837X_REG_I2C_SDA_SHIFT) | \
|
||||
I2CBUS_VALID(I2C_BUS_FROM_SCL_PIN(scl)) | \
|
||||
I2CBUS_VALID(I2C_BUS_FROM_SDA_PIN(sda))))
|
||||
|
||||
#define I2C_BUS_FROM_SDA_PIN(sda_pin) \
|
||||
((sda_pin) == GPIO47_I2C_SDA0 ? 0 : \
|
||||
(sda_pin) == GPIO49_I2C_SDA1 ? 1 : \
|
||||
(sda_pin) == GPIO51_I2C_SDA2_UART1_RX ? 2 : \
|
||||
(sda_pin) == GPIO41_I2C_SDA3_MDIO1 ? 3 : \
|
||||
(sda_pin) == GPIO39_I2C_SDA4 ? 4 : I2CBUS_INVALID)
|
||||
|
||||
#define I2C_BUS_FROM_SCL_PIN(scl_pin) \
|
||||
((scl_pin) == GPIO46_I2C_SCL0 ? 0 : \
|
||||
(scl_pin) == GPIO48_I2C_SCL1 ? 1 : \
|
||||
(scl_pin) == GPIO50_I2C_SCL2_UART1_TX ? 2 : \
|
||||
(scl_pin) == GPIO40_I2C_SCL3_MDC1 ? 3 : I2CBUS_INVALID)
|
||||
|
||||
#if defined(MACHINE_KP_9000_6XHML_X2) || \
|
||||
defined(MACHINE_KP_9000_6XH_X2_V1_1) || \
|
||||
defined(MACHINE_KP_9000_6XHML_X2_V1_1) || \
|
||||
@@ -34,13 +57,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO10_LED10,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
// Right SFP port (6)
|
||||
.sfp_port[1].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.sfp_port[1].pin_los = GPIO37,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
@@ -70,7 +93,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
/* Conditions for LED on:
|
||||
* dual led orange: ledset_0 & ledset_2
|
||||
@@ -105,13 +128,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// Right SFP port
|
||||
.sfp_port[1].pin_detect = GPIO37,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO48_I2C_SCL1, // Button-Switch is unpopulated on PCB, but can be added manually (hole in case is already there)
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -152,7 +175,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
@@ -177,7 +200,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
@@ -214,9 +237,14 @@ __code const struct machine machine = {
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_KP_9000_9XHML_X_V3_1
|
||||
#elif defined(MACHINE_KP_9000_9XHML_X_V3_1) || defined(MACHINE_KP_9000_9XHML_X_V3_2)
|
||||
// 2M-PCB23-V3.2 is wired like V3.1 (SFP detection, LEDs, factory MAC location)
|
||||
__code const struct machine machine = {
|
||||
#if defined(MACHINE_KP_9000_9XHML_X_V3_2)
|
||||
.machine_name = "keepLink KP-9000-9XHML-X V3.2",
|
||||
#else
|
||||
.machine_name = "keepLink KP-9000-9XHML-X V3.1",
|
||||
#endif
|
||||
.isRTL8373 = 1,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
@@ -227,7 +255,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO48_I2C_SCL1,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -265,13 +293,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
|
||||
// Right SFP port (J2)
|
||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
@@ -306,13 +334,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 39 */
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 39 */
|
||||
// Right SFP port (J2)
|
||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 }, /* GPIO 40 */
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ), /* GPIO 40 */
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
@@ -346,7 +374,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO48_I2C_SCL1,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -385,12 +413,12 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = 10,
|
||||
.sfp_port[0].pin_tx_disable = 0xFF,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.sfp_port[1].pin_detect = 30,
|
||||
.sfp_port[1].pin_los = 51,
|
||||
.sfp_port[1].pin_tx_disable = 0xFF,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 , .enable = LED_27 | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
@@ -425,7 +453,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -458,7 +486,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA, // no LOS pin wired
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -499,7 +527,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -531,7 +559,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
@@ -556,12 +584,12 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[0].pin_tx_disable = GPIO54_ACL_BIT2_EN,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = { .sda = GPIO47_I2C_SDA0, .scl = GPIO46_I2C_SCL0 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO47_I2C_SDA0, GPIO46_I2C_SCL0 ),
|
||||
.sfp_port[1].pin_detect = GPIO36_PWM_OUT,
|
||||
.sfp_port[1].pin_los = GPIO37,
|
||||
.sfp_port[1].pin_tx_disable = GPIO51_I2C_SDA2_UART1_RX,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = { .sda = GPIO49_I2C_SDA1, .scl = GPIO48_I2C_SCL1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO49_I2C_SDA1, GPIO48_I2C_SCL1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
.led_sets = {
|
||||
@@ -596,13 +624,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// Right SFP port
|
||||
.sfp_port[1].pin_detect = GPIO37,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -641,7 +669,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -676,7 +704,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO48_I2C_SCL1,
|
||||
.high_leds = { .mux = LED_28_SYS, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
.led_mux_custom = 1,
|
||||
@@ -720,14 +748,14 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
// Right SFP port (6)
|
||||
// LED pin 24
|
||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1},
|
||||
@@ -769,11 +797,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = {
|
||||
.sda = GPIO39_I2C_SDA4,
|
||||
.scl = GPIO40_I2C_SCL3_MDC1
|
||||
},
|
||||
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
|
||||
.high_leds = {
|
||||
@@ -823,14 +847,14 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
/* Right SFP (logical 3, SDS0): GPIO50=ModAbs, GPIO51=RX_LOS */
|
||||
.sfp_port[1].pin_detect = GPIO50_I2C_SCL2_UART1_TX,
|
||||
.sfp_port[1].pin_los = GPIO51_I2C_SDA2_UART1_RX,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
|
||||
@@ -879,14 +903,14 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// SFP port on SDS1 / logical port 8
|
||||
.sfp_port[1].pin_detect = GPIO38,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -911,6 +935,68 @@ __code const struct machine machine = {
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_ONT_S207CW_62TS_SE
|
||||
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "ONT-S207CW-62TS-SE / Binardat 2G06-04210GSM / Binardat 2G06-04210GS",
|
||||
.isRTL8373 = 0,
|
||||
.min_port = 3,
|
||||
.max_port = 8,
|
||||
.n_sfp = 2,
|
||||
.log_to_phys_port = {0, 0, 0, 5, 4, 3, 2, 1, 6},
|
||||
.phys_to_log_port = {7, 6, 5, 4, 3, 8, 0, 0, 0},
|
||||
.is_sfp = {0, 0, 0, 1, 0, 0, 0, 0, 2},
|
||||
|
||||
// SFP port on SDS0 / logical port 3
|
||||
.sfp_port[0].pin_detect = GPIO37,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 0,
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// SFP port on SDS1 / logical port 8
|
||||
.sfp_port[1].pin_detect = GPIO38,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[1].sds = 1,
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 3, 0, 0, 2, 2, 3},
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
.led_sets = {
|
||||
{ // RJ45 Ports 3-4 (normal wiring)
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{ // Unused
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{ // RJ45 Ports 1-2 (reversed wiring)
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{ // SFP Ports 5-6
|
||||
LEDS_10G | LEDS_LINK | LEDS_ACT,
|
||||
LEDS_2G5 | LEDS_1G | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = {
|
||||
0x00,0x01,0x04,0x05,0x08,0x09,0x0c,0x3f,0x0d,0x10,0x11,0x0e,0x14,0x11,0x12,0x15,0x15,0x16,0x18,0x19,0x1a,0x19,0x1d,0x1e,0x1c,0x1d,0x20,0x21
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "SWTG024AS-A-V2.0.1-5C-1SFP",
|
||||
@@ -925,7 +1011,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -968,7 +1054,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_27 | LED_28_SYS | LED_29 },
|
||||
@@ -1049,13 +1135,13 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_detect = GPIO38,
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
// Right SFP port
|
||||
.sfp_port[1].pin_detect = GPIO37,
|
||||
.sfp_port[1].pin_los = GPIO_NA,
|
||||
.sfp_port[1].sds = 0,
|
||||
.sfp_port[1].i2c = { .sda = GPIO41_I2C_SDA3_MDIO1, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[1].i2c = I2CBUS( GPIO41_I2C_SDA3_MDIO1, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
@@ -1114,7 +1200,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO_NA,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -1160,10 +1246,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = {
|
||||
.sda = GPIO39_I2C_SDA4,
|
||||
.scl = GPIO40_I2C_SCL3_MDC1
|
||||
},
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = 0, .enable = 0 },
|
||||
@@ -1197,7 +1280,7 @@ __code const struct machine machine = {
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
@@ -1226,6 +1309,160 @@ __code const struct machine machine = {
|
||||
0x1a, 0x19, 0x1d, 0x1e, 0x1c,
|
||||
0x1d, 0x20, 0x21 },
|
||||
};
|
||||
#elif defined MACHINE_PB_2132
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "PB-2132",
|
||||
.isRTL8373 = 1,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 1,
|
||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
|
||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
|
||||
.reset_pin = GPIO_NA,
|
||||
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
|
||||
.led_sets = {
|
||||
{
|
||||
/* LED0 = RJ45: Amber LED: 2.5G */
|
||||
LEDS_2G5 | LEDS_LINK | LEDS_ACT,
|
||||
/* LED1 = RJ45: Green LED: 10M / 100M / 1000M */
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0
|
||||
},
|
||||
{
|
||||
/* SFP+ single Green LED. */
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
#elif defined MACHINE_HASIVO_S600W_4GT_2XGT_SE
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "Hasivo S600W-4GT-2XGT-SE",
|
||||
.isRTL8373 = 0,
|
||||
.min_port = 3,
|
||||
.max_port = 8,
|
||||
.n_sfp = 0,
|
||||
.n_10g = 2,
|
||||
.log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6},
|
||||
.phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0},
|
||||
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 1, 0, 0, 0, 0, 1 },
|
||||
/* Ports 1-4: Green: 2.5GBit, Orange: 10/100/1000MBit
|
||||
* Ports 5-6: Green: 10GBit, Orange: 5/2.5GBit, None: 10/100/1000MBit
|
||||
*/
|
||||
.led_sets = {
|
||||
{
|
||||
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Yellow
|
||||
LEDS_2G5 | LEDS_LINK, // Green
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK, // Orange
|
||||
0, // Unused
|
||||
},
|
||||
{
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Yellow
|
||||
LEDS_10G | LEDS_LINK, // Green
|
||||
LEDS_5G | LEDS_2G5 | LEDS_LINK, // Orange
|
||||
0, // Unused
|
||||
},
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = {
|
||||
0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
|
||||
0x3f, 0x3f, 0x3f, 0x0f, 0x20,
|
||||
0x21, 0x22, 0x10, 0x11, 0x12,
|
||||
0x14, 0x15, 0x16, 0x18, 0x19,
|
||||
0x1a, 0x1c, 0x1d, 0x1e, 0x0c,
|
||||
0x0d, 0x0e, 0x23
|
||||
},
|
||||
|
||||
};
|
||||
#elif defined MACHINE_HASIVO_S1100WP_8GT_1SX_SE
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "Hasivo S1100WP-8GT-1SX-SE",
|
||||
.isRTL8373 = 1,
|
||||
.mac_flash_offset = 0x1FC000,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 1,
|
||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO54_ACL_BIT2_EN,
|
||||
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.led_sets = { { LEDS_2G5 | LEDS_LINK | LEDS_ACT, // Green LED (right)
|
||||
0,
|
||||
LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, // Amber LED (left)
|
||||
0
|
||||
},
|
||||
{ LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_LINK | LEDS_ACT, // SFP LED
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
},
|
||||
};
|
||||
#elif defined MACHINE_F7008_2_5
|
||||
__code const struct machine machine = {
|
||||
.machine_name = "F7008-2.5 8+1 SFP Port Switch",
|
||||
.isRTL8373 = 1,
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 1,
|
||||
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
|
||||
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.sfp_port[0].pin_detect = GPIO30_ACL_BIT3_EN,
|
||||
.sfp_port[0].pin_los = GPIO37,
|
||||
.sfp_port[0].pin_tx_disable = GPIO_NA,
|
||||
.sfp_port[0].sds = 1,
|
||||
.sfp_port[0].i2c = I2CBUS( GPIO39_I2C_SDA4, GPIO40_I2C_SCL3_MDC1 ),
|
||||
.reset_pin = GPIO_NA,
|
||||
.high_leds = { .mux = LED_27 | LED_29, .enable = LED_28_SYS | LED_29 },
|
||||
.port_led_set = {0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
.led_sets = {
|
||||
{ /* SET0 */
|
||||
LEDS_2G5 | LEDS_LINK, /* LEDID0 - green: 2.5G link */
|
||||
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT, /* LEDID1 - yellow: traffic */
|
||||
0,
|
||||
0,
|
||||
},
|
||||
{ /* SET1 - SFP+ */
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_LINK,
|
||||
LEDS_10G | LEDS_5G | LEDS_2G5 | LEDS_1G | LEDS_LINK | LEDS_ACT,
|
||||
0,
|
||||
0,
|
||||
},
|
||||
},
|
||||
.led_mux_custom = 1,
|
||||
.led_mux = {
|
||||
0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x02,
|
||||
0x0d, 0x10, 0x11, 0x02, 0x14, 0x02, 0x02, 0x15,
|
||||
0x02, 0x02, 0x18, 0x02, 0x02, 0x19, 0x02, 0x02,
|
||||
0x1c, 0x1d, 0x02, 0x02,
|
||||
},
|
||||
};
|
||||
|
||||
#else
|
||||
#error "Please select a machine type in machine.h"
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// #define MACHINE_KP_9000_9XH_X_EU
|
||||
// #define MACHINE_KP_9000_9XHML_X_V2_2
|
||||
// #define MACHINE_KP_9000_9XHML_X_V3_1
|
||||
// #define MACHINE_KP_9000_9XHML_X_V3_2
|
||||
// #define MACHINE_SWGT024_V2_0_MANAGED
|
||||
// #define MACHINE_SWGT024_V2_0_UNMANAGED
|
||||
// #define MACHINE_TRENDNET_TEG_S562
|
||||
@@ -40,19 +41,17 @@
|
||||
// #define MACHINE_HI_K0801WS
|
||||
// #define MACHINE_FNS1200P
|
||||
// #define MACHINE_PCB_SWTG024AS_A_2_0_1
|
||||
// #define MACHINE_ONT_S207CW_62TS_SE
|
||||
// #define MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
|
||||
// #define MACHINE_SWTG024AS_V2_0
|
||||
// #define MACHINE_FG_4GT_2SX_V2_0
|
||||
// #define MACHINE_FG_8GT_1SX
|
||||
// #define MACHINE_LIANGUO_HYWS_SGT0108S
|
||||
// #define MACHINE_POE_2G080110GS
|
||||
|
||||
typedef struct {
|
||||
// GPIO pins for SDA/SCL
|
||||
uint8_t sda;
|
||||
uint8_t scl;
|
||||
} i2c_bus_t;
|
||||
|
||||
// #define MACHINE_PB_2132
|
||||
// #define MACHINE_HASIVO_S600W_4GT_2XGT_SE
|
||||
// #define MACHINE_HASIVO_S1100WP_8GT_1SX_SE
|
||||
// #define MACHINE_F7008_2_5
|
||||
|
||||
#define LED_27 1
|
||||
// SYSTEM LED
|
||||
@@ -72,7 +71,7 @@ struct sfp_port
|
||||
uint8_t pin_los; // gpio number 0-63, 0xFF = don't have it?
|
||||
uint8_t pin_tx_disable; // gpio number 0-63, 0xFF = not present
|
||||
uint8_t sds;
|
||||
i2c_bus_t i2c;
|
||||
uint8_t i2c;
|
||||
};
|
||||
|
||||
struct machine {
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
|
||||
#if defined(MACHINE_KP_9000_6XH_X2) || \
|
||||
defined(MACHINE_KP_9000_6XH_X2_V2_1) || \
|
||||
defined(MACHINE_KP_9000_6XHML_X2_V2_1)
|
||||
defined(MACHINE_KP_9000_6XHML_X2_V2_1) || \
|
||||
defined(MACHINE_HI_K0402WS) || \
|
||||
defined(MACHINE_PCB_K0402WS_V2) || \
|
||||
defined(MACHINE_PCB_K0402WS_V3) || \
|
||||
defined(MACHINE_FNS1200P)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
@@ -42,18 +46,6 @@ void machine_custom_init(void) __banked
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
}
|
||||
|
||||
#elif defined(MACHINE_PCB_K0402WS_V2) || defined(MACHINE_FNS1200P)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
}
|
||||
|
||||
#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
@@ -63,27 +55,8 @@ void machine_custom_init(void) __banked
|
||||
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
|
||||
}
|
||||
|
||||
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
|
||||
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
|
||||
reg_bit_set(RTL837X_REG_LED_MODE, 17);
|
||||
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
|
||||
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
|
||||
|
||||
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
|
||||
sds_read(0, 0, 0);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(0, 0, 0, pval | 0x100);
|
||||
|
||||
sds_read(0, 6, 2);
|
||||
pval = SFR_DATA_U16;
|
||||
sds_write_v(0, 6, 2, pval | 0x4000);
|
||||
}
|
||||
|
||||
#elif defined MACHINE_SWTG024AS_V2_0
|
||||
#elif defined(MACHINE_SWTG024AS_A_2_0_1_5C_1SFP) || \
|
||||
defined(MACHINE_SWTG024AS_V2_0)
|
||||
void machine_custom_init(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
#define SYS_TICK_HZ 200
|
||||
|
||||
/* Timers of the main loop count system ticks, not loop passes: a pass is as
|
||||
* long as the packets it handles, and since #483 the loop no longer sleeps
|
||||
* while packets wait, so passes can outrun the tick as well as lag it. `last`
|
||||
* is the low byte of ticks when the timer last ran; the byte arithmetic wraps
|
||||
* every 256 ticks, so a pass longer than 1.28 s loses time rather than
|
||||
* running the timer 64 times to catch up. */
|
||||
#define TICKS_DUE(last, period) ((uint8_t)((uint8_t)ticks - (last)) >= (period))
|
||||
|
||||
#define CPU_PORT 9
|
||||
#define NUL '\0'
|
||||
|
||||
@@ -54,6 +62,7 @@ extern __xdata uint8_t sbuf[SBUF_SIZE];
|
||||
#define ERR_OK 0
|
||||
#define ERR_TOO_MANY_ARGUMENTS 1
|
||||
#define ERR_CMD_TOO_LONG 2
|
||||
#define ERR_INVALID_ARGUMENT 3
|
||||
|
||||
// For RX data, a propriatary RTL FRAME is inserted. Instead of 0x0800 for IPv4,
|
||||
// the RTL_FRAME_TAG_ID is used as part of an 8-byte tag. When VLAN is activated,
|
||||
@@ -97,7 +106,7 @@ struct vlan_tag {
|
||||
#define FIRMWARE_UPLOAD_START 0x80000
|
||||
|
||||
// Constants for the circular command buffer, the size must be 2^n
|
||||
#define CMD_HISTORY_SIZE 0x400
|
||||
#define CMD_HISTORY_SIZE 0x800
|
||||
#define CMD_HISTORY_MASK (CMD_HISTORY_SIZE - 1)
|
||||
|
||||
enum sfp_speeds {
|
||||
@@ -122,6 +131,7 @@ struct flash_region_t {
|
||||
};
|
||||
|
||||
extern __xdata char port_names[9][PORT_NAME_SIZE];
|
||||
extern __xdata uint16_t lldp_logical_port_status;
|
||||
|
||||
extern __xdata bool stp_enabled;
|
||||
|
||||
@@ -134,9 +144,9 @@ extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
||||
extern __xdata struct uip_eth_addr uip_ethaddr;
|
||||
|
||||
// Headers for calls in the common code area (HOME/BANK0)
|
||||
void print_string_no_syslog(__code char *p);
|
||||
void print_string_newline_no_syslog(__code char *p);
|
||||
void print_string(__code char *p);
|
||||
void print_string_no_syslog(__code const char *p);
|
||||
void print_string_newline_no_syslog(__code const char *p);
|
||||
void print_string(__code const char *p);
|
||||
void print_string_x(__xdata char *p);
|
||||
void print_long(uint32_t a);
|
||||
void print_short(uint16_t a);
|
||||
@@ -182,13 +192,13 @@ uint16_t strlen(__code const char *s);
|
||||
uint16_t strcpy(__xdata uint8_t *dst, const char *s);
|
||||
char strcmp(__xdata const uint8_t *a, __code const uint8_t *b);
|
||||
#endif
|
||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len);
|
||||
void memcpyc(__xdata uint8_t *dst, __code const uint8_t *src, uint16_t len);
|
||||
uint16_t strlen_x(__xdata const char *s);
|
||||
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
|
||||
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b);
|
||||
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b);
|
||||
void tcpip_output(void);
|
||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
|
||||
uint8_t read_flash(uint8_t bank, __code const uint8_t *addr);
|
||||
void get_random_32(void);
|
||||
void read_reg_timer(__xdata uint32_t * tmr);
|
||||
bool gpio_pin_test(uint8_t pin);
|
||||
|
||||
@@ -171,7 +171,7 @@ void flash_read_uid(void)
|
||||
flash_configure_mmio();
|
||||
}
|
||||
|
||||
__code char* get_flash_size_str(void)
|
||||
__code const char* get_flash_size_str(void)
|
||||
{
|
||||
switch (flash_capacity_code) {
|
||||
case 0x12: return "256 KB";
|
||||
|
||||
@@ -19,7 +19,7 @@ void flash_read_security(void);
|
||||
void flash_sector_erase(void);
|
||||
void flash_read_bulk(__xdata uint8_t *dst);
|
||||
void flash_write_bytes(__xdata uint8_t *ptr);
|
||||
__code char* get_flash_size_str(void);
|
||||
__code const char* get_flash_size_str(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,16 +9,18 @@
|
||||
#define IPMC_USES_L3MC
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_igmp.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t igmpEnabled;
|
||||
|
||||
#include "uip.h"
|
||||
#include "uip_arp.h"
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
@@ -29,6 +31,13 @@ extern __xdata struct machine_runtime machine_detected;
|
||||
extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE + 2];
|
||||
|
||||
__xdata uint16_t idx;
|
||||
#define IGMP_IP_HDR offsetof(struct igmp_pkt, hlen)
|
||||
#define IGMP_IP_IHL 0x0f
|
||||
#define IGMP_GROUP_OFS 4
|
||||
#define IGMP_V3_RECORD_OFS 8
|
||||
|
||||
static __xdata uint8_t igmp_grp;
|
||||
static __xdata uint8_t igmp_join;
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
struct ipmc_table_entry {
|
||||
@@ -198,8 +207,10 @@ void entry_to_l2mc(void)
|
||||
#endif
|
||||
|
||||
|
||||
void igmp_packet_handler(void) __banked
|
||||
uint8_t igmp_packet_handler(void) __banked
|
||||
{
|
||||
if (IGMP_I->ipv4_tag != HTONS(UIP_ETHTYPE_IP) || IGMP_I->protocol != IGMP_PROTO)
|
||||
return 0;
|
||||
// By default we do not send anything out
|
||||
uip_len = 0;
|
||||
|
||||
@@ -211,24 +222,40 @@ void igmp_packet_handler(void) __banked
|
||||
}
|
||||
write_char('\n');
|
||||
#endif
|
||||
if (IGMP_I->protocol != 2)
|
||||
return;
|
||||
igmp_grp = IGMP_IP_HDR + ((IGMP_I->hlen & IGMP_IP_IHL) << 2);
|
||||
#ifdef DEBUG
|
||||
print_string("Found IGMP, type: "); print_byte(IGMP_I->igmp_type); write_char('\n');
|
||||
print_string("Found IGMP, type: "); print_byte(uip_buf[igmp_grp]); write_char('\n');
|
||||
#endif
|
||||
// We react to IGMPv1/v2 and v3 membership reports
|
||||
if (!(IGMP_I->igmp_type == 0x12 || IGMP_I->igmp_type == 0x16 || IGMP_I->igmp_type == 0x22))
|
||||
return;
|
||||
switch (uip_buf[igmp_grp]) {
|
||||
case IGMP_V1_REPORT:
|
||||
case IGMP_V2_REPORT:
|
||||
igmp_join = 1;
|
||||
break;
|
||||
case IGMP_V2_LEAVE:
|
||||
igmp_join = 0;
|
||||
break;
|
||||
case IGMP_V3_REPORT:
|
||||
igmp_grp += IGMP_V3_RECORD_OFS;
|
||||
if (uip_buf[igmp_grp] == IGMP_V3_TO_EXCLUDE)
|
||||
igmp_join = 1;
|
||||
else if (uip_buf[igmp_grp] == IGMP_V3_TO_INCLUDE)
|
||||
igmp_join = 0;
|
||||
else
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
igmp_grp += IGMP_GROUP_OFS;
|
||||
#ifdef DEBUG
|
||||
print_string("IGMP membership report, type "); print_byte(IGMP_I->igmp_rtype); write_char('\n');
|
||||
print_string("IGMP join "); print_byte(igmp_join); write_char('\n');
|
||||
#endif
|
||||
|
||||
#ifdef IPMC_USES_L3MC
|
||||
memset((__xdata uint8_t *)&entry, 0, sizeof(struct ipmc_table_entry));
|
||||
// For IPv4 MC, the Source-IP is 0.0.0.0
|
||||
entry.sip[0] = 0x00; entry.sip[1] = 0x00; entry.sip[2] = 0x00; entry.sip[3] = 0x00;
|
||||
// For IPv4 MC, the Destination-IP is the IPv4 MC address
|
||||
entry.dip[0] = IGMP_I->mc_ip[0]; entry.dip[1] = IGMP_I->mc_ip[1]; entry.dip[2] = IGMP_I->mc_ip[2]; entry.dip[3] = IGMP_I->mc_ip[3];
|
||||
memcpy(entry.dip, &uip_buf[igmp_grp], sizeof(entry.dip));
|
||||
entry_to_l3mc();
|
||||
#else
|
||||
/* The L2 Multicast MAC for IP-Multicast is 01:00:5e:xx:yy:zz, where
|
||||
@@ -238,7 +265,7 @@ void igmp_packet_handler(void) __banked
|
||||
*/
|
||||
memset((__xdata uint8_t *)&entry, 0, sizeof(struct l2mc_table_entry));
|
||||
entry.mac[0] = 0x01; entry.mac[1] = 0x00; entry.mac[2] = 0x5e;
|
||||
entry.mac[3] = IGMP_I->mc_ip[1] & 0x7f; entry.mac[4] = IGMP_I->mc_ip[2]; entry.mac[5] = IGMP_I->mc_ip[3];
|
||||
entry.mac[3] = uip_buf[igmp_grp + 1] & 0x7f; entry.mac[4] = uip_buf[igmp_grp + 2]; entry.mac[5] = uip_buf[igmp_grp + 3];
|
||||
entry.vlan = 1; //TODO: Get this out of the packet and compare with VLAN table!
|
||||
entry_to_ipmc();
|
||||
#endif
|
||||
@@ -286,7 +313,7 @@ void igmp_packet_handler(void) __banked
|
||||
print_sfr_data();
|
||||
#endif
|
||||
idx = ((sfr_data[2] & 0xf) << 8) | sfr_data[3];
|
||||
if (IGMP_I->igmp_rtype == 0x4) {// Join group
|
||||
if (igmp_join) {// Join group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
print_string("\nIGMP-Entry FOUND\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
@@ -297,7 +324,7 @@ void igmp_packet_handler(void) __banked
|
||||
// Update (found) entry with portmask from trapped Packet
|
||||
entry.pmask |= ((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f); // Swap bytes from network order, only 4 LSB count
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else if (IGMP_I->igmp_rtype == 0x3){ // Leave group
|
||||
} else { // Leave group
|
||||
if (sfr_data[2] & 0x10) {
|
||||
print_string("\nIGMP_Entry FOUND\n");
|
||||
reg_read_m(RTL837x_L2_DATA_OUT_B);
|
||||
@@ -316,7 +343,7 @@ void igmp_packet_handler(void) __banked
|
||||
// print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n');
|
||||
} else {
|
||||
print_string("IGMP Entry already deleted\n");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
if (!entry.pmask && idx) { // No more ports in that group and an actual entry?
|
||||
// Delete Entry
|
||||
@@ -328,14 +355,12 @@ void igmp_packet_handler(void) __banked
|
||||
reg_read_m(RTL837X_TBL_CTRL);
|
||||
} while (sfr_data[3] & 0x1);
|
||||
print_string("IGMP Entry deleted\n");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
} else { // Unknown message: ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!entry.pmask)
|
||||
return;
|
||||
return 1;
|
||||
print_string("Updating IGMP entry\n");
|
||||
// Write the updated entry
|
||||
#ifdef IPMC_USES_L3MC
|
||||
@@ -372,4 +397,5 @@ void igmp_packet_handler(void) __banked
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
print_sfr_data();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
@@ -3,10 +3,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define IGMP_PROTO 2
|
||||
#define IGMP_V1_REPORT 0x12
|
||||
#define IGMP_V2_REPORT 0x16
|
||||
#define IGMP_V2_LEAVE 0x17
|
||||
#define IGMP_V3_REPORT 0x22
|
||||
#define IGMP_V3_TO_INCLUDE 3
|
||||
#define IGMP_V3_TO_EXCLUDE 4
|
||||
|
||||
void igmp_setup(void) __banked;
|
||||
void igmp_enable(void) __banked;
|
||||
void igmp_router_port_set(uint16_t pmask) __banked;
|
||||
void igmp_packet_handler(void) __banked;
|
||||
uint8_t igmp_packet_handler(void) __banked;
|
||||
void igmp_show(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "boot.h"
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
|
||||
#pragma codeseg BANK2
|
||||
@@ -92,8 +92,18 @@ void static sds_init(void)
|
||||
}
|
||||
|
||||
|
||||
void static tm_init(void)
|
||||
{
|
||||
reg_read_m(RTL837X_TM_CTRL2);
|
||||
sfr_mask_data(0, TM_CTRL2_EN_LATCH, 0);
|
||||
reg_write_m(RTL837X_TM_CTRL2);
|
||||
}
|
||||
|
||||
|
||||
void rtl8373_init(void) __banked
|
||||
{
|
||||
tm_init();
|
||||
|
||||
print_string("\nrtl8373_init called\n");
|
||||
|
||||
// r65d8:3ffbedff R65d8-3ffbedff
|
||||
@@ -191,6 +201,8 @@ void rtl8373_init(void) __banked
|
||||
|
||||
void rtl8372_init(void) __banked
|
||||
{
|
||||
tm_init();
|
||||
|
||||
print_string("\nrtl8372_init called\n");
|
||||
|
||||
sds_init();
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "rtl837x_leds.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
|
||||
#include "uip.h"
|
||||
|
||||
@@ -24,149 +24,6 @@ extern __code struct machine machine;
|
||||
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
void leds_dump(void) __banked
|
||||
{
|
||||
print_string("RTL837X_PIN_MUX_0: "); print_reg(RTL837X_PIN_MUX_0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_IO_EN: "); print_reg(RTL837X_REG_LED_GLB_IO_EN); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET0: "); print_reg(RTL837X_REG_LED1_0_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET0: "); print_reg(RTL837X_REG_LED3_2_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET1: "); print_reg(RTL837X_REG_LED1_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET1: "); print_reg(RTL837X_REG_LED3_2_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET3: "); print_reg(RTL837X_REG_LED3_2_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_1: "); print_reg(RTL837X_REG_LED_GLB_MUX_1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_2: "); print_reg(RTL837X_REG_LED_GLB_MUX_2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_3: "); print_reg(RTL837X_REG_LED_GLB_MUX_3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_4: "); print_reg(RTL837X_REG_LED_GLB_MUX_4); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_5: "); print_reg(RTL837X_REG_LED_GLB_MUX_5); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_6: "); print_reg(RTL837X_REG_LED_GLB_MUX_6); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_ACTIVE: "); print_reg(RTL837X_REG_LED_GLB_ACTIVE); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_MODE: "); print_reg(RTL837X_REG_LED_MODE); write_char('\n');
|
||||
print_string("LED pad Configuration:\n");
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
print_byte(i);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
switch (i % 5) {
|
||||
case 0: // 0
|
||||
reg_read_m(RTL837X_REG_LED_GLB_MUX_1 + (i / 5) * 4);
|
||||
print_byte(sfr_data[3] & 0x3f);
|
||||
break;
|
||||
case 1: // 6
|
||||
print_byte(((sfr_data[3] >> 6) | (sfr_data[2] << 2)) & 0x3f);
|
||||
break;
|
||||
case 2: // 12
|
||||
print_byte(((sfr_data[1] << 4) | (sfr_data[2] >> 4)) & 0x3f);
|
||||
break;
|
||||
case 3: // 18
|
||||
print_byte((sfr_data[1] >> 2) & 0x3f);
|
||||
break;
|
||||
case 4: // 24
|
||||
print_byte(sfr_data[0] & 0x3f);
|
||||
break;
|
||||
}
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
print_string("LED-set Configuration:\n");
|
||||
print_string("LED-ID\t\t0\t\t1\t\t2\t\t3\n");
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
print_string("SET "); write_char('0' + set); write_char(':');
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
print_string("\t ");
|
||||
uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
}
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (! (ledid & 1)) { // LEDID 0, 2
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
} else {
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
reg_read_m(RTL837X_LED_PORT_SET_SEL);
|
||||
__xdata uint8_t set = sfr_data[3 - (i >> 2)];
|
||||
set = (set >> ((i & 3) << 1));
|
||||
print_string("Port "); write_char('0' + i); print_string(": SET ");
|
||||
write_char('0' + set);
|
||||
print_string(": ");
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
write_char('(');
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (ledid & 1) { // LEDID 1, 3
|
||||
sfr_data[2] = sfr_data[0];
|
||||
sfr_data[3] = sfr_data[1];
|
||||
}
|
||||
if (sfr_data[3] & 0x01)
|
||||
print_string(" 2G5");
|
||||
if (sfr_data[3] & 0x02)
|
||||
print_string(" TWO_1G");
|
||||
if (sfr_data[3] & 0x04)
|
||||
print_string(" 1G");
|
||||
if (sfr_data[3] & 0x08)
|
||||
print_string(" 500M");
|
||||
if (sfr_data[3] & 0x10)
|
||||
print_string(" 100M");
|
||||
if (sfr_data[3] & 0x20)
|
||||
print_string(" 10M");
|
||||
if (sfr_data[3] & 0x40)
|
||||
print_string(" LINK");
|
||||
if (sfr_data[3] & 0x80)
|
||||
print_string(" LINK_FLASH");
|
||||
if (sfr_data[2] & 0x01)
|
||||
print_string(" ACT");
|
||||
if (sfr_data[2] & 0x02)
|
||||
print_string(" RX");
|
||||
if (sfr_data[2] & 0x04)
|
||||
print_string(" TX");
|
||||
if (sfr_data[2] & 0x08)
|
||||
print_string(" COL");
|
||||
if (sfr_data[2] & 0x10)
|
||||
print_string(" DUPLEX");
|
||||
if (sfr_data[2] & 0x20)
|
||||
print_string(" TRAINING");
|
||||
if (sfr_data[2] & 0x40)
|
||||
print_string(" MASTER");
|
||||
__xdata uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
}
|
||||
b = ledid & 1 ? b >> 4 : b & 0xf;
|
||||
if (b & 0x1)
|
||||
print_string(" 10G");
|
||||
if (b & 0x2)
|
||||
print_string(" TWO_5G");
|
||||
if (b & 0x4)
|
||||
print_string(" 5G");
|
||||
if (b & 0x8)
|
||||
print_string(" TWO_2G5");
|
||||
print_string("), ");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void leds_setup(void) __banked
|
||||
{
|
||||
@@ -261,7 +118,7 @@ void leds_setup(void) __banked
|
||||
sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0;
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
__code uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
||||
__code const uint8_t * __xdata lptr = &machine.led_sets[0][0];
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
sfr_data[0] = *(lptr + 5);
|
||||
sfr_data[1] = *(lptr + 4);
|
||||
@@ -275,7 +132,7 @@ void leds_setup(void) __banked
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
sfr_data[3 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
sfr_data[3 - ((set - 2) << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
}
|
||||
lptr += 8;
|
||||
@@ -291,7 +148,7 @@ void leds_setup(void) __banked
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET1);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
sfr_data[2 - (set << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
sfr_data[2 - ((set - 2) << 1)] = (*(lptr + 6) << 4) | (*(lptr + 2));
|
||||
reg_write_m(RTL837X_REG_LED3_0_SET3);
|
||||
}
|
||||
lptr += 8;
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_leds.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
void leds_dump(void) __banked
|
||||
{
|
||||
print_string("RTL837X_PIN_MUX_0: "); print_reg(RTL837X_PIN_MUX_0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_IO_EN: "); print_reg(RTL837X_REG_LED_GLB_IO_EN); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET0: "); print_reg(RTL837X_REG_LED1_0_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET0: "); print_reg(RTL837X_REG_LED3_2_SET0); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET1: "); print_reg(RTL837X_REG_LED1_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET1: "); print_reg(RTL837X_REG_LED3_2_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET2: "); print_reg(RTL837X_REG_LED1_0_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET2: "); print_reg(RTL837X_REG_LED3_2_SET2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED1_0_SET3: "); print_reg(RTL837X_REG_LED1_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_2_SET3: "); print_reg(RTL837X_REG_LED3_2_SET3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET1: "); print_reg(RTL837X_REG_LED3_0_SET1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED3_0_SET3: "); print_reg(RTL837X_REG_LED3_0_SET3); write_char('\n');
|
||||
print_string("RTL837X_LED_PORT_SET_SEL: "); print_reg(RTL837X_LED_PORT_SET_SEL); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_1: "); print_reg(RTL837X_REG_LED_GLB_MUX_1); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_2: "); print_reg(RTL837X_REG_LED_GLB_MUX_2); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_3: "); print_reg(RTL837X_REG_LED_GLB_MUX_3); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_4: "); print_reg(RTL837X_REG_LED_GLB_MUX_4); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_5: "); print_reg(RTL837X_REG_LED_GLB_MUX_5); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_MUX_6: "); print_reg(RTL837X_REG_LED_GLB_MUX_6); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_GLB_ACTIVE: "); print_reg(RTL837X_REG_LED_GLB_ACTIVE); write_char('\n');
|
||||
print_string("RTL837X_REG_LED_MODE: "); print_reg(RTL837X_REG_LED_MODE); write_char('\n');
|
||||
print_string("LED pad Configuration:\n");
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
print_byte(i);
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
for (uint8_t i = 0; i < 28; i++) {
|
||||
switch (i % 5) {
|
||||
case 0: // 0
|
||||
reg_read_m(RTL837X_REG_LED_GLB_MUX_1 + (i / 5) * 4);
|
||||
print_byte(sfr_data[3] & 0x3f);
|
||||
break;
|
||||
case 1: // 6
|
||||
print_byte(((sfr_data[3] >> 6) | (sfr_data[2] << 2)) & 0x3f);
|
||||
break;
|
||||
case 2: // 12
|
||||
print_byte(((sfr_data[1] << 4) | (sfr_data[2] >> 4)) & 0x3f);
|
||||
break;
|
||||
case 3: // 18
|
||||
print_byte((sfr_data[1] >> 2) & 0x3f);
|
||||
break;
|
||||
case 4: // 24
|
||||
print_byte(sfr_data[0] & 0x3f);
|
||||
break;
|
||||
}
|
||||
write_char(' ');
|
||||
}
|
||||
write_char('\n');
|
||||
print_string("LED-set Configuration:\n");
|
||||
print_string("LED-ID\t\t0\t\t1\t\t2\t\t3\n");
|
||||
for (__xdata uint8_t set = 0; set < 4; set++) {
|
||||
print_string("SET "); write_char('0' + set); write_char(':');
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
print_string("\t ");
|
||||
uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
print_byte(ledid & 1 ? b >> 4 : b & 0xf);
|
||||
}
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (! (ledid & 1)) { // LEDID 0, 2
|
||||
print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
} else {
|
||||
print_byte(sfr_data[0]); print_byte(sfr_data[1]);
|
||||
}
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
|
||||
reg_read_m(RTL837X_LED_PORT_SET_SEL);
|
||||
__xdata uint8_t set = sfr_data[3 - (i >> 2)];
|
||||
set = (set >> ((i & 3) << 1));
|
||||
print_string("Port "); write_char('0' + i); print_string(": SET ");
|
||||
write_char('0' + set);
|
||||
print_string(": ");
|
||||
for (__xdata uint8_t ledid = 0; ledid < 4; ledid++) {
|
||||
write_char('(');
|
||||
reg_read_m(RTL837X_REG_LED1_0_SET0 - set * 8 - ((ledid >> 1) * 4));
|
||||
if (ledid & 1) { // LEDID 1, 3
|
||||
sfr_data[2] = sfr_data[0];
|
||||
sfr_data[3] = sfr_data[1];
|
||||
}
|
||||
if (sfr_data[3] & 0x01)
|
||||
print_string(" 2G5");
|
||||
if (sfr_data[3] & 0x02)
|
||||
print_string(" TWO_1G");
|
||||
if (sfr_data[3] & 0x04)
|
||||
print_string(" 1G");
|
||||
if (sfr_data[3] & 0x08)
|
||||
print_string(" 500M");
|
||||
if (sfr_data[3] & 0x10)
|
||||
print_string(" 100M");
|
||||
if (sfr_data[3] & 0x20)
|
||||
print_string(" 10M");
|
||||
if (sfr_data[3] & 0x40)
|
||||
print_string(" LINK");
|
||||
if (sfr_data[3] & 0x80)
|
||||
print_string(" LINK_FLASH");
|
||||
if (sfr_data[2] & 0x01)
|
||||
print_string(" ACT");
|
||||
if (sfr_data[2] & 0x02)
|
||||
print_string(" RX");
|
||||
if (sfr_data[2] & 0x04)
|
||||
print_string(" TX");
|
||||
if (sfr_data[2] & 0x08)
|
||||
print_string(" COL");
|
||||
if (sfr_data[2] & 0x10)
|
||||
print_string(" DUPLEX");
|
||||
if (sfr_data[2] & 0x20)
|
||||
print_string(" TRAINING");
|
||||
if (sfr_data[2] & 0x40)
|
||||
print_string(" MASTER");
|
||||
__xdata uint8_t b;
|
||||
if (set < 2) {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET1);
|
||||
b = sfr_data[3-((set << 1) + (ledid >> 1))];
|
||||
} else {
|
||||
reg_read_m(RTL837X_REG_LED3_0_SET3);
|
||||
b = sfr_data[3-(((set-2) << 1) + (ledid >> 1))];
|
||||
}
|
||||
b = ledid & 1 ? b >> 4 : b & 0xf;
|
||||
if (b & 0x1)
|
||||
print_string(" 10G");
|
||||
if (b & 0x2)
|
||||
print_string(" TWO_5G");
|
||||
if (b & 0x4)
|
||||
print_string(" 5G");
|
||||
if (b & 0x8)
|
||||
print_string(" TWO_2G5");
|
||||
print_string("), ");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_lldp.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "dhcp.h"
|
||||
#include "uip.h"
|
||||
#include "uip/uip.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __xdata bool lldp_enabled;
|
||||
extern __code const struct machine machine;
|
||||
|
||||
__xdata uint16_t lldp_ticks;
|
||||
__xdata uint16_t lldp_logical_port_status = 0xffff;
|
||||
|
||||
void lldp_init(void) __banked
|
||||
{
|
||||
lldp_ticks = 0;
|
||||
}
|
||||
|
||||
void lldp_tick(void) __banked
|
||||
{
|
||||
lldp_ticks++;
|
||||
|
||||
if (lldp_ticks < LLDP_TX_INTERVAL_TICKS)
|
||||
return;
|
||||
|
||||
lldp_ticks = 0;
|
||||
|
||||
if(lldp_enabled == 1)
|
||||
lldp_send();
|
||||
}
|
||||
|
||||
//Outgoing LLDP packet.
|
||||
|
||||
struct lldp_pkt {
|
||||
struct uip_eth_addr dst;
|
||||
struct uip_eth_addr src;
|
||||
struct rtl_tag rtl_tag;
|
||||
uint16_t ether_type;
|
||||
|
||||
uint8_t payload[64];
|
||||
};
|
||||
|
||||
#define LLDP_O ((__xdata struct lldp_pkt *)&uip_buf[RTL_FRAME_DESC_SIZE])
|
||||
|
||||
// The type is 7 bits and the length is 9 bits
|
||||
// we can represent this as the 7 most significant
|
||||
// bits of the type bit and leave the least significant
|
||||
// bit as 0 always as we're not going to need 2^9 for
|
||||
// the length at any point
|
||||
#define LLDP_TYPE(value) (value << 1)
|
||||
|
||||
void lldp_send(void) __banked __reentrant
|
||||
{
|
||||
__xdata uint8_t *p;
|
||||
uint8_t port_position;
|
||||
|
||||
lldp_set_addresses();
|
||||
lldp_set_rtl_wrapper();
|
||||
|
||||
p = LLDP_O->payload;
|
||||
|
||||
//Chassis ID
|
||||
*p++ = LLDP_TYPE(LLDP_CHASSIS_ID_TLV_TYPE);
|
||||
*p++ = LLDP_CHASSIS_ID_TLV_LENGTH;
|
||||
*p++ = LLDP_CHASSIS_ID_TLV_SUBTYPE;
|
||||
|
||||
memcpy(p, uip_ethaddr.addr, MAC_ADDR_LEN);
|
||||
p += MAC_ADDR_LEN;
|
||||
|
||||
//Port ID
|
||||
*p++ = LLDP_TYPE(LLDP_PORT_ID_TLV_TYPE);
|
||||
*p++ = LLDP_PORT_ID_TLV_LENGTH;
|
||||
*p++ = LLDP_PORT_ID_TLV_SUBTYPE;
|
||||
port_position = (p-LLDP_O->payload);
|
||||
*p++ = '0'; // filled in per port below
|
||||
|
||||
//TTL
|
||||
*p++ = LLDP_TYPE(LLDP_TTL_TLV_TYPE);
|
||||
*p++ = LLDP_TTL_TLV_LENGTH;
|
||||
*p++ = 0x00; //padding
|
||||
*p++ = LLDP_TTL_TTL_SECONDS;
|
||||
|
||||
p += lldp_sysname(p);
|
||||
p += lldp_sysdesc(p);
|
||||
|
||||
// End of LLDPDU TLV
|
||||
*p++ = 0x00; //padding
|
||||
*p++ = 0x00; //padding
|
||||
|
||||
while (p < (LLDP_O->payload + LLDP_MIN_ETHERNET_PAYLOAD_LENGTH))
|
||||
*p++ = 0x00;
|
||||
|
||||
/*
|
||||
* uip_len is the Ethernet frame length excluding FCS.
|
||||
*
|
||||
* The frame consists of:
|
||||
*
|
||||
* dst mac
|
||||
* src mac
|
||||
* rtl_tag sizeof(struct rtl_tag)
|
||||
* EtherType (2 bytes)
|
||||
* payload (how far we've moved p pointer)
|
||||
*/
|
||||
uip_len = MAC_ADDR_LEN + MAC_ADDR_LEN + sizeof(struct rtl_tag) + LLDP_ETHERTYPE_LENGTH + (p - LLDP_O->payload);
|
||||
|
||||
for (uint8_t port = machine.min_port; port <= machine.max_port; port++) {
|
||||
|
||||
if ((1 << port) & lldp_logical_port_status) {
|
||||
LLDP_O->payload[port_position] = '0' + machine.log_to_phys_port[port];
|
||||
LLDP_O->rtl_tag.pmask = HTONS((uint16_t)1 << port);
|
||||
|
||||
tcpip_output();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lldp_set_addresses(void) __banked {
|
||||
// LLDP destination multicast addr: 01:80:c2:00:00:0e
|
||||
memcpyc(LLDP_O->dst.addr, "\x01\x80\xc2\x00\x00\x0e", MAC_ADDR_LEN);
|
||||
memcpy(LLDP_O->src.addr, uip_ethaddr.addr, MAC_ADDR_LEN);
|
||||
}
|
||||
|
||||
void lldp_set_rtl_wrapper(void) __banked {
|
||||
/*
|
||||
* This is the RTL CPU tag, not the Ethernet EtherType.
|
||||
* port 0 -> 0x0001
|
||||
* port 1 -> 0x0002
|
||||
* port 2 -> 0x0004
|
||||
*/
|
||||
LLDP_O->rtl_tag.tag = HTONS(RTL_FRAME_TAG_ID);
|
||||
LLDP_O->rtl_tag.version = RTL_FRAME_TAG_VERSION;
|
||||
LLDP_O->rtl_tag.reason = 0x00;
|
||||
LLDP_O->rtl_tag.flags = HTONS(RTL_TAG_LEARN_DIS);
|
||||
|
||||
LLDP_O->ether_type = HTONS(LLDP_ETHERTYPE);
|
||||
}
|
||||
|
||||
uint8_t lldp_sysname(__xdata uint8_t *p) __banked
|
||||
{
|
||||
uint8_t hostname_length = strlen_x(hostname);
|
||||
|
||||
*p++ = LLDP_TYPE(LLDP_SYSNAME_TLV_TYPE);
|
||||
*p++ = hostname_length;
|
||||
memcpy(p, hostname, hostname_length);
|
||||
return hostname_length + 2;
|
||||
}
|
||||
|
||||
uint8_t lldp_sysdesc(__xdata uint8_t *p) __banked
|
||||
{
|
||||
uint16_t machine_name_length = strlen(machine.machine_name);
|
||||
|
||||
*p++ = LLDP_TYPE(LLDP_SYSDESC_TLV_TYPE);
|
||||
*p++ = machine_name_length;
|
||||
memcpyc(p, machine.machine_name, machine_name_length);
|
||||
return machine_name_length + 2;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _LLDP_H_
|
||||
#define _LLDP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LLDP_MIN_ETHERNET_PAYLOAD_LENGTH 46
|
||||
#define LLDP_ETHERTYPE 0x88cc
|
||||
#define LLDP_ETHERTYPE_LENGTH 2
|
||||
#define LLDP_MAX_FRAME 256
|
||||
#define MAC_ADDR_LEN 6
|
||||
#define LLDP_TX_INTERVAL_TICKS 6000
|
||||
|
||||
#define LLDP_PORT_ID_TLV_TYPE 2
|
||||
#define LLDP_PORT_ID_TLV_LENGTH 0x02
|
||||
#define LLDP_PORT_ID_TLV_SUBTYPE 0x07
|
||||
|
||||
#define LLDP_TTL_TLV_TYPE 3
|
||||
#define LLDP_TTL_TLV_LENGTH 2
|
||||
#define LLDP_TTL_TTL_SECONDS 120
|
||||
|
||||
#define LLDP_CHASSIS_ID_TLV_TYPE 1
|
||||
#define LLDP_CHASSIS_ID_TLV_LENGTH 7
|
||||
#define LLDP_CHASSIS_ID_TLV_SUBTYPE 4
|
||||
|
||||
#define LLDP_SYSNAME_TLV_TYPE 5
|
||||
#define LLDP_SYSDESC_TLV_TYPE 6
|
||||
|
||||
void lldp_init(void) __banked;
|
||||
void lldp_tick(void) __banked;
|
||||
void lldp_send(void) __banked;
|
||||
void lldp_set_addresses(void) __banked;
|
||||
void lldp_set_rtl_wrapper(void) __banked;
|
||||
uint8_t lldp_sysname(__xdata uint8_t *p) __banked;
|
||||
uint8_t lldp_sysdesc(__xdata uint8_t *p) __banked;
|
||||
|
||||
#endif
|
||||
@@ -20,9 +20,11 @@
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code uint16_t bit_mask[16];
|
||||
extern __code const uint16_t bit_mask[16];
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
extern __xdata uint32_t rtl8224_release_tick;
|
||||
|
||||
__xdata struct phy_settings phy_settings;
|
||||
|
||||
@@ -33,7 +35,7 @@ __xdata struct phy_settings phy_settings;
|
||||
// Note: Adding `Swapping the RX for N-devices`-setting on the end of the array, didn't work.
|
||||
// Setting will apply but still no packets flow.
|
||||
// Settings are `0x2000, 0xc10c`,
|
||||
__code uint16_t rtl8224_sds0_setttings[42] = {
|
||||
__code const uint16_t rtl8224_sds0_setttings[42] = {
|
||||
// SDS_DATA, SDS_CMD
|
||||
0x4480, 0xc842,
|
||||
0x0400, 0xc9c2,
|
||||
@@ -214,9 +216,20 @@ void phy_config(uint8_t phy) __banked
|
||||
}
|
||||
|
||||
|
||||
void rtl8224_wait_ready(void) __banked
|
||||
{
|
||||
do {
|
||||
rtl8224_read_reg_u16(RTL837X_REG_CHIP_ID + 1);
|
||||
if (SFR_DATA_U16 == 0x8224)
|
||||
return;
|
||||
} while ((ticks - rtl8224_release_tick) < (SYS_TICK_HZ * 5 / 2));
|
||||
print_string("\r\nRTL8224 not responding\r\n");
|
||||
}
|
||||
|
||||
void phy_config_8224(void) __banked
|
||||
{
|
||||
uint16_t pval;
|
||||
uint16_t tries;
|
||||
print_string("\r\nphy_config_8224 called\r\nRTL8224 ID: ");
|
||||
|
||||
// Print RTL8224 chip id
|
||||
@@ -244,9 +257,12 @@ void phy_config_8224(void) __banked
|
||||
i++;
|
||||
rtl8224_write_reg_u16(RTL837X_SDS_INDACS_CMD, rtl8224_sds0_setttings[i]);
|
||||
i++;
|
||||
tries = 0xffff;
|
||||
do {
|
||||
rtl8224_read_reg_u16(0x3f8);
|
||||
} while (SFR_DATA_8 & 0x80);
|
||||
} while ((SFR_DATA_8 & 0x80) && --tries);
|
||||
if (SFR_DATA_8 & 0x80)
|
||||
print_string("\r\nRTL8224 SerDes access timed out\r\n");
|
||||
}
|
||||
|
||||
print_string("\r\nphy_config_8224 done\r\n");
|
||||
@@ -354,8 +370,9 @@ void phy_set_speed(void) __banked
|
||||
phy_modify(phy_settings.port, PHY_MMD31, PHY_MMD31_GBCR, 0x0200, 0x0000);
|
||||
} else {
|
||||
// AN Advertisement Register (MMD 7.0x0010)
|
||||
// bits 0-4: 0x1 (802.3 supported), Extended Next Page format used
|
||||
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1001);
|
||||
// bits 0-4: 0x1 (802.3 supported), bit 10: PAUSE,
|
||||
// Extended Next Page format used
|
||||
phy_write(phy_settings.port, PHY_MMD_AN, PHY_ANEG_ADV, 0x1401);
|
||||
if (phy_settings.speed == PHY_SPEED_1G) {
|
||||
// Multi-GBASE-TBASE-T AN Control 1 Register (MMD 7.0x0020)
|
||||
// bit 14: SLAVE, bit 13: Multi-Port device, 1: LD Loop timin enableed
|
||||
|
||||
@@ -22,6 +22,7 @@ extern __xdata struct phy_settings phy_settings;
|
||||
void rtl8224_phy_enable(void) __banked;
|
||||
void phy_config(uint8_t phy) __banked;
|
||||
void phy_config_8224(void) __banked;
|
||||
void rtl8224_wait_ready(void) __banked;
|
||||
void phy_set_speed(void) __banked;
|
||||
void phy_set_duplex(void) __banked;
|
||||
void phy_show(uint8_t port) __banked;
|
||||
|
||||
@@ -10,38 +10,6 @@ extern __xdata uint8_t sfr_data[4];
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked {
|
||||
switch (sda_pin) {
|
||||
case GPIO47_I2C_SDA0:
|
||||
return 0;
|
||||
case GPIO49_I2C_SDA1:
|
||||
return 1;
|
||||
case GPIO51_I2C_SDA2_UART1_RX:
|
||||
return 2;
|
||||
case GPIO41_I2C_SDA3_MDIO1:
|
||||
return 3;
|
||||
case GPIO39_I2C_SDA4:
|
||||
return 4;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked{
|
||||
switch (scl_pin) {
|
||||
case GPIO46_I2C_SCL0:
|
||||
return 0;
|
||||
case GPIO48_I2C_SCL1:
|
||||
return 1;
|
||||
case GPIO50_I2C_SCL2_UART1_TX:
|
||||
return 2;
|
||||
case GPIO40_I2C_SCL3_MDC1:
|
||||
return 3;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns RTL837X_REG_GPIO_XX_OUTPUT register address */
|
||||
static uint16_t gpio_output_reg(uint8_t pin) __banked{
|
||||
return pin < 32 ? RTL837X_REG_GPIO_00_31_OUTPUT : RTL837X_REG_GPIO_32_63_OUTPUT;
|
||||
@@ -147,8 +115,7 @@ bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
|
||||
|
||||
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
|
||||
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
|
||||
(dev >> 5) | i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5
|
||||
| i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2,
|
||||
(dev >> 5) | machine.sfp_port[slot].i2c,
|
||||
((dev << 3) & 0xff) | 0x1);
|
||||
|
||||
do {
|
||||
|
||||
@@ -71,12 +71,6 @@
|
||||
/* Not available GPIO */
|
||||
#define GPIO_NA 0xFF
|
||||
|
||||
/* Convert SDA PIN GPIO to I2C bus number */
|
||||
uint8_t i2c_bus_from_sda_pin(uint8_t sda_pin) __banked;
|
||||
|
||||
/* Convert SCL PIN GPIO to I2C bus number */
|
||||
uint8_t i2c_bus_from_scl_pin(uint8_t scl_pin) __banked;
|
||||
|
||||
/*
|
||||
* Setup a GPIO pin as input
|
||||
* pin: GPIO pin number 0-63
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
extern __code uint8_t * __code hex;
|
||||
extern __code uint16_t bit_mask[16];
|
||||
extern __code struct machine machine;
|
||||
extern __code const uint8_t * __code const hex;
|
||||
extern __code const uint16_t bit_mask[16];
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata uint16_t vlan_ptr;
|
||||
extern __xdata uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
@@ -40,7 +40,6 @@ static void wait_table_ready(void)
|
||||
|
||||
void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked
|
||||
{
|
||||
print_string("\nport_mirror_set called \n");
|
||||
print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: ");
|
||||
print_short(rx_pmask); print_string(", tx mask: "); print_short(tx_pmask);
|
||||
write_char('\n');
|
||||
@@ -52,7 +51,6 @@ void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t t
|
||||
|
||||
void port_mirror_del(void) __banked
|
||||
{
|
||||
print_string("\nport_mirror_del called \n");
|
||||
REG_SET(RTL837x_MIRROR_CTRL, 0);
|
||||
}
|
||||
|
||||
@@ -102,9 +100,9 @@ static void port_pvid_write(uint8_t port, __xdata uint16_t pvid)
|
||||
|
||||
reg_read_m(reg);
|
||||
if (port & 0x1) {
|
||||
REG_WRITE(reg, sfr_data[0], pvid >> 4, sfr_data[2] & 0x0f | (pvid << 4), sfr_data[3]);
|
||||
REG_WRITE(reg, sfr_data[0], pvid >> 4, (sfr_data[2] & 0x0f) | (pvid << 4), sfr_data[3]);
|
||||
} else {
|
||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0 | (pvid >> 8), pvid);
|
||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], (sfr_data[2] & 0xf0) | (pvid >> 8), pvid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +110,6 @@ void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked
|
||||
{
|
||||
uint8_t lag = port_lag_of(port);
|
||||
|
||||
print_string("\nport_pvid_set called \n");
|
||||
if (lag == PORT_LAG_NONE) {
|
||||
port_pvid_write(port, pvid);
|
||||
return;
|
||||
@@ -141,7 +138,6 @@ void vlan_delete(uint16_t vlan) __banked
|
||||
if (!vlan || vlan >= 0xfff)
|
||||
return;
|
||||
|
||||
print_string("\nvlan_delete called \n"); print_short(vlan);
|
||||
vlan_name_remove(vlan);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_A, 0, 0, 0, 0);
|
||||
REG_WRITE(RTL837X_TBL_CTRL, vlan >> 8, vlan, TBL_VLAN, TBL_WRITE | TBL_EXECUTE);
|
||||
@@ -232,7 +228,7 @@ void vlan_create(void) __banked
|
||||
vlan_settings.members |= 0x0200; // Set 10th bit
|
||||
vlan_settings.tagged |= 0x0200;
|
||||
|
||||
print_string("\nvlan_create called\nvlan: "); print_short(vlan_settings.vlan);
|
||||
print_string("vlan: "); print_short(vlan_settings.vlan);
|
||||
print_string(", members: "); print_short(vlan_settings.members);
|
||||
print_string(", tagged: "); print_short(vlan_settings.tagged); write_char('\n');
|
||||
|
||||
@@ -250,7 +246,6 @@ void vlan_create(void) __banked
|
||||
|
||||
wait_table_ready();
|
||||
|
||||
print_string("vlan_create done \n");
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +258,6 @@ void vlan_create(void) __banked
|
||||
*/
|
||||
void vlan_setup(void) __banked
|
||||
{
|
||||
print_string("\nvlan_setup called \n");
|
||||
|
||||
// No VLAN names set up so far
|
||||
vlan_ptr = 0;
|
||||
@@ -285,7 +279,7 @@ void vlan_setup(void) __banked
|
||||
#endif
|
||||
reg_read_m(reg);
|
||||
if (i & 0x1) {
|
||||
REG_WRITE(reg, sfr_data[0], 0, sfr_data[2] & 0x0f | 0x10, sfr_data[3]);
|
||||
REG_WRITE(reg, sfr_data[0], 0, (sfr_data[2] & 0x0f) | 0x10, sfr_data[3]);
|
||||
} else {
|
||||
REG_WRITE(reg, sfr_data[0], sfr_data[1], sfr_data[2] & 0xf0, 0x01);
|
||||
}
|
||||
@@ -331,7 +325,6 @@ void vlan_setup(void) __banked
|
||||
print_string("\nvlan_setup, REG 0x4f4c: "); print_reg(0x4f4c);
|
||||
#endif
|
||||
|
||||
print_string("vlan_setup done \n");
|
||||
}
|
||||
|
||||
|
||||
@@ -354,7 +347,6 @@ void port_l2_forget_port(uint8_t port) __banked
|
||||
*/
|
||||
uint8_t port_l2_forget(void) __banked
|
||||
{
|
||||
print_string("\nport_l2_forget called\n");
|
||||
// Configure the entries to be flushed:
|
||||
// port-based (bits 0-1 are 0 and dynamic entries, bit 2 specifies dynamic entries
|
||||
REG_SET(RTL837x_L2_TBL_FLUSH_CNF, 0x0);
|
||||
@@ -370,7 +362,6 @@ uint8_t port_l2_forget(void) __banked
|
||||
reg_read_m(RTL837x_L2_TBL_FLUSH_CTRL);
|
||||
} while (sfr_data[1]);
|
||||
|
||||
print_string("port_l2_forget done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -465,7 +456,6 @@ void port_l2mc_set(uint8_t mac_last, __xdata uint16_t vid, __xdata uint16_t pmas
|
||||
*/
|
||||
void port_l2_setup(void) __banked
|
||||
{
|
||||
print_string("\nport_l2_setup called\n");
|
||||
|
||||
port_l2_forget();
|
||||
|
||||
@@ -483,7 +473,38 @@ void port_l2_setup(void) __banked
|
||||
// When maximim entries learned, then simply flood the packet
|
||||
reg_bit_set(RTL837X_L2_LRN_PORT_CONSTRT_ACT, 0);
|
||||
|
||||
print_string("\nport_l2_setup done\n");
|
||||
}
|
||||
|
||||
|
||||
void port_media_show(uint8_t port) __banked
|
||||
{
|
||||
uint8_t pause;
|
||||
|
||||
if (!machine.is_sfp[port]) {
|
||||
reg_read_m(RTL837X_REG_LINKS_STS);
|
||||
if (sfr_data[(port / 8) + 1] >> (port % 8) & 1) {
|
||||
print_string("Link role: ");
|
||||
reg_read_m(RTL837X_MAC_MSTR_SLV_STS);
|
||||
if (sfr_data[3 - (port >> 3)] & (1 << (port & 7)))
|
||||
print_string("master\n");
|
||||
else
|
||||
print_string("slave\n");
|
||||
}
|
||||
}
|
||||
|
||||
print_string("Pause negotiated:");
|
||||
reg_read_m(RTL837X_MAC_TX_PAUSE_STS);
|
||||
pause = sfr_data[3 - (port >> 3)] & (1 << (port & 7));
|
||||
if (pause)
|
||||
print_string(" TX");
|
||||
reg_read_m(RTL837X_MAC_RX_PAUSE_STS);
|
||||
if (sfr_data[3 - (port >> 3)] & (1 << (port & 7))) {
|
||||
print_string(" RX");
|
||||
pause = 1;
|
||||
}
|
||||
if (!pause)
|
||||
print_string(" none");
|
||||
write_char('\n');
|
||||
}
|
||||
|
||||
|
||||
@@ -590,12 +611,12 @@ void port_eee_enable(__xdata uint8_t port,__xdata uint8_t speed) __banked
|
||||
|
||||
if (machine.is_sfp[port])
|
||||
{
|
||||
print_string("EEE can't be enabled for SFP port "); print_byte(port); print_string("\n");
|
||||
print_string("EEE can't be enabled for SFP port "); print_phys_port(port); print_string("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), EEE_RX_ENABLE | EEE_TX_ENABLE);
|
||||
print_string("EEE on for "); print_byte(port); print_string(" speed ");
|
||||
print_string("EEE on for "); print_phys_port(port); print_string(" speed ");
|
||||
// Enable all speeds up to the specified speed
|
||||
if (speed & EEE_100) {
|
||||
print_string("100m\n");
|
||||
@@ -654,7 +675,7 @@ void port_eee_disable(uint8_t port) __banked
|
||||
if (machine.is_sfp[port])
|
||||
return;
|
||||
|
||||
print_string("EEE off for "); print_byte(port); write_char('\n');
|
||||
print_string("EEE off for "); print_phys_port(port); write_char('\n');
|
||||
REG_SET(RTL837X_EEE_CTRL_BASE + (port << 8), 0);
|
||||
// Disable EEE advertisement for 100/1000BASE-T via EEE Advertisement Reg
|
||||
phy_write(port, PHY_MMD_AN, PHY_EEE_ADV, 0);
|
||||
@@ -758,7 +779,7 @@ void port_eee_enable_all(__xdata uint8_t speed) __banked
|
||||
port_eee_enable(i, speed);
|
||||
} else {
|
||||
if (speed & EEE_10G)
|
||||
port_eee_enable(i, speed & EEE_NORESET | EEE_2G5);
|
||||
port_eee_enable(i, (speed & EEE_NORESET) | EEE_2G5);
|
||||
else
|
||||
port_eee_enable(i, speed);
|
||||
}
|
||||
@@ -899,7 +920,7 @@ void vlan_dump(void) __banked
|
||||
/** Set the ingress VLAN filtering */
|
||||
bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
||||
{
|
||||
if (port < machine.min_port || port > machine.max_port && port != CPU_PORT) {
|
||||
if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) {
|
||||
return false;
|
||||
}
|
||||
if (enabled)
|
||||
@@ -913,7 +934,7 @@ bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked
|
||||
/** Get the ingress VLAN filtering status */
|
||||
bool port_ingress_vlan_filter_get(uint8_t port) __banked
|
||||
{
|
||||
if (port < machine.min_port || port > machine.max_port && port != CPU_PORT) {
|
||||
if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ extern __xdata struct vlan_settings vlan_settings;
|
||||
uint8_t port_l2_forget(void) __banked;
|
||||
void port_l2_learned(void) __banked;
|
||||
void port_stats_print(void) __banked;
|
||||
void port_media_show(uint8_t port) __banked;
|
||||
int8_t vlan_get(uint16_t vlan) __banked;
|
||||
__xdata uint16_t vlan_name(uint16_t vlan) __banked;
|
||||
void vlan_name_remove(uint16_t vlan) __banked;
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#define RESET_SOC_BIT 0
|
||||
#define RESET_NIC_BIT 2
|
||||
|
||||
#define RTL837X_TM_CTRL2 0x0338
|
||||
#define TM_CTRL2_EN_LATCH 0x04
|
||||
#define RTL837X_TM_RESULT 0x0340
|
||||
#define RTL837X_TM_RESULT_POWERON 0x0350
|
||||
// Temperature: 19 bit value, bits 18:3 in the low 16 bits of the register,
|
||||
// bits 2:0 in bits 18:16. Bit 18 signed, bits 17:10 degrees C, bits 9:0 fraction.
|
||||
|
||||
#define RTL837X_REG_HW_CONF 0x6040
|
||||
// Bits 4 & 5: CLOCK DIVIDER from 125MHz for Timer
|
||||
|
||||
@@ -83,6 +90,10 @@
|
||||
#define RTL837X_REG_LINKS 0x63f0
|
||||
#define RTL837X_REG_LINKS_89 0x63f4
|
||||
#define RTL837X_REG_LINKS_STS 0x63E8
|
||||
/* Per-port status bits: bit N is chip port N */
|
||||
#define RTL837X_MAC_TX_PAUSE_STS 0x63FC
|
||||
#define RTL837X_MAC_RX_PAUSE_STS 0x6400
|
||||
#define RTL837X_MAC_MSTR_SLV_STS 0x6408
|
||||
|
||||
/* Each nibble encodes the link state of a port.
|
||||
Port 0 appears to be the CPU port
|
||||
@@ -126,6 +137,10 @@
|
||||
#define RTL837X_REG_I2C_CTRL2 0x041c
|
||||
#define RTL837X_REG_I2C_IN 0x0420
|
||||
#define RTL837X_REG_I2C_OUT 0x0424
|
||||
#define RTL837X_REG_I2C_SCL_SHIFT 5
|
||||
#define RTL837X_REG_I2C_SDA_SHIFT 2
|
||||
#define RTL837X_REG_I2C_SCL_MASK 0x3
|
||||
#define RTL837X_REG_I2C_SDA_MASK 0x7
|
||||
|
||||
/*
|
||||
* NIC Related registers
|
||||
@@ -137,6 +152,10 @@
|
||||
#define RTL837X_REG_RX_CTRL 0x785c
|
||||
#define RTL837X_REG_TX_CTRL 0x7860
|
||||
#define RTL837X_REG_NIC_RX_BUFF_DATA 0x7874
|
||||
#define RTL837X_NIC_INT_STS 0x7854
|
||||
#define RTL837X_NIC_INT_MSK 0x7858
|
||||
#define NIC_INT_RXIS 0x02
|
||||
#define NIC_INT_RXIE 0x02
|
||||
#define RTL837X_REG_CPU_RX_CURR_PKT 0x787c
|
||||
#define RTL837X_REG_NIC_TX_CURR_PKT 0x7884
|
||||
#define RTL837X_REG_CPU_TX_CURR_PKT 0x7890
|
||||
@@ -144,6 +163,9 @@
|
||||
#define RTL837X_REG_CPU_TAG_AWARE_PMASK 0x603C
|
||||
#define RTL837X_REG_MAC_FORCE_MODE 0x6344
|
||||
|
||||
/* Flags in byte 1 of the RX frame descriptor */
|
||||
#define RX_TAG_L4_CSUM_BAD 0x04
|
||||
|
||||
/*
|
||||
* Statistics related registers
|
||||
*/
|
||||
@@ -263,6 +285,9 @@
|
||||
*/
|
||||
#define RTL8373_RLDP_TIMER 0x1074
|
||||
#define RTL837X_RMA0_CONF 0x4ecc
|
||||
#define RTL837X_IMR_INT_PORT_LINK_STS_CHG 0x5f34
|
||||
#define RTL837X_ISR_SW_INT_MODE 0x5f84
|
||||
#define RTL837X_ISR_INT_PORT_LINK_CHG 0x5f88
|
||||
#define RTL837X_RMA_CONF 0x4f1c
|
||||
#define RTL837X_MSTP_STATES 0x5310
|
||||
#define RTL837X_REG_LED_RLDP_1 0x65F8
|
||||
@@ -302,6 +327,11 @@
|
||||
#define RTL837X_IGBW_PORT_FC_CTRL 0x4C8C
|
||||
#define RTL837X_EGBW_PORT_CTRL 0x1c34
|
||||
#define RTL837X_EGBW_CTRL 0x447c
|
||||
#define RTL837X_STORM_CTRL 0x54e4
|
||||
#define RTL837X_STORM_MIDX 0x54f4
|
||||
#define RTL837X_METER_RATE 0x5cf0
|
||||
#define RTL837X_METER_BURST 0x5df0
|
||||
#define RTL837X_METER_MODE 0x5ef0
|
||||
#define EGBW_INC_IFG 0x02
|
||||
#define EGBW_CPUMODE 0x01
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <stdint.h>
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_sfr.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_storm.h"
|
||||
#include "machine.h"
|
||||
|
||||
#pragma codeseg BANK3
|
||||
#pragma constseg BANK3
|
||||
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
|
||||
/* RTL837X_STORM_MIDX words, row type * 2 + half: half 0 holds ports 0-4, half 1 ports 5-9,
|
||||
* 6 bits per port, each set to STORM_METER(port, type) */
|
||||
static const __code uint8_t storm_midx[8][4] = {
|
||||
{ 0x28, 0x92, 0x07, 0x18 }, { 0x3c, 0xe3, 0x4c, 0x2c },
|
||||
{ 0x29, 0x96, 0x17, 0x59 }, { 0x3d, 0xe7, 0x5c, 0x6d },
|
||||
{ 0x2a, 0x9a, 0x27, 0x9a }, { 0x3e, 0xeb, 0x6c, 0xae },
|
||||
{ 0x2b, 0x9e, 0x37, 0xdb }, { 0x3f, 0xef, 0x7c, 0xef },
|
||||
};
|
||||
|
||||
static __code const char * __code const storm_names[STORM_TYPES] = { " bcast ", " mcast ", " ucast ", " umcast " };
|
||||
|
||||
|
||||
void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked
|
||||
{
|
||||
__xdata uint8_t idx = STORM_METER(port, type);
|
||||
__xdata uint8_t row = (type << 1) | (port >= 5 ? 1 : 0);
|
||||
__xdata uint8_t * __xdata r = (uint8_t *)&rate;
|
||||
|
||||
sfr_data[0] = 0;
|
||||
sfr_data[1] = r[2];
|
||||
sfr_data[2] = r[1];
|
||||
sfr_data[3] = r[0];
|
||||
reg_write_m(RTL837X_METER_RATE + (idx << 2));
|
||||
|
||||
if (!pps) {
|
||||
sfr_data[1] = 0;
|
||||
sfr_data[2] = 0x20;
|
||||
sfr_data[3] = 0;
|
||||
}
|
||||
reg_write_m(RTL837X_METER_BURST + (idx << 2));
|
||||
|
||||
if (pps)
|
||||
reg_bit_set(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f);
|
||||
else
|
||||
reg_bit_clear(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f);
|
||||
|
||||
sfr_data[0] = storm_midx[row][0];
|
||||
sfr_data[1] = storm_midx[row][1];
|
||||
sfr_data[2] = storm_midx[row][2];
|
||||
sfr_data[3] = storm_midx[row][3];
|
||||
reg_write_m(RTL837X_STORM_MIDX + (row << 2));
|
||||
|
||||
reg_bit_set(RTL837X_STORM_CTRL + (type << 2), port);
|
||||
}
|
||||
|
||||
|
||||
void storm_off(uint8_t port, __xdata uint8_t type) __banked
|
||||
{
|
||||
reg_bit_clear(RTL837X_STORM_CTRL + (type << 2), port);
|
||||
}
|
||||
|
||||
|
||||
void storm_show(void) __banked
|
||||
{
|
||||
uint8_t i, t, idx;
|
||||
|
||||
for (i = machine.min_port; i <= machine.max_port; i++) {
|
||||
print_string("port ");
|
||||
write_char('0' + machine.log_to_phys_port[i]);
|
||||
for (t = 0; t < STORM_TYPES; t++) {
|
||||
print_string(storm_names[t]);
|
||||
if (!reg_bit_test(RTL837X_STORM_CTRL + (t << 2), i)) {
|
||||
print_string("off");
|
||||
continue;
|
||||
}
|
||||
idx = STORM_METER(i, t);
|
||||
reg_read_m(RTL837X_METER_RATE + (idx << 2));
|
||||
print_byte(sfr_data[1]); print_byte(sfr_data[2]); print_byte(sfr_data[3]);
|
||||
if (reg_bit_test(RTL837X_METER_MODE + ((idx >> 5) << 2), idx & 0x1f))
|
||||
print_string(" pps");
|
||||
else
|
||||
print_string(" kbps");
|
||||
}
|
||||
write_char('\n');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _RTL837X_STORM_H_
|
||||
#define _RTL837X_STORM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define STORM_TYPES 4
|
||||
#define STORM_METER_BASE 24
|
||||
#define STORM_METER(port, type) (STORM_METER_BASE + (((port) << 2) | (type)))
|
||||
|
||||
void storm_set(uint8_t port, __xdata uint8_t type, __xdata uint32_t rate, __xdata uint8_t pps) __banked;
|
||||
void storm_off(uint8_t port, __xdata uint8_t type) __banked;
|
||||
void storm_show(void) __banked;
|
||||
|
||||
#endif
|
||||
@@ -15,12 +15,14 @@
|
||||
#include "uip.h"
|
||||
#include "machine.h"
|
||||
|
||||
extern __xdata uint8_t err_status;
|
||||
|
||||
// All entry points are __banked and nothing here runs from an interrupt,
|
||||
// so the module does not need to stay in the resident bank
|
||||
#pragma codeseg BANK2
|
||||
#pragma constseg BANK2
|
||||
|
||||
extern __code struct machine machine;
|
||||
extern __code const struct machine machine;
|
||||
extern __xdata uint8_t sfr_data[4];
|
||||
extern __xdata struct machine_runtime machine_detected;
|
||||
|
||||
@@ -33,7 +35,7 @@ extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
|
||||
extern __xdata uint8_t cmd_words_len;
|
||||
extern __xdata uint8_t cmd_words_b[15];
|
||||
extern __xdata char save_cmd; /* 0 while execute_config() replays the saved config */
|
||||
uint8_t cmd_compare(uint8_t start, __code uint8_t * cmd);
|
||||
uint8_t cmd_compare(uint8_t start, __code const uint8_t * cmd);
|
||||
uint8_t atoi_byte(uint8_t idx);
|
||||
uint8_t cmd_parse_port_separator(uint8_t idx);
|
||||
extern __xdata uint8_t atoi_results_u8;
|
||||
@@ -1134,5 +1136,6 @@ void stp_parse(void) __banked __reentrant
|
||||
}
|
||||
return;
|
||||
err:
|
||||
err_status = ERR_INVALID_ARGUMENT;
|
||||
print_string("Error: stp on|off|status | prio <0-15> | hello <1-10> | maxage <6-40> | fwd <4-30> | txhold <1-10> | version rstp|stp | port <1-9>|lag <1-4> on|off|edge|cost|prio|guard|filter ...\n");
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "rtl837x_leds.h"
|
||||
#include "rtl837x_bandwidth.h"
|
||||
#include "rtl837x_init.h"
|
||||
#include "rtl837x_lldp.h"
|
||||
#include "dhcp.h"
|
||||
#include "cmd_parser.h"
|
||||
#include "cmd_editor.h"
|
||||
@@ -79,20 +80,23 @@ void crc16_bank1(__xdata uint8_t *v) __naked;
|
||||
|
||||
__xdata uint8_t idle_ready;
|
||||
|
||||
__code uint8_t ownIP[] = { 192, 168, 2, 2 };
|
||||
__code uint8_t gatewayIP[] = { 192, 168, 2, 22};
|
||||
__code uint8_t netmask[] = { 255, 255, 255, 0};
|
||||
__code const uint8_t ownIP[] = { 192, 168, 2, 2 };
|
||||
__code const uint8_t gatewayIP[] = { 192, 168, 2, 22};
|
||||
__code const uint8_t netmask[] = { 255, 255, 255, 0};
|
||||
|
||||
__xdata struct uip_eth_addr uip_ethaddr;
|
||||
|
||||
volatile __xdata uint32_t ticks;
|
||||
volatile __xdata uint8_t sec_counter;
|
||||
volatile __xdata uint16_t sleep_ticks;
|
||||
__xdata uint8_t stp_clock;
|
||||
__xdata uint8_t stp_tick_last;
|
||||
__xdata uint8_t arp_age_secs;
|
||||
extern __xdata struct dhcp_state dhcp_state;
|
||||
|
||||
#define STP_TICK_DIVIDER 3
|
||||
#define STP_TICK_STEP (SYS_TICK_HZ / STP_HZ)
|
||||
#define STP_CATCH_UP 8
|
||||
#define SFP_TICK_STEP 10
|
||||
__xdata uint8_t sfp_tick_last;
|
||||
|
||||
/* Buffer for serial input, SBUF_SIZE must be power of 2 < 256
|
||||
* Writing to this buffer is under the sole control of the serial ISR
|
||||
@@ -108,8 +112,8 @@ extern __xdata uint8_t gpio_last_value[8];
|
||||
|
||||
extern __xdata struct flash_region_t flash_region;
|
||||
|
||||
__code uint8_t * __code greeting = "\nA minimal prompt to explore the RTL8372:\n";
|
||||
__code uint8_t * __code hex = "0123456789abcdef";
|
||||
__code const uint8_t * __code const greeting = "\nA minimal prompt to explore the RTL8372:\n";
|
||||
__code const uint8_t * __code const hex = "0123456789abcdef";
|
||||
|
||||
__xdata uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||
|
||||
@@ -124,9 +128,10 @@ __xdata uint8_t tx_seq;
|
||||
|
||||
__xdata bool stp_enabled;
|
||||
__xdata uint8_t igmpEnabled;
|
||||
__xdata bool lldp_enabled;
|
||||
__xdata char hostname[24]; /* device hostname, default set at boot, see rtl837x_common.h */
|
||||
|
||||
__code uint16_t bit_mask[16] = {
|
||||
__code const uint16_t bit_mask[16] = {
|
||||
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
||||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
||||
};
|
||||
@@ -134,6 +139,11 @@ __code uint16_t bit_mask[16] = {
|
||||
|
||||
__xdata uint8_t linkbits_last[4];
|
||||
__xdata uint8_t linkbits_last_p89;
|
||||
__data __at(0x20) volatile uint8_t evflags;
|
||||
volatile __bit __at(0x00) link_irq;
|
||||
volatile __bit __at(0x01) rx_irq;
|
||||
volatile __bit __at(0x02) tick_pending;
|
||||
__bit __at(0x03) cmd_available;
|
||||
// Last known state of the SFP detection/Loss of Signal pins
|
||||
__xdata bool button_last;
|
||||
__xdata uint8_t button_sec_counter_last;
|
||||
@@ -195,6 +205,7 @@ void isr_timer0(void) __interrupt(1)
|
||||
void isr_timer2(void) __interrupt(5)
|
||||
{
|
||||
ticks++;
|
||||
tick_pending = 1;
|
||||
if (sleep_ticks > 0)
|
||||
sleep_ticks--;
|
||||
sec_counter++;
|
||||
@@ -254,8 +265,19 @@ void write_char(char c)
|
||||
write_char_no_syslog(c);
|
||||
|
||||
if (syslog_state.enabled) {
|
||||
logbuf[syslog_state.writeptr++] = c;
|
||||
syslog_state.writeptr &= (LOGBUF_SIZE - 1);
|
||||
__xdata uint16_t next = (syslog_state.writeptr + 1) & (LOGBUF_SIZE - 1);
|
||||
|
||||
/* The ring is drained once per main loop pass, and a single command
|
||||
* can print several times its size, so writing on regardless laps
|
||||
* the reader and the datagram starts mid record. Drop instead, and
|
||||
* flag a line so the reader empties what is there even if no
|
||||
* newline has been seen yet. */
|
||||
if (next == syslog_state.readptr) {
|
||||
syslog_state.line_available = 1;
|
||||
return;
|
||||
}
|
||||
logbuf[syslog_state.writeptr] = c;
|
||||
syslog_state.writeptr = next;
|
||||
if (c == '\n')
|
||||
syslog_state.line_available = 1;
|
||||
}
|
||||
@@ -303,19 +325,19 @@ void itoa_short(uint16_t v)
|
||||
}
|
||||
|
||||
|
||||
void print_string(__code char *p)
|
||||
void print_string(__code const char *p)
|
||||
{
|
||||
while (*p)
|
||||
write_char(*p++);
|
||||
}
|
||||
|
||||
void print_string_no_syslog(__code char *p)
|
||||
void print_string_no_syslog(__code const char *p)
|
||||
{
|
||||
while (*p)
|
||||
write_char_no_syslog(*p++);
|
||||
}
|
||||
|
||||
void print_string_newline_no_syslog(__code char *p)
|
||||
void print_string_newline_no_syslog(__code const char *p)
|
||||
{
|
||||
write_char_no_syslog('\n');
|
||||
print_string_no_syslog(p);
|
||||
@@ -349,7 +371,7 @@ int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len)
|
||||
void memcpyc(__xdata uint8_t *dst, __code const uint8_t *src, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
*dst++ = *src++;
|
||||
@@ -390,6 +412,16 @@ uint16_t strlen_x(__xdata const char *s)
|
||||
}
|
||||
|
||||
|
||||
uint16_t strcpy(__xdata uint8_t *dst, const char *s)
|
||||
{
|
||||
__xdata uint8_t *b = dst;
|
||||
while (*s)
|
||||
*dst++ = *s++;
|
||||
*dst = 0;
|
||||
return dst - b;
|
||||
}
|
||||
|
||||
|
||||
char strcmp(__xdata const uint8_t *a, __code const uint8_t *b)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
@@ -478,14 +510,14 @@ void print_cmd_prompt(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* External IRQ 0 Service Routine: Called on link change?
|
||||
* Note that all registers are being put on the STACK because of calling a subroutine
|
||||
* External IRQ 0 Service Routine: the switch reports a link change. The
|
||||
* register access macros share the SFR data bytes with the main loop, so
|
||||
* the handler only latches the event; idle() reads and clears it.
|
||||
*/
|
||||
void isr_ext0(void) __interrupt(0)
|
||||
{
|
||||
EX0 = 0; // Disable interrupt for the moment
|
||||
IT0 = 1; // Trigger on falling edge of external interrupt
|
||||
EX0 = 1; // Re-enable interrupt
|
||||
EX0 = 0;
|
||||
link_irq = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -494,9 +526,8 @@ void isr_ext0(void) __interrupt(0)
|
||||
*/
|
||||
void isr_ext1(void) __interrupt(2)
|
||||
{
|
||||
// This flag should only be reset after all packets have been read
|
||||
EX1 = 0;
|
||||
EX1 = 1;
|
||||
rx_irq = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -785,7 +816,7 @@ void nic_tx_packet(uint16_t ring_ptr)
|
||||
* Note that the address in the flash memory is not simply 0xbbaddr, because
|
||||
* the size of a bank is merely 0xc000.
|
||||
*/
|
||||
uint8_t read_flash(uint8_t bank, __code uint8_t *addr)
|
||||
uint8_t read_flash(uint8_t bank, __code const uint8_t *addr)
|
||||
{
|
||||
uint8_t v;
|
||||
uint8_t current_bank = PSBANK;
|
||||
@@ -973,14 +1004,19 @@ void tcpip_output(void)
|
||||
}
|
||||
|
||||
|
||||
#define RX_BUDGET 4
|
||||
|
||||
void handle_rx(void)
|
||||
{
|
||||
// Check the amount of data available on the NIC/ASIC side
|
||||
reg_read_m(RTL837X_REG_NIC_RX_BUFF_DATA);
|
||||
if (sfr_data[2] != 0 || sfr_data[3] != 0) {
|
||||
reg_read_m(RTL837X_REG_CPU_RX_CURR_PKT);
|
||||
uint16_t ring_ptr = ((uint16_t)sfr_data[2]) << 8;
|
||||
ring_ptr |= sfr_data[3];
|
||||
__xdata uint8_t budget = RX_BUDGET;
|
||||
|
||||
while (budget--) {
|
||||
// Check the amount of data available on the NIC/ASIC side
|
||||
reg_read(RTL837X_REG_NIC_RX_BUFF_DATA);
|
||||
if (!SFR_DATA_U16)
|
||||
break;
|
||||
reg_read(RTL837X_REG_CPU_RX_CURR_PKT);
|
||||
uint16_t ring_ptr = SFR_DATA_U16;
|
||||
ring_ptr <<= 3;
|
||||
if (!nic_rx_header(ring_ptr)) {
|
||||
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
|
||||
@@ -999,6 +1035,7 @@ void handle_rx(void)
|
||||
REG_SET(RTL837X_REG_NIC_RXCMD, 1);
|
||||
return;
|
||||
}
|
||||
health_rx_frame();
|
||||
|
||||
#ifdef RXTXDBG
|
||||
print_string("\n<< ");
|
||||
@@ -1027,8 +1064,7 @@ void handle_rx(void)
|
||||
tcpip_output();
|
||||
}
|
||||
} else if (igmpEnabled && uip_buf[0] == 0x01 && uip_buf[1] == 0x00 && uip_buf[2] == 0x5e // IPv4-MC packet?
|
||||
&& uip_buf[3] == 0x00 && uip_buf[4] == 0x00 && uip_buf[5] == 0x16) {
|
||||
igmp_packet_handler();
|
||||
&& igmp_packet_handler()) {
|
||||
if (uip_len) {
|
||||
tcpip_output();
|
||||
}
|
||||
@@ -1152,54 +1188,8 @@ void handle_button(void)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// An idle function that sleeps for 1 tick and does all the house-keeping
|
||||
//
|
||||
void idle(void)
|
||||
void check_links(void)
|
||||
{
|
||||
PCON |= 1;
|
||||
if (sec_counter >= SYS_TICK_HZ) {
|
||||
sec_counter -= SYS_TICK_HZ;
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
uint8_t v = sfr_data[3];
|
||||
#ifdef DEBUG
|
||||
print_string(" Tick counter: "); print_long(ticks); write_char('\n');
|
||||
#endif
|
||||
v++;
|
||||
sfr_data[3] = v;
|
||||
if (!v) {
|
||||
v = sfr_data[2];
|
||||
v++;
|
||||
sfr_data[2] = v;
|
||||
if (!v) {
|
||||
v = sfr_data[1];
|
||||
v++;
|
||||
sfr_data[1] = v;
|
||||
if (!v) {
|
||||
v = sfr_data[0];
|
||||
v++;
|
||||
sfr_data[0] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
reg_write_m(RTL837X_REG_SEC_COUNTER);
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
|
||||
// Check for button presses once a second
|
||||
handle_button();
|
||||
// Age the ARP cache: uip_arp_timer() expects a 10 s cadence
|
||||
if (++arp_age_secs >= 10) {
|
||||
arp_age_secs = 0;
|
||||
uip_arp_timer();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
print_sfr_data();
|
||||
write_char('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check for Link changes
|
||||
reg_read_m(RTL837X_REG_LINKS_89);
|
||||
__xdata uint8_t linkbits_p89 = sfr_data[3];
|
||||
|
||||
@@ -1232,24 +1222,104 @@ void idle(void)
|
||||
cpy_4(linkbits_last, sfr_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for changes with SFP modules
|
||||
handle_sfp();
|
||||
|
||||
// Check new Packets RX
|
||||
handle_rx();
|
||||
// Check UIP for packets to transmit
|
||||
//
|
||||
// An idle function that sleeps for 1 tick and does all the house-keeping
|
||||
//
|
||||
static void handle_tick(void)
|
||||
{
|
||||
if (sec_counter >= SYS_TICK_HZ) {
|
||||
sec_counter -= SYS_TICK_HZ;
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
uint8_t v = sfr_data[3];
|
||||
#ifdef DEBUG
|
||||
print_string(" Tick counter: "); print_long(ticks); write_char('\n');
|
||||
#endif
|
||||
v++;
|
||||
sfr_data[3] = v;
|
||||
if (!v) {
|
||||
v = sfr_data[2];
|
||||
v++;
|
||||
sfr_data[2] = v;
|
||||
if (!v) {
|
||||
v = sfr_data[1];
|
||||
v++;
|
||||
sfr_data[1] = v;
|
||||
if (!v) {
|
||||
v = sfr_data[0];
|
||||
v++;
|
||||
sfr_data[0] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
reg_write_m(RTL837X_REG_SEC_COUNTER);
|
||||
reg_read_m(RTL837X_REG_SEC_COUNTER);
|
||||
|
||||
// Check for button presses once a second
|
||||
handle_button();
|
||||
link_irq = 1;
|
||||
// Age the ARP cache: uip_arp_timer() expects a 10 s cadence
|
||||
if (++arp_age_secs >= 10) {
|
||||
arp_age_secs = 0;
|
||||
uip_arp_timer();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
print_sfr_data();
|
||||
write_char('\n');
|
||||
#endif
|
||||
}
|
||||
|
||||
health_phase(HEALTH_PH_LINK);
|
||||
if (TICKS_DUE(sfp_tick_last, SFP_TICK_STEP)) {
|
||||
sfp_tick_last += SFP_TICK_STEP;
|
||||
handle_sfp();
|
||||
}
|
||||
health_phase(HEALTH_PH_SFP);
|
||||
handle_tx();
|
||||
// If STP protocol enabled, decrease STP timers to trigger actions
|
||||
health_phase(HEALTH_PH_TX);
|
||||
if (stp_enabled) {
|
||||
if (!stp_clock) {
|
||||
stp_clock = STP_TICK_DIVIDER;
|
||||
uint8_t n = STP_CATCH_UP;
|
||||
while (n-- && TICKS_DUE(stp_tick_last, STP_TICK_STEP)) {
|
||||
stp_tick_last += STP_TICK_STEP;
|
||||
stp_timers();
|
||||
} else {
|
||||
stp_clock--;
|
||||
}
|
||||
}
|
||||
// Check whether a command is waiting in the cmd_buffer and execute
|
||||
health_phase(HEALTH_PH_STP);
|
||||
lldp_tick();
|
||||
health_phase(HEALTH_LLDP);
|
||||
}
|
||||
|
||||
|
||||
void idle(void)
|
||||
{
|
||||
if (!evflags)
|
||||
PCON |= 1;
|
||||
health_loop_start();
|
||||
if (tick_pending) {
|
||||
tick_pending = 0;
|
||||
handle_tick();
|
||||
}
|
||||
if (link_irq) {
|
||||
link_irq = 0;
|
||||
REG_SET(RTL837X_ISR_INT_PORT_LINK_CHG, 0x3ff);
|
||||
EX0 = 1;
|
||||
check_links();
|
||||
}
|
||||
health_phase(HEALTH_PH_LINK);
|
||||
if (rx_irq) {
|
||||
rx_irq = 0;
|
||||
handle_rx();
|
||||
REG_SET(RTL837X_NIC_INT_STS, NIC_INT_RXIS);
|
||||
reg_read(RTL837X_REG_NIC_RX_BUFF_DATA);
|
||||
if (SFR_DATA_U16)
|
||||
rx_irq = 1;
|
||||
else
|
||||
EX1 = 1;
|
||||
}
|
||||
health_phase(HEALTH_PH_RX);
|
||||
if (cmd_available) {
|
||||
cmd_available = 0;
|
||||
cmd_tokenize();
|
||||
@@ -1257,6 +1327,7 @@ void idle(void)
|
||||
cmd_parser();
|
||||
print_cmd_prompt();
|
||||
}
|
||||
health_phase(HEALTH_PH_CMD);
|
||||
}
|
||||
|
||||
|
||||
@@ -1282,14 +1353,16 @@ void reset_chip(void)
|
||||
|
||||
void setup_external_irqs(void)
|
||||
{
|
||||
REG_SET(0x5f84, 0x42);
|
||||
REG_SET(0x5f34, 0x3ff);
|
||||
REG_SET(RTL837X_ISR_SW_INT_MODE, 0x42);
|
||||
REG_SET(RTL837X_ISR_INT_PORT_LINK_CHG, 0x3ff);
|
||||
REG_SET(RTL837X_IMR_INT_PORT_LINK_STS_CHG, 0x3ff);
|
||||
|
||||
// EX0 = 1; // Enable external IRQ 0 (Link-change)
|
||||
EX0 = 0;
|
||||
IT0 = 1; // External IRQ on falling edge
|
||||
link_irq = 1;
|
||||
IT0 = 1; // External IRQ 0 on falling edge (link change)
|
||||
EX0 = 1;
|
||||
|
||||
EX1 = 1; // External IRQ 1 enable
|
||||
rx_irq = 1;
|
||||
EX1 = 1; // External IRQ 1: the NIC has received a packet
|
||||
EX2 = 1; // External IRQ 2 enable: bit EIE.0
|
||||
EX3 = 1; // External IRQ 3 enable: bit EIE.1
|
||||
PX3 = 1; // Set EIP.1 = 1: External IRQ 3 set to high priority
|
||||
@@ -1570,7 +1643,8 @@ void check_and_flash_update_image(void)
|
||||
void main(void)
|
||||
{
|
||||
ticks = 0;
|
||||
stp_clock = STP_TICK_DIVIDER;
|
||||
stp_tick_last = (uint8_t)ticks;
|
||||
sfp_tick_last = (uint8_t)ticks;
|
||||
dhcp_state.state = DHCP_OFF;
|
||||
sbuf_ptr = 0;
|
||||
|
||||
@@ -1674,14 +1748,14 @@ void main(void)
|
||||
|
||||
REG_SET(RTL837X_PIN_MUX_2, 0x0); // Disable pins for ACL
|
||||
init_smi();
|
||||
if (machine_detected.isRTL8373)
|
||||
rtl8224_wait_ready();
|
||||
|
||||
rtl8373_revision();
|
||||
|
||||
leds_setup();
|
||||
machine_custom_init();
|
||||
|
||||
leds_dump();
|
||||
|
||||
set_sys_led_state(SYS_LED_SLOW);
|
||||
|
||||
if (machine_detected.isRTL8373)
|
||||
@@ -1714,6 +1788,7 @@ void main(void)
|
||||
stp_enabled = 0;
|
||||
stp_defaults(); /* 802.1D/w default config before any "stp ..." replay */
|
||||
nic_setup();
|
||||
REG_SET(RTL837X_NIC_INT_MSK, NIC_INT_RXIE);
|
||||
vlan_setup();
|
||||
port_l2_setup();
|
||||
igmp_setup();
|
||||
@@ -1721,6 +1796,7 @@ void main(void)
|
||||
uip_init();
|
||||
uip_arp_init();
|
||||
httpd_init();
|
||||
lldp_init();
|
||||
|
||||
management_vlan = 1; // Default management VLAN is 1
|
||||
|
||||
@@ -1751,6 +1827,7 @@ void main(void)
|
||||
|
||||
cmd_editor_init();
|
||||
|
||||
health_stack_paint();
|
||||
while (1) {
|
||||
cmd_edit();
|
||||
idle(); // Enter Idle mode until interrupt occurs
|
||||
|
||||
@@ -0,0 +1,410 @@
|
||||
; Assembler file to intercept register writes/reads and PHY writes/reads
|
||||
; assemble with as31
|
||||
; Compile with
|
||||
; as31 -Fbyte -Orwintercept_zoerax_hg0402xg.hex rwintercept_zoerax_hg0402xg.asm
|
||||
; ./injector zoerax_hg0402xg.bin RTLPlayground/rwintercept_zoerax_hg0402xg.hex zoerax_hg0402xg_patched.bin
|
||||
; Start at 0x3b00, where there is always some space in BANK 0
|
||||
.equ valptr, 0xc7
|
||||
|
||||
|
||||
.equ SFR_DATA_0, 0xa7
|
||||
.equ SFR_DATA_8, 0xa6
|
||||
.equ SFR_DATA_16, 0xa5
|
||||
.equ SFR_DATA_24, 0xa4
|
||||
|
||||
; Intercept Register Write
|
||||
.org 0x4d62
|
||||
lcall reg_write
|
||||
nop
|
||||
|
||||
; Intercept Register Read
|
||||
.org 0x4dad
|
||||
lcall reg_read_head
|
||||
.org 0x4e6f
|
||||
lcall reg_read_tail
|
||||
|
||||
; Intercept PHY write
|
||||
.org 0x522c
|
||||
lcall phy_write
|
||||
|
||||
; Intercept PHY read
|
||||
.org 0x526f
|
||||
lcall phy_read_head
|
||||
.org 0x5295
|
||||
ljmp phy_read_tail
|
||||
|
||||
; Intercept SDS write
|
||||
.org 0x503c
|
||||
lcall sds_write
|
||||
nop
|
||||
|
||||
; Intercept SDS read
|
||||
.org 0x5061
|
||||
lcall sds_read_head
|
||||
nop
|
||||
.org 0x507b
|
||||
ljmp sds_read_tail
|
||||
|
||||
;
|
||||
; BEGIN actual code at unused end of BANK0
|
||||
;
|
||||
.org 0x3b00
|
||||
|
||||
;
|
||||
; print the address of a register write. The address is in R6/R7. A and r4 can be scratched
|
||||
;
|
||||
reg_write:
|
||||
mov a, #'R'
|
||||
acall putc
|
||||
|
||||
mov a, r6
|
||||
acall wbyte
|
||||
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, #'-'
|
||||
acall putc
|
||||
|
||||
mov dptr, #valptr
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #valptr + 1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #valptr + 2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #valptr + 3
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov a, r7
|
||||
mov r5, a
|
||||
mov a, r6
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
;
|
||||
; print the address of a register read The address is in R2/R3. Registers 4-7 are scratch
|
||||
;
|
||||
reg_read_head:
|
||||
mov a, #'r'
|
||||
acall putc
|
||||
|
||||
mov a, r2
|
||||
acall wbyte
|
||||
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
clr a
|
||||
mov r7, a
|
||||
mov r6, a
|
||||
mov r5, a
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
reg_read_tail:
|
||||
mov dptr, #0xc5
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #0xc5 + 1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #0xc5 + 2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
mov dptr, #0xc5 + 3
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov dptr,#0xc5
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
; print phy write options
|
||||
;
|
||||
phy_write:
|
||||
mov a, #'P'
|
||||
acall putc
|
||||
|
||||
mov a, r4
|
||||
acall wbyte
|
||||
|
||||
; phymask
|
||||
mov a, r6
|
||||
acall wbyte
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, #'.'
|
||||
acall putc
|
||||
|
||||
; dev_id?
|
||||
mov a, r5
|
||||
acall wbyte
|
||||
|
||||
; x_phywrite_opt
|
||||
mov dptr, #0xf1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
; The register going to SFR_C2 and SFR_C3
|
||||
mov a, r2
|
||||
acall wbyte
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov dptr, #0xf2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
|
||||
mov dptr, #0xf3
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov dptr, #0xeb
|
||||
mov r4, #0
|
||||
ret
|
||||
|
||||
;
|
||||
; print phy read options
|
||||
;
|
||||
phy_read_head:
|
||||
mov r1, 4 ; actually r4
|
||||
|
||||
mov a, #'p'
|
||||
acall putc
|
||||
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, r5
|
||||
acall wbyte
|
||||
|
||||
mov a, #'.'
|
||||
acall putc
|
||||
|
||||
mov a, r2
|
||||
acall wbyte
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov r1, 7
|
||||
mov a, r2
|
||||
ret
|
||||
|
||||
phy_read_tail:
|
||||
mov r6, 4
|
||||
mov a, r6
|
||||
acall wbyte
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
mov r4, 6
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
; print SDS write options
|
||||
;
|
||||
sds_write:
|
||||
mov a, r4
|
||||
mov r2, a ; R2 is scratch
|
||||
|
||||
mov a, #'Q'
|
||||
acall putc
|
||||
|
||||
|
||||
mov a, r7
|
||||
acall wbyte
|
||||
mov a, r5
|
||||
acall wbyte
|
||||
mov a, r3
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov dptr, #0xe1
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
|
||||
mov dptr, #0xe2
|
||||
movx a, @dptr
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov a, r7
|
||||
mov r1, a
|
||||
mov a, r5
|
||||
mov r7, a
|
||||
mov a, r2
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
;
|
||||
; print SDS read options
|
||||
;
|
||||
sds_read_head:
|
||||
mov a, r4
|
||||
mov r1, a ; R1 is scratch
|
||||
|
||||
mov a, #'q'
|
||||
acall putc
|
||||
|
||||
mov a, r7 ; sds_index bit
|
||||
acall wbyte
|
||||
mov a, r5 ; SFR_94 (2 x r5 | r7)
|
||||
acall wbyte
|
||||
mov a, r3 ; SFR_93
|
||||
acall wbyte
|
||||
|
||||
mov a, #':'
|
||||
acall putc
|
||||
|
||||
mov a, r1
|
||||
mov r4, a ; R1 is scratch
|
||||
|
||||
mov a, r7
|
||||
mov r1, a
|
||||
mov a, r5
|
||||
mov r7, a
|
||||
|
||||
ret
|
||||
|
||||
;
|
||||
; print SDS read result
|
||||
;
|
||||
sds_read_tail:
|
||||
mov a, r4
|
||||
mov r6, a ; R6 is returned and preserved
|
||||
|
||||
mov a, r7 ; = r7 = SFR_DATA_8
|
||||
acall wbyte
|
||||
mov r7, SFR_DATA_0
|
||||
mov a, r7 ; SFR_DATA_0
|
||||
acall wbyte
|
||||
|
||||
mov a, #' '
|
||||
acall putc
|
||||
|
||||
mov a, r6 ; R6 is returned and preserved
|
||||
mov r4, a
|
||||
ret
|
||||
|
||||
;
|
||||
; Write a byte as hex to serial
|
||||
;
|
||||
nop
|
||||
nop
|
||||
wbyte:
|
||||
mov r4, a
|
||||
swap a
|
||||
anl a, #0x0f
|
||||
mov dptr,#hex
|
||||
movc a, @a+dptr
|
||||
|
||||
jb ET0, wbyte1
|
||||
ret
|
||||
wbyte1:
|
||||
jbc TI, wbyte2
|
||||
sjmp wbyte1
|
||||
wbyte2:
|
||||
mov SBUF,a
|
||||
|
||||
mov a, r4
|
||||
anl a, #0x0f
|
||||
mov dptr,#hex
|
||||
movc a, @a+dptr
|
||||
|
||||
wbyte3:
|
||||
jbc TI, wbyte4
|
||||
sjmp wbyte3
|
||||
wbyte4:
|
||||
mov SBUF,a
|
||||
|
||||
ret
|
||||
|
||||
;
|
||||
; Intercept isr_ext0
|
||||
;
|
||||
isr_ext0:
|
||||
mov a, #'i'
|
||||
acall putc
|
||||
mov r0,#0x51
|
||||
inc @r0
|
||||
ret
|
||||
|
||||
;
|
||||
; Intercept isr_ext1
|
||||
;
|
||||
isr_ext1:
|
||||
mov a, #'I'
|
||||
acall putc
|
||||
mov r0,#0x25
|
||||
mov a, @r0
|
||||
ret
|
||||
;
|
||||
; Intercept isr_ext2
|
||||
;
|
||||
isr_ext2:
|
||||
mov a, #'J'
|
||||
acall putc
|
||||
mov r0, #0x1e
|
||||
mov a, #0xa
|
||||
ret
|
||||
|
||||
;
|
||||
; Intercept isr_ext3
|
||||
;
|
||||
isr_ext3:
|
||||
mov a, #'j'
|
||||
acall putc
|
||||
mov r0,#0x1e
|
||||
mov a,#0x14
|
||||
ret
|
||||
|
||||
;
|
||||
; Write a character to serial
|
||||
;
|
||||
nop
|
||||
nop
|
||||
putc:
|
||||
jb ET0, putc1
|
||||
ret
|
||||
putc1:
|
||||
jbc TI,putc2
|
||||
sjmp putc1
|
||||
putc2:
|
||||
mov SBUF,a
|
||||
ret
|
||||
|
||||
hex:
|
||||
.byte "0123456789abcdef"
|
||||
.end
|
||||
@@ -20,6 +20,8 @@ extern __code const struct machine machine;
|
||||
|
||||
// SFP1 b0 = 1 => module missing, b1 = 1 => LOS;
|
||||
// SFP2 b4 = 1 => module missing, b5 = 1 => LOS;
|
||||
extern volatile __xdata uint32_t ticks;
|
||||
|
||||
__xdata uint8_t sfp_pins_last;
|
||||
__xdata char sfp_module_vendor[2][17];
|
||||
__xdata char sfp_module_model[2][17];
|
||||
@@ -28,6 +30,8 @@ __xdata uint8_t sfp_options[2];
|
||||
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
|
||||
__xdata uint8_t sfp_speed[2];
|
||||
__xdata uint8_t sfp_quirks[2];
|
||||
__xdata uint8_t sfp_wake_at[2];
|
||||
__xdata uint8_t sfp_wake_pending[2];
|
||||
|
||||
|
||||
__code enum sfp_quirk {
|
||||
@@ -35,12 +39,12 @@ __code enum sfp_quirk {
|
||||
};
|
||||
|
||||
struct sfp_quirk_entry {
|
||||
__code char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code char *model;
|
||||
__code const char *vendor; // Set vendor or model to 0 to act as wildcard
|
||||
__code const char *model;
|
||||
uint8_t quirks;
|
||||
};
|
||||
|
||||
static __code struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
static __code const struct sfp_quirk_entry sfp_quirk_table[] = {
|
||||
{ "QSFPTEK", "QT-SFP+-T", SFP_QUIRK_DDM },
|
||||
};
|
||||
|
||||
@@ -88,9 +92,14 @@ bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t lengt
|
||||
return false;
|
||||
|
||||
dst[length] = NUL;
|
||||
memcpy(dst, sfp_buf, length);
|
||||
for (uint8_t i = 0; i < length; i++) {
|
||||
uint8_t c = sfp_buf[i];
|
||||
if (c && (c < 0x20 || c > 0x7e || c == '"' || c == '\\'))
|
||||
c = '.';
|
||||
dst[i] = c;
|
||||
}
|
||||
|
||||
while (length > 0 && dst[--length] == ' ')
|
||||
while (length-- > 0 && (dst[length] == ' ' || dst[length] == NUL))
|
||||
dst[length] = NUL;
|
||||
|
||||
return true;
|
||||
@@ -152,7 +161,6 @@ static bool sfp_module_read(uint8_t sfp)
|
||||
|
||||
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024
|
||||
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
|
||||
delay(100); // Delay, because some modules need time to wake up
|
||||
if (!sfp_read_block(sfp, 11, 2))
|
||||
return false;
|
||||
|
||||
@@ -194,6 +202,11 @@ void handle_sfp(void) __banked
|
||||
if (sfp_pins_last & (0x1 << (sfp << 2))) {
|
||||
sfp_pins_last &= ~(0x01 << (sfp << 2));
|
||||
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
|
||||
sfp_wake_at[sfp] = ticks;
|
||||
sfp_wake_pending[sfp] = 1;
|
||||
} else if (sfp_wake_pending[sfp]
|
||||
&& (uint8_t)((uint8_t)ticks - sfp_wake_at[sfp]) >= SFP_WAKE_TICKS) {
|
||||
sfp_wake_pending[sfp] = 0;
|
||||
if (!sfp_module_read(sfp)) {
|
||||
print_string("SFP: an I2C read failed, retrying on the next poll\n");
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
@@ -202,6 +215,7 @@ void handle_sfp(void) __banked
|
||||
} else {
|
||||
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
|
||||
sfp_pins_last |= 0x01 << (sfp << 2);
|
||||
sfp_wake_pending[sfp] = 0;
|
||||
print_string("\n<MODULE REMOVED> Slot: "); write_char('1' + sfp); write_char('\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef SFP_H
|
||||
#define SFP_H
|
||||
|
||||
#define SFP_WAKE_TICKS 100
|
||||
|
||||
extern __xdata uint8_t sfp_pins_last;
|
||||
extern __xdata char sfp_module_vendor[2][17];
|
||||
extern __xdata char sfp_module_model[2][17];
|
||||
|
||||
@@ -60,7 +60,7 @@ void syslog_stop(void) __banked
|
||||
void syslog_callback(uint16_t lport) __banked
|
||||
{
|
||||
uint16_t syslog_hdr;
|
||||
if (lport != state.syslog_conn->lport)
|
||||
if (!state.syslog_conn || lport != state.syslog_conn->lport)
|
||||
return;
|
||||
|
||||
if ((state.readptr != state.writeptr) && state.line_available)
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
CC = gcc
|
||||
SRCROOT = ..
|
||||
# -include shim first so __xdata/__code/__banked vanish before any firmware header.
|
||||
CFLAGS = -std=gnu11 -g -O1 -Wall -Wextra -Wno-unused-parameter -Wno-unknown-pragmas \
|
||||
CFLAGS = -std=gnu11 -g -O1 -Wall -Wextra -Werror -Wno-unused-parameter -Wno-unknown-pragmas \
|
||||
-Wno-pointer-sign \
|
||||
-DRTLP_HOST_TEST \
|
||||
-fsanitize=address,undefined -fno-omit-frame-pointer \
|
||||
-include sdcc_shim.h -I. -I$(SRCROOT) -I$(SRCROOT)/httpd -I$(SRCROOT)/uip
|
||||
-include sdcc_shim.h -Istub -I. -I$(SRCROOT) -I$(SRCROOT)/httpd -I$(SRCROOT)/uip
|
||||
ifeq ($(findstring clang,$(shell $(CC) --version 2>/dev/null)),)
|
||||
CFLAGS += -Wno-builtin-declaration-mismatch
|
||||
endif
|
||||
@@ -23,7 +24,16 @@ LDFLAGS = -fsanitize=address,undefined
|
||||
BUILDDIR = build
|
||||
|
||||
# One binary per subsystem under test.
|
||||
TESTS = $(BUILDDIR)/test_cmd_editor
|
||||
TESTS = $(BUILDDIR)/test_cmd_editor \
|
||||
$(BUILDDIR)/test_port_tables \
|
||||
$(BUILDDIR)/test_page_json \
|
||||
$(BUILDDIR)/test_httpd_tx \
|
||||
$(BUILDDIR)/test_tick_gate
|
||||
|
||||
# The table tests link the register mock and one environment file; stub/
|
||||
# stands in for the two headers a firmware build generates.
|
||||
TABLE_ENV = support.c hw_mock.c env_tables.c $(SRCROOT)/cmd_editor.c \
|
||||
$(SRCROOT)/rtl837x_port.c $(SRCROOT)/httpd/page_impl.c
|
||||
|
||||
all: run
|
||||
|
||||
@@ -34,6 +44,21 @@ $(BUILDDIR):
|
||||
$(BUILDDIR)/test_cmd_editor: test_cmd_editor.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
# rtl837x_port.c and httpd/page_impl.c are compiled UNMODIFIED from the firmware tree.
|
||||
$(BUILDDIR)/test_port_tables: test_port_tables.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||
|
||||
$(BUILDDIR)/test_tick_gate: test_tick_gate.c support.c $(SRCROOT)/cmd_editor.c | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
$(BUILDDIR)/test_page_json: test_page_json.c $(TABLE_ENV) hw_mock.h | $(BUILDDIR)
|
||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||
|
||||
# httpd/httpd.c and uip/uip.c are compiled UNMODIFIED from the firmware tree;
|
||||
# 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)
|
||||
$(CC) $(CFLAGS) $(filter %.c,$^) -o $@ $(LDFLAGS)
|
||||
|
||||
run: $(TESTS)
|
||||
@fail=0; for t in $(TESTS); do \
|
||||
echo "=== $$t ==="; \
|
||||
|
||||
@@ -19,6 +19,16 @@ fires — so it drops straight into CI.
|
||||
- **`sdcc_shim.h`** (force-included) erases SDCC 8051 keywords (`__xdata`,
|
||||
`__code`, `__banked`, …) so firmware sources compile under host gcc. It changes
|
||||
no logic — the code under test is byte-for-byte the firmware source.
|
||||
- **`hw_mock.c` / `hw_mock.h`** simulate the ASIC edge: a flat register file
|
||||
behind `reg_read`/`reg_write` and the `SFR_DATA_*` registers, with a table
|
||||
engine that performs a VLAN or L2 operation the moment `TBL_CTRL` is written,
|
||||
fetches a MIB counter on `STAT_GET` and drops entries on `L2_TBL_FLUSH_CTRL`.
|
||||
Nothing ever reports busy, so a polling loop runs once. The header states the
|
||||
VLAN and L2 entry layouts independently of the firmware, so a test can hold
|
||||
what `rtl837x_port.c` writes against what `page_impl.c` reads.
|
||||
- **`env_tables.c`** carries the globals and leaf calls those two modules link
|
||||
against; **`stub/`** stands in for the two headers only a firmware build
|
||||
generates, so the harness needs no SDCC build first.
|
||||
- **`support.c` / `support.h`** mock the hardware edges: the 16-byte serial ring
|
||||
(`sbuf`), the command/history buffers, and the character-output sink
|
||||
(`write_char` etc.). Buffers are sized **exactly** as on target, so ASan
|
||||
@@ -35,6 +45,9 @@ fires — so it drops straight into CI.
|
||||
| Test binary | TU under test | Findings exercised |
|
||||
|-------------|---------------|--------------------|
|
||||
| `test_cmd_editor` | `cmd_editor.c` | **C4** — full-line hang + `cmd_buffer` 1-byte overflow; basic entry & backspace regressions |
|
||||
| `test_port_tables` | `rtl837x_port.c` | VLAN entry layout and round trip, PVID register sharing, static multicast and management entries, per-port flush, trunk membership and hash seed |
|
||||
| `test_page_json` | `httpd/page_impl.c` + `rtl837x_port.c` | `/vlan.json`, `/vlanlist`, `/l2.json` (walk, wrap marker, paging inside `outbuf`), 64-bit counters in `/status.json` and `/counters.json` |
|
||||
| `test_httpd_tx` | `httpd/httpd.c` + `uip/uip.c` | a GET of a static file against a client that moves its receive window: ACK accounting, continuation chunks out of flash, retransmission |
|
||||
|
||||
## Adding a test for another module
|
||||
1. Write `test_<module>.c` with `main()` driving the module's entry points and
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* env_tables.c - what rtl837x_port.c and httpd/page_impl.c link against
|
||||
* besides the register mock: the console, the buffers page_impl writes into,
|
||||
* the machine description and leaf calls into subsystems not under test.
|
||||
* Buffers keep their firmware sizes so AddressSanitizer sees the same bounds
|
||||
* the 8051 has.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "machine.h"
|
||||
#include "uip.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "syslog.h"
|
||||
#include "rtl837x_phy.h"
|
||||
#include "support.h"
|
||||
|
||||
/* ---- console: everything lands in out_buf (support.c) ---- */
|
||||
void print_byte(uint8_t v)
|
||||
{
|
||||
static const char h[] = "0123456789abcdef";
|
||||
write_char(h[(v >> 4) & 0xf]);
|
||||
write_char(h[v & 0xf]);
|
||||
}
|
||||
void print_short(uint16_t v) { print_byte(v >> 8); print_byte(v); }
|
||||
void print_long(uint32_t v) { print_short(v >> 16); print_short(v); }
|
||||
void print_reg(uint16_t v) { print_short(v); }
|
||||
void itoa_short(uint16_t v)
|
||||
{
|
||||
char b[6]; int n = 0;
|
||||
do { b[n++] = '0' + v % 10; v /= 10; } while (v);
|
||||
while (n) write_char(b[--n]);
|
||||
}
|
||||
void dbg_string(char *p) { (void)p; }
|
||||
void dbg_short(uint16_t v) { (void)v; }
|
||||
void dbg_char(char c) { (void)c; }
|
||||
void dbg_byte(uint8_t v) { (void)v; }
|
||||
|
||||
/* ---- copied verbatim from rtlplayground.c ---- */
|
||||
uint16_t strtox(uint8_t *dst, const char *s)
|
||||
{
|
||||
uint8_t *b = dst;
|
||||
while (*s)
|
||||
*dst++ = *s++;
|
||||
*dst = 0;
|
||||
return dst - b;
|
||||
}
|
||||
|
||||
const uint16_t bit_mask[16] = {
|
||||
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
||||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
||||
};
|
||||
const uint8_t hex_chars[] = "0123456789abcdef";
|
||||
uint8_t *hex = (uint8_t *)hex_chars;
|
||||
|
||||
/* ---- a 9-port RTL8373 whose logical ports map to themselves ---- */
|
||||
const struct machine machine = {
|
||||
.machine_name = "HOSTTEST",
|
||||
.min_port = 0,
|
||||
.max_port = 8,
|
||||
.n_sfp = 0,
|
||||
.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 },
|
||||
};
|
||||
struct machine_runtime machine_detected = { .isRTL8373 = 1 };
|
||||
|
||||
/* ---- firmware state the modules read or write ---- */
|
||||
uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
uint16_t slen;
|
||||
uint16_t management_vlan = 1;
|
||||
uint16_t cont_len;
|
||||
uint32_t cont_addr;
|
||||
uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
uint16_t vlan_ptr;
|
||||
uint8_t sfp_pins_last = 0xff;
|
||||
uint8_t sfp_options[2];
|
||||
char sfp_module_vendor[2][17];
|
||||
char sfp_module_model[2][17];
|
||||
char sfp_module_serial[2][17];
|
||||
char hostname[24] = "hosttest";
|
||||
char port_names[9][PORT_NAME_SIZE];
|
||||
struct flash_region_t flash_region;
|
||||
struct syslog_state syslog_state;
|
||||
bool stp_enabled;
|
||||
bool lldp_enabled;
|
||||
uint16_t lldp_logical_port_status;
|
||||
|
||||
|
||||
uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask;
|
||||
struct uip_eth_addr uip_ethaddr = { .addr = { 0x02, 0x11, 0x22, 0x33, 0x44, 0x55 } };
|
||||
|
||||
/* ---- leaf calls into subsystems not under test ---- */
|
||||
void flash_read_bulk(uint8_t *dst) { (void)dst; }
|
||||
const char *get_flash_size_str(void) { return "2M"; }
|
||||
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg) { (void)slot; (void)reg; return 0; }
|
||||
bool gpio_pin_test(uint8_t pin) { (void)pin; return false; }
|
||||
void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg) { (void)phy_id; (void)dev_id; (void)reg; }
|
||||
void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t val) { (void)phy_id; (void)dev_id; (void)reg; (void)val; }
|
||||
void phy_reset(uint8_t port) { (void)port; }
|
||||
uint8_t stp_port_role(uint8_t port) { (void)port; return 0; }
|
||||
uint8_t stp_port_state(uint8_t port) { (void)port; return 3; }
|
||||
|
||||
/* ---- STP state send_stp() prints; the tree is not under test here ---- */
|
||||
#include "rtl837x_stp.h"
|
||||
struct bridge root_bridge;
|
||||
struct bridge stp_dbridge[STP_ENTITIES];
|
||||
uint16_t stp_bpdu_age[STP_ENTITIES];
|
||||
uint16_t stp_dpid[STP_ENTITIES];
|
||||
uint16_t stp_lag_mask[STP_LAG_COUNT];
|
||||
uint16_t stp_tc_count;
|
||||
uint32_t root_bridge_cost;
|
||||
uint32_t stp_dcost[STP_ENTITIES];
|
||||
uint32_t stp_pcost[STP_ENTITIES];
|
||||
uint8_t stp_ent_of[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
uint8_t stp_fwddelay_s = 15, stp_hello_s = 2, stp_maxage_s = 20;
|
||||
uint8_t stp_pflags[STP_ENTITIES];
|
||||
uint8_t stp_pp2p[STP_ENTITIES];
|
||||
uint8_t stp_pprio[STP_ENTITIES];
|
||||
uint8_t stp_prio = 0x80, stp_root_port = 0xff, stp_rstp = 1, stp_txhold = 6;
|
||||
|
||||
/* ---- SFP: no module present, reads fail ---- */
|
||||
uint8_t sfp_buf[16];
|
||||
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) { (void)slot; (void)reg; (void)len; return false; }
|
||||
void print_phys_port(uint8_t port) { itoa_short(machine.log_to_phys_port[port]); }
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* hw_mock.c - the ASIC edge: SFR storage, register file, table engine.
|
||||
*
|
||||
* The shim declares every SFR extern so that including rtl837x_sfr.h from many
|
||||
* translation units does not define them repeatedly. Undefining the four
|
||||
* keywords here and re-including the header emits the definitions once, so
|
||||
* the mock tracks the real register list without a hand-kept copy.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#undef __sfr
|
||||
#undef __sfr16
|
||||
#undef __sfr32
|
||||
#undef __sbit
|
||||
#define __sfr volatile uint8_t
|
||||
#define __sfr16 volatile uint16_t
|
||||
#define __sfr32 volatile uint32_t
|
||||
#define __sbit bool
|
||||
#include "rtl837x_sfr.h"
|
||||
#undef __sfr
|
||||
#undef __sfr16
|
||||
#undef __sfr32
|
||||
#undef __sbit
|
||||
#define __sfr extern volatile uint8_t
|
||||
#define __sfr16 extern volatile uint16_t
|
||||
#define __sfr32 extern volatile uint32_t
|
||||
#define __sbit extern bool
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "hw_mock.h"
|
||||
|
||||
uint8_t sfr_data[4];
|
||||
unsigned long hw_reads, hw_writes;
|
||||
|
||||
static uint32_t regfile[0x10000];
|
||||
static uint32_t vlan_tbl[4096];
|
||||
static struct hw_l2 l2[HW_L2_MAX];
|
||||
static uint64_t counters[16][64];
|
||||
|
||||
void hw_reset(void)
|
||||
{
|
||||
memset(regfile, 0, sizeof(regfile));
|
||||
memset(vlan_tbl, 0, sizeof(vlan_tbl));
|
||||
memset(l2, 0, sizeof(l2));
|
||||
memset(counters, 0, sizeof(counters));
|
||||
memset(sfr_data, 0, sizeof(sfr_data));
|
||||
hw_reads = hw_writes = 0;
|
||||
}
|
||||
|
||||
void hw_reg_set(uint16_t addr, uint32_t v) { regfile[addr] = v; }
|
||||
uint32_t hw_reg_get(uint16_t addr) { return regfile[addr]; }
|
||||
uint32_t hw_vlan_word(uint16_t vid) { return vlan_tbl[vid & 0xfff]; }
|
||||
void hw_counter_set(uint8_t port, uint8_t counter, uint64_t value) { counters[port & 0xf][counter & 0x3f] = value; }
|
||||
|
||||
/* ---- L2 table -------------------------------------------------------- */
|
||||
|
||||
static int l2_cmp(const void *x, const void *y)
|
||||
{
|
||||
const struct hw_l2 *a = x, *b = y;
|
||||
if (a->present != b->present)
|
||||
return a->present ? -1 : 1;
|
||||
return (int)a->idx - (int)b->idx;
|
||||
}
|
||||
|
||||
static void l2_sort(void) { qsort(l2, HW_L2_MAX, sizeof(l2[0]), l2_cmp); }
|
||||
|
||||
int hw_l2_count(void)
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < HW_L2_MAX; i++)
|
||||
n += l2[i].present;
|
||||
return n;
|
||||
}
|
||||
|
||||
const struct hw_l2 *hw_l2_at(int n)
|
||||
{
|
||||
l2_sort();
|
||||
return (n >= 0 && n < hw_l2_count()) ? &l2[n] : 0;
|
||||
}
|
||||
|
||||
static void l2_key(const struct hw_l2 *e, uint8_t mac[6], uint16_t *vid)
|
||||
{
|
||||
mac[0] = e->b >> 8; mac[1] = e->b;
|
||||
mac[2] = e->a >> 24; mac[3] = e->a >> 16; mac[4] = e->a >> 8; mac[5] = e->a;
|
||||
*vid = ((e->b >> 16) & 0xfff);
|
||||
}
|
||||
|
||||
const struct hw_l2 *hw_l2_find(const uint8_t mac[6], uint16_t vid)
|
||||
{
|
||||
for (int i = 0; i < HW_L2_MAX; i++) {
|
||||
uint8_t m[6]; uint16_t v;
|
||||
if (!l2[i].present)
|
||||
continue;
|
||||
l2_key(&l2[i], m, &v);
|
||||
if (v == vid && !memcmp(m, mac, 6))
|
||||
return &l2[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hw_l2 *l2_free(void)
|
||||
{
|
||||
for (int i = 0; i < HW_L2_MAX; i++)
|
||||
if (!l2[i].present)
|
||||
return &l2[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t l2_hash(const uint8_t mac[6], uint16_t vid)
|
||||
{
|
||||
uint16_t h = vid;
|
||||
for (int i = 0; i < 6; i++)
|
||||
h = (uint16_t)(h * 31 + mac[i]);
|
||||
return h & 0xfff;
|
||||
}
|
||||
|
||||
void hw_l2_put(uint16_t idx, const uint8_t mac[6], uint16_t vid, uint16_t port_or_pmask, bool is_static)
|
||||
{
|
||||
struct hw_l2 *e = (struct hw_l2 *)hw_l2_find(mac, vid);
|
||||
bool mc = mac[0] & 1;
|
||||
if (!e)
|
||||
e = l2_free();
|
||||
e->present = true;
|
||||
e->idx = idx & 0xfff;
|
||||
e->a = ((uint32_t)mac[2] << 24) | ((uint32_t)mac[3] << 16) | ((uint32_t)mac[4] << 8) | mac[5];
|
||||
e->b = (0x20u << 24) | ((uint32_t)(vid & 0xfff) << 16) | ((uint32_t)mac[0] << 8) | mac[1];
|
||||
if (mc) {
|
||||
e->b |= (uint32_t)(port_or_pmask & 0x3) << 30;
|
||||
e->c = (port_or_pmask >> 2) & 0xff;
|
||||
} else {
|
||||
e->b |= (uint32_t)(port_or_pmask & 0x3) << 30;
|
||||
e->c = (port_or_pmask >> 2) & 0x3;
|
||||
}
|
||||
if (is_static)
|
||||
e->c |= 1u << 16;
|
||||
}
|
||||
|
||||
void hw_l2_decode(const struct hw_l2 *e, uint8_t mac[6], uint16_t *vid, uint16_t *port_or_pmask,
|
||||
bool *valid, bool *is_static, bool *mc)
|
||||
{
|
||||
l2_key(e, mac, vid);
|
||||
*valid = (e->b >> 29) & 1;
|
||||
*is_static = (e->c >> 16) & 1;
|
||||
*mc = mac[0] & 1;
|
||||
if (*mc)
|
||||
*port_or_pmask = ((e->b >> 30) & 0x3) | ((e->c & 0xff) << 2);
|
||||
else
|
||||
*port_or_pmask = ((e->b >> 30) & 0x3) | ((e->c & 0x3) << 2);
|
||||
}
|
||||
|
||||
/* ---- the engine ------------------------------------------------------ */
|
||||
|
||||
static void l2_out(const struct hw_l2 *e, uint16_t idx)
|
||||
{
|
||||
regfile[RTL837x_L2_DATA_OUT_A] = e ? e->a : 0;
|
||||
regfile[RTL837x_L2_DATA_OUT_B] = e ? e->b : 0;
|
||||
regfile[RTL837x_L2_DATA_OUT_C] = e ? e->c : 0;
|
||||
regfile[RTL837x_TBL_DATA_0] = (regfile[RTL837x_TBL_DATA_0] & ~0x1fffu) | (e ? 0x1000 : 0) | (idx & 0xfff);
|
||||
}
|
||||
|
||||
static void table_exec(uint32_t ctrl)
|
||||
{
|
||||
uint16_t idx = ((ctrl >> 16) & 0xfff);
|
||||
uint8_t type = ctrl >> 8;
|
||||
bool write = ctrl & TBL_WRITE;
|
||||
|
||||
if (type == TBL_VLAN) {
|
||||
if (write)
|
||||
vlan_tbl[idx] = regfile[RTL837x_TBL_DATA_IN_A];
|
||||
else
|
||||
regfile[RTL837x_L2_DATA_OUT_A] = vlan_tbl[idx];
|
||||
return;
|
||||
}
|
||||
if (type != TBL_L2_UNICAST)
|
||||
return;
|
||||
|
||||
uint32_t d0 = regfile[RTL837x_TBL_DATA_0];
|
||||
uint8_t method = (d0 >> 14) & 0x3;
|
||||
bool clear = (d0 >> 18) & 1;
|
||||
|
||||
if (method == TBL_LUTREAD_MAC) {
|
||||
struct hw_l2 key = { .present = true, .a = regfile[RTL837x_TBL_DATA_IN_A],
|
||||
.b = regfile[RTL837x_TBL_DATA_IN_B], .c = regfile[RTL837x_TBL_DATA_IN_C] };
|
||||
uint8_t mac[6]; uint16_t vid;
|
||||
l2_key(&key, mac, &vid);
|
||||
struct hw_l2 *e = (struct hw_l2 *)hw_l2_find(mac, vid);
|
||||
if (write) {
|
||||
if (clear) {
|
||||
if (e)
|
||||
e->present = false;
|
||||
l2_out(0, 0);
|
||||
return;
|
||||
}
|
||||
if (!e) {
|
||||
e = l2_free();
|
||||
e->idx = l2_hash(mac, vid);
|
||||
}
|
||||
e->present = true;
|
||||
e->a = key.a; e->b = key.b; e->c = key.c;
|
||||
l2_out(e, e->idx);
|
||||
return;
|
||||
}
|
||||
l2_out(e, e ? e->idx : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* next-entry reads: the first present entry at or after idx, wrapping */
|
||||
l2_sort();
|
||||
int n = hw_l2_count();
|
||||
struct hw_l2 *e = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
if (l2[i].idx >= idx) { e = &l2[i]; break; }
|
||||
if (!e && n)
|
||||
e = &l2[0];
|
||||
if (write) {
|
||||
/* a write by index replaces the entry that sits there */
|
||||
for (int i = 0; i < n; i++)
|
||||
if (l2[i].idx == idx) { e = &l2[i]; break; }
|
||||
if (!e)
|
||||
e = l2_free();
|
||||
e->present = (regfile[RTL837x_TBL_DATA_IN_B] >> 29) & 1;
|
||||
e->idx = idx;
|
||||
e->a = regfile[RTL837x_TBL_DATA_IN_A];
|
||||
e->b = regfile[RTL837x_TBL_DATA_IN_B];
|
||||
e->c = regfile[RTL837x_TBL_DATA_IN_C];
|
||||
return;
|
||||
}
|
||||
l2_out(e, e ? e->idx : idx);
|
||||
}
|
||||
|
||||
static void flush_exec(uint32_t ctrl)
|
||||
{
|
||||
uint16_t mask = ctrl & 0x3ff;
|
||||
bool dynamic_only = regfile[RTL837x_L2_TBL_FLUSH_CNF] == 0;
|
||||
for (int i = 0; i < HW_L2_MAX; i++) {
|
||||
uint8_t mac[6]; uint16_t vid, p; bool valid, st, mc;
|
||||
if (!l2[i].present)
|
||||
continue;
|
||||
hw_l2_decode(&l2[i], mac, &vid, &p, &valid, &st, &mc);
|
||||
if (mc || (st && dynamic_only))
|
||||
continue;
|
||||
if ((mask >> p) & 1)
|
||||
l2[i].present = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void stat_exec(uint32_t v)
|
||||
{
|
||||
uint8_t cnt = (uint8_t)(((v >> 8) & 0xff) << 3) | ((v >> 5) & 0x7);
|
||||
uint8_t port = (v >> 1) & 0xf;
|
||||
uint64_t c = counters[port][cnt & 0x3f];
|
||||
regfile[RTL837X_STAT_V_HIGH] = (uint32_t)(c >> 32);
|
||||
regfile[RTL837X_STAT_V_LOW] = (uint32_t)c;
|
||||
}
|
||||
|
||||
static void reg_store(uint16_t addr, uint32_t v)
|
||||
{
|
||||
hw_writes++;
|
||||
regfile[addr] = v;
|
||||
switch (addr) {
|
||||
case RTL837X_TBL_CTRL:
|
||||
if (v & TBL_EXECUTE) {
|
||||
table_exec(v);
|
||||
regfile[addr] = v & ~(uint32_t)TBL_EXECUTE;
|
||||
}
|
||||
break;
|
||||
case RTL837x_L2_TBL_FLUSH_CTRL:
|
||||
if (v & L2_TBL_FLUSH_EXEC) {
|
||||
flush_exec(v);
|
||||
regfile[addr] = v & ~(uint32_t)L2_TBL_FLUSH_EXEC;
|
||||
}
|
||||
break;
|
||||
case RTL837X_STAT_GET:
|
||||
if (v & 1) {
|
||||
stat_exec(v);
|
||||
regfile[addr] = v & ~1u;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t sfr_word(void)
|
||||
{
|
||||
return ((uint32_t)SFR_DATA_24 << 24) | ((uint32_t)SFR_DATA_16 << 16) | ((uint32_t)SFR_DATA_8 << 8) | SFR_DATA_0;
|
||||
}
|
||||
|
||||
static void sfr_load(uint32_t v)
|
||||
{
|
||||
SFR_DATA_24 = v >> 24; SFR_DATA_16 = v >> 16; SFR_DATA_8 = v >> 8; SFR_DATA_0 = v;
|
||||
}
|
||||
|
||||
void reg_read(uint16_t addr)
|
||||
{
|
||||
hw_reads++;
|
||||
sfr_load(regfile[addr]);
|
||||
}
|
||||
|
||||
void reg_read_m(uint16_t addr)
|
||||
{
|
||||
reg_read(addr);
|
||||
sfr_data[0] = SFR_DATA_24; sfr_data[1] = SFR_DATA_16; sfr_data[2] = SFR_DATA_8; sfr_data[3] = SFR_DATA_0;
|
||||
}
|
||||
|
||||
void reg_write(uint16_t addr)
|
||||
{
|
||||
reg_store(addr, sfr_word());
|
||||
}
|
||||
|
||||
void reg_write_m(uint16_t addr)
|
||||
{
|
||||
sfr_load(((uint32_t)sfr_data[0] << 24) | ((uint32_t)sfr_data[1] << 16) | ((uint32_t)sfr_data[2] << 8) | sfr_data[3]);
|
||||
reg_write(addr);
|
||||
}
|
||||
|
||||
void reg_bit_set(uint16_t addr, char bit)
|
||||
{
|
||||
reg_read_m(addr);
|
||||
sfr_data[3 - (bit >> 3)] |= 1 << (bit & 7);
|
||||
reg_write_m(addr);
|
||||
}
|
||||
|
||||
void reg_bit_clear(uint16_t addr, char bit)
|
||||
{
|
||||
reg_read_m(addr);
|
||||
sfr_data[3 - (bit >> 3)] &= ~(1 << (bit & 7));
|
||||
reg_write_m(addr);
|
||||
}
|
||||
|
||||
uint8_t reg_bit_test(uint16_t addr, char bit)
|
||||
{
|
||||
reg_read_m(addr);
|
||||
return (sfr_data[3 - (bit >> 3)] >> (bit & 7)) & 1;
|
||||
}
|
||||
|
||||
void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set)
|
||||
{
|
||||
sfr_data[3 - n] = (sfr_data[3 - n] & ~mask) | set;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* hw_mock.h - a simulated RTL837x register file and table engine.
|
||||
*
|
||||
* The firmware reaches the ASIC only through reg_read/reg_read_m/reg_write/
|
||||
* reg_write_m and the SFR_DATA_* registers, so mocking that edge is enough to
|
||||
* run the table code on the host. Every register is a 32-bit word in a flat
|
||||
* file; a few addresses are live: writing TBL_CTRL with EXECUTE performs the
|
||||
* table operation at once and clears the bit, STAT_GET fetches a counter,
|
||||
* L2_TBL_FLUSH_CTRL drops entries. Nothing here ever reports busy, so a
|
||||
* polling loop in the firmware runs exactly once.
|
||||
*
|
||||
* The VLAN and L2 entry layouts mirror what rtl837x_port.c writes and what
|
||||
* httpd/page_impl.c reads; the decoders below are an independent statement
|
||||
* of that layout, so a test can compare the firmware's two ends against it.
|
||||
*/
|
||||
#ifndef TEST_HW_MOCK_H
|
||||
#define TEST_HW_MOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void hw_reset(void); /* every register 0, tables empty */
|
||||
void hw_reg_set(uint16_t addr, uint32_t v);
|
||||
uint32_t hw_reg_get(uint16_t addr);
|
||||
|
||||
extern uint8_t sfr_data[4]; /* the firmware's register scratch, owned here */
|
||||
extern unsigned long hw_reads; /* reg_read + reg_read_m calls since hw_reset */
|
||||
extern unsigned long hw_writes; /* reg_write + reg_write_m calls since hw_reset */
|
||||
|
||||
/* VLAN table: the 32-bit word the firmware wrote for that VID, 0 = never written */
|
||||
uint32_t hw_vlan_word(uint16_t vid);
|
||||
|
||||
/* L2 table: entries as the three data words the firmware exchanges with the
|
||||
* engine. Word B: bit 29 valid, bits 31:30 the low two bits of the port (or
|
||||
* of the member mask), bits 27:16 VID, bits 15:0 the first two MAC octets.
|
||||
* Word A: the last four MAC octets. Word C: bit 16 static, bits 1:0 the high
|
||||
* two bits of the port; for a multicast MAC bits 7:0 are the member mask
|
||||
* shifted right by two. */
|
||||
#define HW_L2_MAX 64
|
||||
struct hw_l2 {
|
||||
bool present;
|
||||
uint16_t idx;
|
||||
uint32_t a, b, c; /* DATA_IN_A/B/C on write, L2_DATA_OUT_A/B/C on read */
|
||||
};
|
||||
|
||||
/* Pointers returned below stay valid until the next table operation. */
|
||||
int hw_l2_count(void);
|
||||
const struct hw_l2 *hw_l2_at(int n); /* n-th present entry in idx order */
|
||||
const struct hw_l2 *hw_l2_find(const uint8_t mac[6], uint16_t vid);
|
||||
/* Put an entry the way the switch would hold it: a learned unicast entry on
|
||||
* one port, or a static one. mc entries use pmask instead of a port. */
|
||||
void hw_l2_put(uint16_t idx, const uint8_t mac[6], uint16_t vid, uint16_t port_or_pmask, bool is_static);
|
||||
void hw_l2_decode(const struct hw_l2 *e, uint8_t mac[6], uint16_t *vid, uint16_t *port_or_pmask,
|
||||
bool *valid, bool *is_static, bool *mc);
|
||||
|
||||
/* MIB counter the next STAT_GET for (port, counter) returns */
|
||||
void hw_counter_set(uint8_t port, uint8_t counter, uint64_t value);
|
||||
|
||||
#endif /* TEST_HW_MOCK_H */
|
||||
@@ -12,6 +12,7 @@
|
||||
#define SDCC_SHIM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Memory-space qualifiers → nothing (host has one flat address space). */
|
||||
#define __xdata
|
||||
@@ -22,12 +23,27 @@
|
||||
/* bool, not unsigned char: SDCC's bit types normalize any assigned value
|
||||
* to 0/1, which _Bool reproduces exactly. */
|
||||
#define __bit bool
|
||||
#define __sbit bool
|
||||
|
||||
/* NOTE: the firmware ships its own 8051 memcpy/memset/strlen/strcpy/sleep with
|
||||
* incompatible signatures (rtl837x_common.h). Host TUs must therefore build with
|
||||
* -fno-builtin (so gcc doesn't auto-declare the builtins) and must NOT include
|
||||
* <string.h>/<unistd.h>. Test code uses the t_* helpers in support.h instead. */
|
||||
/* Special-function registers are declared in rtl837x_sfr.h as
|
||||
* `__sfr __at(0xNN) NAME;`. With __at erased those become plain declarations,
|
||||
* so they must carry extern or every translation unit including the header
|
||||
* defines its own copy. __sbit is the bit-in-an-SFR form and only appears
|
||||
* there; the local bit variable keyword is __bit above. test/hw_mock.c
|
||||
* undefines these four and re-includes the header once to emit the storage. */
|
||||
#define __sfr extern volatile uint8_t
|
||||
#define __sfr16 extern volatile uint16_t
|
||||
#define __sfr32 extern volatile uint32_t
|
||||
#define __sbit extern bool
|
||||
|
||||
/* The firmware ships its own memcpy/memset/strlen/strcpy/sleep, and
|
||||
* rtl837x_common.h hides those prototypes under RTLP_HOST_TEST so host builds
|
||||
* take the C library versions. Something has to declare them, and firmware
|
||||
* sources do call memset and memcpy; this header is force-included ahead of
|
||||
* everything, so pulling <string.h> in here puts the libc versions in scope
|
||||
* before any firmware header and nothing clashes. sleep() is not in
|
||||
* <string.h> and is declared on its own rather than through <unistd.h>. */
|
||||
#include <string.h>
|
||||
extern unsigned int sleep(unsigned int seconds);
|
||||
|
||||
/* Function attributes → nothing (no banking / no 8051 calling conventions). */
|
||||
#define __banked
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/* Stand-in for the generated html_data.h: the table generators under test
|
||||
* never touch the embedded file list, and the real header exists only after
|
||||
* a firmware build, which the host harness must not depend on. */
|
||||
#ifndef FDATA_DEFS_H
|
||||
#define FDATA_DEFS_H
|
||||
#include <stdint.h>
|
||||
typedef enum mime_type_e { mime_HTML = 0, mime_SVG, mime_ICO, mime_PNG, mime_JS, mime_CSS, mime_TXT } mime_type_t;
|
||||
struct f_data { __code const char *file; uint32_t start; uint16_t len; mime_type_t mime; uint8_t gzip; };
|
||||
#define FDATA_START_login_html 0x00040000UL
|
||||
#define FDATA_START_favicon_ico 0x00041000UL
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifndef VERSION_H
|
||||
#define VERSION_H
|
||||
#define VERSION_SW "host-test"
|
||||
#define BUILD_DATE "1970-01-01 00:00:00"
|
||||
#endif
|
||||
@@ -27,6 +27,7 @@ uint8_t cmd_available;
|
||||
uint8_t err_status;
|
||||
uint8_t cmd_history[CMD_HISTORY_SIZE];
|
||||
uint16_t cmd_history_ptr;
|
||||
__xdata uint16_t session_timeout = 200; /* httpd global, referenced by page_impl.c */
|
||||
|
||||
/* editor-internal read pointer (defined in cmd_editor.c, external linkage) */
|
||||
extern __xdata uint8_t l;
|
||||
@@ -47,7 +48,7 @@ static void out_putc(char c) {
|
||||
|
||||
/* --- mocked print helpers (signatures match rtl837x_common.h post-shim) ---- */
|
||||
void write_char(char c) { out_putc(c); }
|
||||
void print_string(char *p) { while (*p) out_putc(*p++); }
|
||||
void print_string(const char *p) { while (*p) out_putc(*p++); }
|
||||
void print_string_x(char *p) { while (*p) out_putc(*p++); }
|
||||
void print_cmd_prompt(void) { print_string((char *)"> "); }
|
||||
void itoa(uint8_t v) { /* firmware prints a decimal number */
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* Host-side bench for the httpd transmit path.
|
||||
*
|
||||
* Compiles the UNMODIFIED httpd/httpd.c and uip/uip.c and drives them through a
|
||||
* real handshake and a real GET from a client that moves its receive window.
|
||||
* Everything below the two modules - flash, console, JSON pages - is mocked
|
||||
* here, so what the bench observes is the byte stream the firmware would put on
|
||||
* the wire.
|
||||
*
|
||||
* The file served out of the simulated flash carries a position-dependent
|
||||
* pattern, so a duplicated or skipped range shows up as a mismatch at a known
|
||||
* offset instead of an anonymous "content differs".
|
||||
*
|
||||
* Run: make -C test (exit code 0 = all scenarios pass)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Some hosts ship these in <sys/_endian.h>, and they assign to their argument;
|
||||
* uip.h refuses to be included next to them. The firmware definitions are the
|
||||
* ones this bench needs, so the host macros go first. */
|
||||
#undef HTONS
|
||||
#undef NTOHS
|
||||
|
||||
#include "httpd.h"
|
||||
#include "uip.h"
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_flash.h"
|
||||
#include "page_impl.h"
|
||||
#include "html_data.h"
|
||||
|
||||
/* Private to uip.c, and the client needs them to build segments. */
|
||||
#define TCP_SYN 0x02
|
||||
#define TCP_PSH 0x08
|
||||
#define TCP_ACK 0x10
|
||||
|
||||
#define TCPH ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
|
||||
|
||||
#define MSS_FULL 1460
|
||||
#define SMALL_WINDOW 600
|
||||
|
||||
/* httpd.c serves this one file without a session, which keeps the bench clear
|
||||
* of the login machinery: what is under test is the transmit path. */
|
||||
#define FILE_START FDATA_START_login_html
|
||||
#define FILE_NAME "/login.html"
|
||||
#define FILE_LEN 6000
|
||||
#define STREAM_MAX 16384
|
||||
|
||||
static int failures;
|
||||
static int verbose;
|
||||
|
||||
#define CHECK(cond, name) do { \
|
||||
if (cond) printf("PASS %s\n", name); \
|
||||
else { printf("FAIL %s\n", name); failures++; } \
|
||||
} while (0)
|
||||
|
||||
static uint8_t pattern(uint32_t addr)
|
||||
{
|
||||
return (uint8_t)((addr * 7u) + (addr >> 8));
|
||||
}
|
||||
|
||||
/* ---- firmware environment below httpd.c --------------------------------- */
|
||||
|
||||
volatile uint8_t sfr_data[4];
|
||||
volatile uint32_t ticks;
|
||||
uint8_t cmd_capture;
|
||||
uint8_t err_status;
|
||||
const uint8_t * const hex = (const uint8_t *)"0123456789abcdef";
|
||||
uint16_t crc_value;
|
||||
const uint8_t * const HTTP_RESPONCE_TXT = (const uint8_t *)"HTTP/1.1 200 OK\r\n\r\n";
|
||||
uint32_t flash_size = 0x80000;
|
||||
uint8_t flash_buf[FLASH_BUF_SIZE];
|
||||
uint8_t rx_headers[16];
|
||||
struct flash_region_t flash_region;
|
||||
|
||||
const char * const mime_strings[] = { "text/html", "image/svg+xml", "image/x-icon",
|
||||
"image/png", "text/javascript", "text/css", "text/plain" };
|
||||
|
||||
const struct f_data f_data[] = {
|
||||
{ FILE_NAME, FILE_START, FILE_LEN, mime_HTML, 0 },
|
||||
{ 0, 0, 0, mime_HTML, 0 },
|
||||
};
|
||||
|
||||
void flash_read_bulk(uint8_t *dst)
|
||||
{
|
||||
for (uint16_t i = 0; i < flash_region.len; i++)
|
||||
dst[i] = pattern(flash_region.addr + i);
|
||||
}
|
||||
|
||||
void flash_init(uint8_t enable_dio) { (void)enable_dio; }
|
||||
void flash_sector_erase(void) { }
|
||||
void flash_write_bytes(uint8_t *ptr) { (void)ptr; }
|
||||
const char *get_flash_size_str(void) { return "512 kB"; }
|
||||
void crc16_bank1(uint8_t *v) { (void)v; }
|
||||
void reset_chip(void) { }
|
||||
void delay(uint16_t t) { (void)t; }
|
||||
void write_char(char c) { (void)c; }
|
||||
void write_char_no_syslog(char c) { (void)c; }
|
||||
void print_string(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 cmd_parser(void) { }
|
||||
void execute_config(void) { }
|
||||
void execute_commands(uint8_t *p) { (void)p; }
|
||||
void clear_command_history(void) { }
|
||||
void udp_callbacks(void) { }
|
||||
void tcpip_output(void) { }
|
||||
void get_random_32(void) { }
|
||||
void read_reg_timer(uint32_t *tmr) { *tmr = 0; }
|
||||
|
||||
/* 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. */
|
||||
u8_t uip_buf[UIP_BUFSIZE + 2];
|
||||
|
||||
uint16_t strlen_x(const char *s) { return (uint16_t)strlen(s); }
|
||||
|
||||
uint16_t strtox(uint8_t *dst, const char *s)
|
||||
{
|
||||
uint16_t n = 0;
|
||||
|
||||
while (s[n]) { dst[n] = (uint8_t)s[n]; n++; }
|
||||
return n;
|
||||
}
|
||||
|
||||
void memcpyc(uint8_t *dst, const uint8_t *src, uint16_t len) { memcpy(dst, src, len); }
|
||||
|
||||
bool strstart(const uint8_t *a, const uint8_t *b)
|
||||
{
|
||||
while (*b) { if (*a++ != *b++) return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strstart_x(const uint8_t *a, const uint8_t *b) { return strstart(a, b); }
|
||||
|
||||
bool send_counters(uint8_t phys_port) { (void)phys_port; return false; }
|
||||
void send_status(void) { }
|
||||
void send_vlan(uint16_t vlan) { (void)vlan; }
|
||||
void send_basic_info(void) { }
|
||||
void send_bandwidth(void) { }
|
||||
void send_storm(void) { }
|
||||
void send_isolation(void) { }
|
||||
void send_eee(void) { }
|
||||
void send_l2(uint16_t idx) { (void)idx; }
|
||||
void l2_delete(uint16_t idx) { (void)idx; }
|
||||
void send_mirror(void) { }
|
||||
void send_mtu(void) { }
|
||||
void send_config(void) { }
|
||||
void send_cmd_log(void) { }
|
||||
void send_lag(void) { }
|
||||
void send_stp(void) { }
|
||||
void send_stp_counters(void) { }
|
||||
void send_vlanlist(void) { }
|
||||
void send_lldp(void) {}
|
||||
|
||||
extern uint8_t authenticated;
|
||||
|
||||
/* 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. */
|
||||
extern u16_t uip_listenports[UIP_LISTENPORTS];
|
||||
|
||||
/* ---- the simulated client ----------------------------------------------- */
|
||||
|
||||
static uint32_t cli_seq; /* next sequence number we send */
|
||||
static uint32_t cli_rcv_nxt; /* next sequence number we expect */
|
||||
static uint16_t cli_window; /* what we advertise */
|
||||
|
||||
static uint8_t stream[STREAM_MAX]; /* bytes accepted from the server */
|
||||
static int stream_len;
|
||||
|
||||
static uint8_t last_tx[MSS_FULL + 64]; /* payload of the last server segment */
|
||||
static int last_tx_len;
|
||||
|
||||
static uint16_t hton16(uint16_t v)
|
||||
{
|
||||
return (uint16_t)((v << 8) | (v >> 8));
|
||||
}
|
||||
|
||||
static void wr32(uint8_t *p, uint32_t v)
|
||||
{
|
||||
p[0] = v >> 24; p[1] = v >> 16; p[2] = v >> 8; p[3] = v;
|
||||
}
|
||||
|
||||
static uint32_t rd32(const uint8_t *p)
|
||||
{
|
||||
return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) |
|
||||
((uint32_t)p[2] << 8) | p[3];
|
||||
}
|
||||
|
||||
static void trace(const char *tag)
|
||||
{
|
||||
if (!verbose)
|
||||
return;
|
||||
printf(" [%-8s] uip_len=%-5u flags=0x%02x seq=%-6u ack=%-6u | conn: state=0x%02x len=%-5u mss=%-5u tstate=%u\n",
|
||||
tag, uip_len,
|
||||
uip_len ? TCPH->flags : 0,
|
||||
uip_len ? rd32(TCPH->seqno) : 0,
|
||||
uip_len ? rd32(TCPH->ackno) : 0,
|
||||
uip_conns[0].tcpstateflags, uip_conns[0].len, uip_conns[0].mss,
|
||||
uip_conns[0].appstate.tstate);
|
||||
}
|
||||
|
||||
/* Takes in one outgoing segment, if uIP produced one. */
|
||||
static int harvest(void)
|
||||
{
|
||||
uint8_t *payload;
|
||||
uint32_t seq;
|
||||
int plen, hlen;
|
||||
|
||||
if (uip_len == 0)
|
||||
return -1;
|
||||
|
||||
seq = rd32(TCPH->seqno);
|
||||
/* The SYNACK carries the MSS option, so the header is not always 20 B. */
|
||||
hlen = (TCPH->tcpoffset >> 4) * 4;
|
||||
payload = &uip_buf[UIP_LLH_LEN + 20 + hlen];
|
||||
plen = (int)uip_len - 20 - hlen;
|
||||
if (plen < 0)
|
||||
plen = 0;
|
||||
|
||||
if (plen > 0) {
|
||||
last_tx_len = plen > (int)sizeof(last_tx) ? (int)sizeof(last_tx) : plen;
|
||||
memcpy(last_tx, payload, last_tx_len);
|
||||
|
||||
/* A real client keeps what continues the stream and drops the
|
||||
* rest, so bytes sent twice under new sequence numbers land in
|
||||
* the file just as they would in a browser. */
|
||||
if (seq == cli_rcv_nxt) {
|
||||
if (stream_len + plen <= STREAM_MAX) {
|
||||
memcpy(stream + stream_len, payload, plen);
|
||||
stream_len += plen;
|
||||
}
|
||||
cli_rcv_nxt += plen;
|
||||
}
|
||||
if (verbose)
|
||||
printf(" server -> %d B, seq %u\n", plen, seq);
|
||||
}
|
||||
if (TCPH->flags & TCP_SYN)
|
||||
cli_rcv_nxt = seq + 1;
|
||||
|
||||
uip_len = 0;
|
||||
return plen;
|
||||
}
|
||||
|
||||
static void client_send(uint8_t flags, const char *payload, int plen)
|
||||
{
|
||||
int hlen = 20;
|
||||
|
||||
/* A SYN carries the MSS option, as every real client does: uIP takes the
|
||||
* connection MSS from it, and without one the server has nothing to send
|
||||
* with. */
|
||||
if (flags & TCP_SYN)
|
||||
hlen = 24;
|
||||
|
||||
memset(uip_buf, 0, UIP_LLH_LEN + 20 + hlen + (plen > 0 ? plen : 0));
|
||||
TCPH->vhl = 0x45;
|
||||
TCPH->tos = 0;
|
||||
TCPH->len[0] = (uint8_t)((20 + hlen + plen) >> 8);
|
||||
TCPH->len[1] = (uint8_t)((20 + hlen + plen) & 0xff);
|
||||
TCPH->ttl = 64;
|
||||
TCPH->proto = UIP_PROTO_TCP;
|
||||
TCPH->ipchksum = 0;
|
||||
TCPH->srcipaddr[0] = hton16(0x0a00); TCPH->srcipaddr[1] = hton16(0x0002);
|
||||
TCPH->destipaddr[0] = hton16(0x0a00); TCPH->destipaddr[1] = hton16(0x0001);
|
||||
TCPH->srcport = hton16(40000);
|
||||
TCPH->destport = hton16(80);
|
||||
wr32(TCPH->seqno, cli_seq);
|
||||
wr32(TCPH->ackno, cli_rcv_nxt);
|
||||
TCPH->tcpoffset = (uint8_t)((hlen / 4) << 4);
|
||||
TCPH->flags = flags;
|
||||
TCPH->wnd[0] = (uint8_t)(cli_window >> 8);
|
||||
TCPH->wnd[1] = (uint8_t)(cli_window & 0xff);
|
||||
TCPH->tcpchksum = 0;
|
||||
|
||||
if (hlen == 24) {
|
||||
uint8_t *opt = &uip_buf[UIP_LLH_LEN + 40];
|
||||
|
||||
opt[0] = 2; opt[1] = 4; /* kind = MSS, length 4 */
|
||||
opt[2] = MSS_FULL >> 8; opt[3] = MSS_FULL & 0xff;
|
||||
}
|
||||
if (plen > 0)
|
||||
memcpy(&uip_buf[UIP_LLH_LEN + 20 + hlen], payload, plen);
|
||||
|
||||
uip_len = 20 + hlen + plen;
|
||||
uip_input();
|
||||
trace("input");
|
||||
cli_seq += plen;
|
||||
if (flags & TCP_SYN)
|
||||
cli_seq++;
|
||||
harvest();
|
||||
}
|
||||
|
||||
static void client_ack(uint16_t window)
|
||||
{
|
||||
cli_window = window;
|
||||
client_send(TCP_ACK, NULL, 0);
|
||||
}
|
||||
|
||||
static void run_periodic(int rounds)
|
||||
{
|
||||
for (int i = 0; i < rounds; i++) {
|
||||
uip_periodic(0);
|
||||
trace("timer");
|
||||
harvest();
|
||||
}
|
||||
}
|
||||
|
||||
static void session_start(uint16_t window)
|
||||
{
|
||||
uip_init();
|
||||
httpd_init();
|
||||
authenticated = 1;
|
||||
|
||||
cli_seq = 1000;
|
||||
cli_rcv_nxt = 0;
|
||||
cli_window = window;
|
||||
stream_len = 0;
|
||||
last_tx_len = 0;
|
||||
|
||||
client_send(TCP_SYN, NULL, 0);
|
||||
client_ack(window);
|
||||
}
|
||||
|
||||
static void request_file(uint16_t window)
|
||||
{
|
||||
static const char get[] = "GET " FILE_NAME " HTTP/1.1\r\nHost: sw\r\n\r\n";
|
||||
|
||||
cli_window = window;
|
||||
client_send(TCP_ACK | TCP_PSH, get, (int)strlen(get));
|
||||
}
|
||||
|
||||
/* Drains the response, acknowledging every segment with the given window. */
|
||||
static void drain(uint16_t window)
|
||||
{
|
||||
for (int i = 0; i < 20 && stream_len < STREAM_MAX; i++) {
|
||||
client_ack(window);
|
||||
run_periodic(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int body_offset(void)
|
||||
{
|
||||
for (int i = 0; i + 4 <= stream_len; i++)
|
||||
if (!memcmp(stream + i, "\r\n\r\n", 4))
|
||||
return i + 4;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Offset of the first body byte that is not the one the file holds there, or
|
||||
* -1 when the body matches, or -2 when no header ever arrived. */
|
||||
static int first_body_mismatch(void)
|
||||
{
|
||||
int off = body_offset();
|
||||
|
||||
if (off < 0)
|
||||
return -2;
|
||||
for (int i = 0; i < FILE_LEN && off + i < stream_len; i++)
|
||||
if (stream[off + i] != pattern(FILE_START + i))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void report(const char *tag)
|
||||
{
|
||||
if (verbose)
|
||||
printf(" %s: header %d B, stream %d B, first mismatch %d\n",
|
||||
tag, body_offset(), stream_len, first_body_mismatch());
|
||||
}
|
||||
|
||||
/* ---- scenarios ---------------------------------------------------------- */
|
||||
|
||||
/* Instrument check: with a window that never moves, the MSS at ACK time and the
|
||||
* length sent earlier are the same number, so the file must arrive intact. If
|
||||
* this one fails, the bench is wrong - not the firmware. */
|
||||
static void scenario_steady_window(void)
|
||||
{
|
||||
session_start(MSS_FULL);
|
||||
if (verbose)
|
||||
printf(" listen port=0x%04x, initial mss=%u\n",
|
||||
uip_listenports[0], uip_conns[0].initialmss);
|
||||
request_file(MSS_FULL);
|
||||
drain(MSS_FULL);
|
||||
report("steady");
|
||||
|
||||
CHECK(body_offset() >= 0, "control: response carries an HTTP header");
|
||||
CHECK(stream_len >= body_offset() + FILE_LEN,
|
||||
"control: the whole file arrives");
|
||||
CHECK(first_body_mismatch() == -1,
|
||||
"control: file content without duplicates or gaps");
|
||||
}
|
||||
|
||||
/* The client stops draining, so the window in the ACK is smaller than the
|
||||
* segment that ACK covers. */
|
||||
static void scenario_shrinking_window(void)
|
||||
{
|
||||
session_start(MSS_FULL);
|
||||
request_file(MSS_FULL);
|
||||
drain(SMALL_WINDOW);
|
||||
report("shrinking");
|
||||
|
||||
CHECK(body_offset() >= 0,
|
||||
"shrinking window: response carries an HTTP header");
|
||||
CHECK(stream_len >= body_offset() + FILE_LEN,
|
||||
"shrinking window: the whole file arrives");
|
||||
CHECK(first_body_mismatch() == -1,
|
||||
"shrinking window: file content without duplicates or gaps");
|
||||
}
|
||||
|
||||
/* The client catches up, so the window in the ACK is larger than the segment
|
||||
* that ACK covers. */
|
||||
static void scenario_growing_window(void)
|
||||
{
|
||||
session_start(SMALL_WINDOW);
|
||||
request_file(SMALL_WINDOW);
|
||||
drain(MSS_FULL);
|
||||
report("growing");
|
||||
|
||||
CHECK(stream_len >= body_offset() + FILE_LEN,
|
||||
"growing window: the whole file arrives");
|
||||
CHECK(first_body_mismatch() == -1,
|
||||
"growing window: file content without duplicates or gaps");
|
||||
}
|
||||
|
||||
/* A segment is lost, a window update shrinks the window while it is still
|
||||
* unacknowledged, and the retransmission timer fires. */
|
||||
static void scenario_rexmit_after_shrink(void)
|
||||
{
|
||||
uint8_t original[MSS_FULL + 64];
|
||||
int original_len, same = 1;
|
||||
|
||||
session_start(MSS_FULL);
|
||||
request_file(MSS_FULL);
|
||||
|
||||
original_len = last_tx_len;
|
||||
memcpy(original, last_tx, original_len);
|
||||
|
||||
/* The segment never arrived: take it back out of the client's stream and
|
||||
* send a pure window update, which acknowledges nothing. */
|
||||
if (original_len > 0 && stream_len >= original_len) {
|
||||
stream_len -= original_len;
|
||||
cli_rcv_nxt -= original_len;
|
||||
}
|
||||
cli_window = SMALL_WINDOW;
|
||||
client_send(TCP_ACK, NULL, 0);
|
||||
|
||||
memset(&uip_buf[UIP_LLH_LEN + 40], 0xaa, MSS_FULL);
|
||||
|
||||
last_tx_len = 0;
|
||||
run_periodic(UIP_RTO + 2);
|
||||
|
||||
if (last_tx_len != original_len || memcmp(last_tx, original, original_len))
|
||||
same = 0;
|
||||
|
||||
if (verbose)
|
||||
printf(" first %d B, retransmitted %d B\n",
|
||||
original_len, last_tx_len);
|
||||
|
||||
CHECK(original_len > 0, "retransmission: the first segment went out");
|
||||
CHECK(same, "retransmission: the repeat carries the same bytes");
|
||||
}
|
||||
|
||||
static void scenario_bad_l4_checksum(void)
|
||||
{
|
||||
uip_stats_t chkerr_before;
|
||||
uint32_t seq_before;
|
||||
int len_before;
|
||||
|
||||
session_start(MSS_FULL);
|
||||
|
||||
chkerr_before = uip_stat.tcp.chkerr;
|
||||
len_before = stream_len;
|
||||
seq_before = cli_seq;
|
||||
|
||||
rx_headers[1] = RX_TAG_L4_CSUM_BAD;
|
||||
request_file(MSS_FULL);
|
||||
rx_headers[1] = 0;
|
||||
cli_seq = seq_before;
|
||||
|
||||
CHECK(uip_stat.tcp.chkerr == chkerr_before + 1,
|
||||
"bad checksum: the segment is counted as a checksum error");
|
||||
CHECK(stream_len == len_before,
|
||||
"bad checksum: the request draws no reply");
|
||||
|
||||
request_file(MSS_FULL);
|
||||
drain(MSS_FULL);
|
||||
report("bad checksum");
|
||||
|
||||
CHECK(body_offset() >= 0,
|
||||
"bad checksum control: the same request with a good flag is served");
|
||||
CHECK(first_body_mismatch() == -1,
|
||||
"bad checksum control: the file that follows is intact");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc > 1 && !strcmp(argv[1], "-v"))
|
||||
verbose = 1;
|
||||
|
||||
printf("== httpd: accounting for the bytes actually sent ==\n");
|
||||
scenario_steady_window();
|
||||
scenario_shrinking_window();
|
||||
scenario_growing_window();
|
||||
scenario_rexmit_after_shrink();
|
||||
scenario_bad_l4_checksum();
|
||||
|
||||
printf("\n%s (%d failure%s)\n",
|
||||
failures ? "BENCH: FAILURES" : "BENCH: ALL PASS",
|
||||
failures, failures == 1 ? "" : "s");
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* test_page_json.c - the JSON generators of httpd/page_impl.c, fed by the
|
||||
* table code of rtl837x_port.c over the simulated engine. Both modules are
|
||||
* compiled unmodified, so what the web page shows is checked against what
|
||||
* the CLI configured, through the same bytes the switch would hold.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "machine.h"
|
||||
#include "page_impl.h"
|
||||
#include "support.h"
|
||||
#include "hw_mock.h"
|
||||
|
||||
extern uint8_t outbuf[TCP_OUTBUF_SIZE];
|
||||
extern uint16_t slen;
|
||||
extern uint8_t vlan_names[VLAN_NAMES_SIZE];
|
||||
extern uint16_t vlan_ptr;
|
||||
extern uint16_t management_vlan;
|
||||
|
||||
/* The response body: what follows the blank line after the header. */
|
||||
static const char *body(void)
|
||||
{
|
||||
outbuf[slen < TCP_OUTBUF_SIZE ? slen : TCP_OUTBUF_SIZE - 1] = 0;
|
||||
const char *p = strstr((const char *)outbuf, "\r\n\r\n");
|
||||
return p ? p + 4 : (const char *)outbuf;
|
||||
}
|
||||
|
||||
static int has(const char *needle) { return strstr(body(), needle) != 0; }
|
||||
|
||||
static int count(const char *needle)
|
||||
{
|
||||
int n = 0;
|
||||
for (const char *p = body(); (p = strstr(p, needle)); p += strlen(needle))
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Brackets and braces balance outside strings, quotes pair up. */
|
||||
static int balanced(void)
|
||||
{
|
||||
int depth = 0, instr = 0;
|
||||
for (const char *p = body(); *p; p++) {
|
||||
if (*p == '"') { instr = !instr; continue; }
|
||||
if (instr) continue;
|
||||
if (*p == '{' || *p == '[') depth++;
|
||||
if (*p == '}' || *p == ']') depth--;
|
||||
if (depth < 0) return 0;
|
||||
}
|
||||
return depth == 0 && !instr;
|
||||
}
|
||||
|
||||
static void name_vlan(uint16_t vid, const char *name)
|
||||
{
|
||||
static const char h[] = "0123456789abcdef";
|
||||
vlan_names[vlan_ptr++] = h[(vid >> 8) & 0xf];
|
||||
vlan_names[vlan_ptr++] = h[(vid >> 4) & 0xf];
|
||||
vlan_names[vlan_ptr++] = h[vid & 0xf];
|
||||
while (*name) vlan_names[vlan_ptr++] = *name++;
|
||||
vlan_names[vlan_ptr++] = ' ';
|
||||
vlan_names[vlan_ptr] = 0;
|
||||
}
|
||||
|
||||
static void make_vlan(uint16_t vid, uint16_t members, uint16_t tagged)
|
||||
{
|
||||
vlan_settings.vlan = vid;
|
||||
vlan_settings.members = members;
|
||||
vlan_settings.tagged = tagged;
|
||||
vlan_create();
|
||||
}
|
||||
|
||||
static void t_vlan(void)
|
||||
{
|
||||
printf("[test] /vlan.json shows what vlan_create and pvid wrote\n");
|
||||
hw_reset(); out_reset(); vlan_ptr = 0; vlan_names[0] = 0;
|
||||
make_vlan(10, 0x0015, 0x0004);
|
||||
name_vlan(10, "lab");
|
||||
port_pvid_set(0, 10);
|
||||
port_pvid_set(2, 10);
|
||||
port_pvid_set(4, 20);
|
||||
send_vlan(10);
|
||||
char want[32];
|
||||
snprintf(want, sizeof want, "\"members\":\"0x%x\"", hw_vlan_word(10));
|
||||
CHECK(has(want), "members is the entry word");
|
||||
CHECK(has("\"name\":\"lab\""), "name comes from the name table");
|
||||
CHECK(has("\"pvid\":\"0x0005\""), "pvid mask has ports 1 and 3, not 5");
|
||||
CHECK(balanced(), "valid JSON");
|
||||
}
|
||||
|
||||
static void t_vlanlist(void)
|
||||
{
|
||||
printf("[test] /vlanlist lists the VLANs that exist\n");
|
||||
hw_reset(); out_reset(); vlan_ptr = 0; vlan_names[0] = 0;
|
||||
make_vlan(10, 0x0015, 0x0004);
|
||||
make_vlan(20, 0x00f0, 0x0000);
|
||||
make_vlan(4094, 0x0001, 0x0000);
|
||||
name_vlan(10, "lab");
|
||||
name_vlan(4094, "top");
|
||||
management_vlan = 10;
|
||||
send_vlanlist();
|
||||
CHECK(has("\"mgmt\":10"), "management VLAN");
|
||||
CHECK(has("{\"id\":10,\"name\":\"lab\"}"), "VLAN 10 with its name");
|
||||
CHECK(has("{\"id\":20,\"name\":\"\"}"), "VLAN 20 without a name");
|
||||
CHECK(has("{\"id\":4094,\"name\":\"top\"}"), "VLAN 4094 is the last one listed");
|
||||
CHECK(count("\"id\":") == 3, "and nothing else");
|
||||
CHECK(balanced(), "valid JSON");
|
||||
vlan_delete(20);
|
||||
send_vlanlist();
|
||||
CHECK(count("\"id\":") == 2 && !has("\"id\":20"), "a deleted VLAN drops out");
|
||||
management_vlan = 1;
|
||||
}
|
||||
|
||||
static const uint8_t base_mac[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00 };
|
||||
|
||||
static void put(uint16_t idx, uint8_t last, uint16_t vid, uint8_t port, bool st)
|
||||
{
|
||||
uint8_t m[6];
|
||||
memcpy(m, base_mac, 6);
|
||||
m[5] = last;
|
||||
hw_l2_put(idx, m, vid, port, st);
|
||||
}
|
||||
|
||||
static void t_l2(void)
|
||||
{
|
||||
printf("[test] /l2.json walks the table\n");
|
||||
hw_reset(); out_reset();
|
||||
put(0x010, 0x01, 1, 4, false);
|
||||
put(0x020, 0x02, 2, CPU_PORT, true);
|
||||
put(0x8f0, 0x03, 1, 7, false);
|
||||
send_l2(0);
|
||||
CHECK(count("\"mac\":") == 4, "three entries, and the first one again: that repeat is how the page sees the wrap");
|
||||
CHECK(count("\"idx\":\"0010\"") == 2 && strstr(body(), "\"idx\":\"0010\"}]"), "the repeat closes the list");
|
||||
CHECK(has("{\"vlan\":\"001\",\"mac\":\"00:11:22:33:44:01\",\"type\":\"l\",\"port\":4,\"lag\":0,\"idx\":\"0010\"}"), "learned entry, VLAN, port and index");
|
||||
CHECK(has("\"mac\":\"00:11:22:33:44:02\",\"type\":\"s\",\"port\":9"), "static entry on the CPU port");
|
||||
CHECK(has("\"idx\":\"08f0\""), "an index above 0x800 keeps its high bit");
|
||||
CHECK(balanced(), "valid JSON");
|
||||
|
||||
out_reset();
|
||||
send_l2(0x100);
|
||||
const char *b = body();
|
||||
CHECK(strstr(b, "44:03") && strstr(b, "44:03") < strstr(b, "44:01"), "starting at 0x100 lists 0x8f0 first and wraps");
|
||||
CHECK(count("\"mac\":") == 4 && count("44:03") == 2, "and still finds all three before repeating 0x8f0");
|
||||
}
|
||||
|
||||
/* Walk the table the way the page does: ask for the index after the last
|
||||
* entry of each page until an index comes back that was seen before. */
|
||||
static void t_l2_page(void)
|
||||
{
|
||||
printf("[test] /l2.json pages the way the web page walks it\n");
|
||||
hw_reset(); out_reset();
|
||||
for (int i = 0; i < 40; i++)
|
||||
put(0x100 + i * 3, 0x10 + i, 1, i % 8, false);
|
||||
uint8_t seen[4096 / 8] = { 0 };
|
||||
int pages = 0, unique = 0, wrapped = 0, idx = 0, biggest = 0;
|
||||
while (!wrapped && pages < 10) {
|
||||
out_reset();
|
||||
send_l2(idx);
|
||||
pages++;
|
||||
if (slen > TCP_OUTBUF_SIZE || !balanced())
|
||||
break;
|
||||
if ((int)slen > biggest)
|
||||
biggest = slen;
|
||||
int n = 0, last = -1;
|
||||
for (const char *p = body(); (p = strstr(p, "\"idx\":\"")); p += 7) {
|
||||
int v = (int)strtol(p + 7, 0, 16);
|
||||
n++;
|
||||
if (seen[v >> 3] & (1 << (v & 7))) { wrapped = 1; break; }
|
||||
seen[v >> 3] |= 1 << (v & 7);
|
||||
unique++;
|
||||
last = v;
|
||||
}
|
||||
if (!n)
|
||||
break;
|
||||
idx = last + 1;
|
||||
}
|
||||
CHECK(wrapped, "the walk ends on a repeated index");
|
||||
CHECK(unique == 40, "and has visited every entry once");
|
||||
CHECK(pages == 2, "in two pages");
|
||||
CHECK(biggest <= TCP_OUTBUF_SIZE, "no page outgrows outbuf");
|
||||
CHECK(balanced(), "every page is valid JSON");
|
||||
}
|
||||
|
||||
static void t_status_counters(void)
|
||||
{
|
||||
printf("[test] /status.json prints 64-bit packet counters in full\n");
|
||||
hw_reset(); out_reset();
|
||||
hw_counter_set(0, STAT_COUNTER_TX_PKTS, 0x100000005ULL);
|
||||
hw_counter_set(0, STAT_COUNTER_RX_PKTS, 0x00000000000000ffULL);
|
||||
hw_counter_set(1, STAT_COUNTER_TX_PKTS, 0x00000001ffffffffULL);
|
||||
send_status();
|
||||
CHECK(has("\"txG\":\"0x100000005\""), "a counter past 2^32 keeps the zeros of its low word");
|
||||
CHECK(has("\"rxG\":\"0xff\""), "a small counter stays short");
|
||||
CHECK(has("\"txG\":\"0x1ffffffff\""), "a low word of all ones");
|
||||
out_reset();
|
||||
send_counters(1);
|
||||
CHECK(has("\"0x100000005\"") && has("\"0x0\""), "/counters.json prints them the same way");
|
||||
CHECK(slen <= TCP_OUTBUF_SIZE, "fits the buffer");
|
||||
CHECK(balanced(), "valid JSON");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("== httpd/page_impl.c JSON tests ==\n");
|
||||
t_vlan();
|
||||
t_vlanlist();
|
||||
t_l2();
|
||||
t_l2_page();
|
||||
t_status_counters();
|
||||
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
|
||||
return tests_failed ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* test_port_tables.c - rtl837x_port.c against the simulated table engine.
|
||||
*
|
||||
* What the firmware writes to the VLAN and L2 tables is checked against an
|
||||
* independent statement of the entry layout (hw_mock.h), and what it reads
|
||||
* back is checked against what it wrote. The module is compiled unmodified.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_regs.h"
|
||||
#include "rtl837x_port.h"
|
||||
#include "machine.h"
|
||||
#include "support.h"
|
||||
#include "hw_mock.h"
|
||||
|
||||
extern struct machine_runtime machine_detected;
|
||||
|
||||
/* VLAN entry as vlan_create() lays it out: bit 25 valid, bits 0-9 members,
|
||||
* bits 10-19 the untag set, which is every port not in the tagged set (the
|
||||
* bit of a non-member is meaningless to the switch and stays set). */
|
||||
static uint32_t vlan_word(uint16_t members, uint16_t tagged)
|
||||
{
|
||||
return (1u << 25) | ((uint32_t)(~tagged & 0x3ff) << 10) | members;
|
||||
}
|
||||
|
||||
static void t_vlan_roundtrip(void)
|
||||
{
|
||||
printf("[test] VLAN entry: create, read back, delete\n");
|
||||
hw_reset(); out_reset();
|
||||
vlan_settings.vlan = 10;
|
||||
vlan_settings.members = 0x0015; /* ports 1, 3, 5 */
|
||||
vlan_settings.tagged = 0x0004; /* port 3 tagged */
|
||||
vlan_create();
|
||||
/* the CPU port is always a tagged member */
|
||||
CHECK(hw_vlan_word(10) == vlan_word(0x0015 | 0x0200, 0x0004 | 0x0200), "vlan 10 entry has the documented layout");
|
||||
CHECK(hw_vlan_word(11) == 0, "the neighbouring entry is untouched");
|
||||
|
||||
uint32_t w = hw_vlan_word(10);
|
||||
CHECK(vlan_get(10) == 0, "vlan_get finds it");
|
||||
CHECK(((uint32_t)sfr_data[0] << 24 | (uint32_t)sfr_data[1] << 16 | (uint32_t)sfr_data[2] << 8 | sfr_data[3]) == w,
|
||||
"and returns the word that was written");
|
||||
CHECK(sfr_data[0] & 0x02, "with the valid bit the JSON generators test for");
|
||||
|
||||
unsigned long r = hw_reads;
|
||||
CHECK(vlan_get(4095) == -1, "VLAN 4095 is refused");
|
||||
CHECK(hw_reads == r, "without touching the engine");
|
||||
|
||||
vlan_delete(10);
|
||||
CHECK(hw_vlan_word(10) == 0, "vlan_delete clears the entry");
|
||||
vlan_delete(0);
|
||||
vlan_delete(4095);
|
||||
CHECK(hw_vlan_word(0) == 0 && hw_vlan_word(4095) == 0, "VLAN 0 and 4095 cannot be deleted");
|
||||
}
|
||||
|
||||
static void t_vlan_rtl8372(void)
|
||||
{
|
||||
printf("[test] VLAN entry on an RTL8372: ports 0-2 are not there\n");
|
||||
hw_reset();
|
||||
machine_detected.isRTL8373 = 0;
|
||||
vlan_settings.vlan = 20;
|
||||
vlan_settings.members = 0x03ff;
|
||||
vlan_settings.tagged = 0x0000;
|
||||
vlan_create();
|
||||
uint32_t w = hw_vlan_word(20);
|
||||
CHECK(((w >> 10) & 0x7) == 0, "the untagged bits of ports 0-2 stay clear");
|
||||
CHECK((w & 0x3ff) == 0x03ff, "the member bits are what was asked for");
|
||||
machine_detected.isRTL8373 = 1;
|
||||
}
|
||||
|
||||
static void t_pvid(void)
|
||||
{
|
||||
printf("[test] PVID: two ports share one register\n");
|
||||
hw_reset();
|
||||
port_pvid_set(2, 100);
|
||||
port_pvid_set(3, 4094);
|
||||
CHECK(port_pvid_get(2) == 100, "even port reads back");
|
||||
CHECK(port_pvid_get(3) == 4094, "odd port reads back");
|
||||
port_pvid_set(3, 7);
|
||||
CHECK(port_pvid_get(2) == 100, "writing the odd port leaves the even one alone");
|
||||
CHECK(port_pvid_get(3) == 7, "and takes the new value");
|
||||
port_pvid_set(2, 4001);
|
||||
CHECK(port_pvid_get(3) == 7, "writing the even port leaves the odd one alone");
|
||||
CHECK(port_pvid_get(8) == 0, "an untouched port reads 0");
|
||||
}
|
||||
|
||||
static void t_l2mc(void)
|
||||
{
|
||||
printf("[test] static multicast entry steering a group to the CPU\n");
|
||||
hw_reset();
|
||||
port_l2mc_set(0x0e, 2, PMASK_CPU);
|
||||
const uint8_t mac[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e };
|
||||
const struct hw_l2 *e = hw_l2_find(mac, 2);
|
||||
CHECK(e != 0, "the entry exists for 01:80:c2:00:00:0e in VLAN 2");
|
||||
if (e) {
|
||||
uint8_t m[6]; uint16_t vid, pm; bool valid, st, mc;
|
||||
hw_l2_decode(e, m, &vid, &pm, &valid, &st, &mc);
|
||||
CHECK(valid, "valid");
|
||||
CHECK(mc, "multicast");
|
||||
CHECK(pm == PMASK_CPU, "member mask is the CPU port alone");
|
||||
}
|
||||
port_l2mc_set(0x0e, 2, PMASK_CPU | 0x0003);
|
||||
e = hw_l2_find(mac, 2);
|
||||
CHECK(hw_l2_count() == 1, "writing the same key again replaces, not adds");
|
||||
if (e) {
|
||||
uint8_t m[6]; uint16_t vid, pm; bool valid, st, mc;
|
||||
hw_l2_decode(e, m, &vid, &pm, &valid, &st, &mc);
|
||||
CHECK(pm == (PMASK_CPU | 0x0003), "with the new mask, low bits included");
|
||||
}
|
||||
}
|
||||
|
||||
static void t_static_mgmt(void)
|
||||
{
|
||||
printf("[test] the management MAC pinned to the CPU port\n");
|
||||
hw_reset();
|
||||
uint8_t mac[6] = { 0x02, 0x11, 0x22, 0x33, 0x44, 0x55 };
|
||||
port_l2_static_mgmt(mac, 2, false);
|
||||
const struct hw_l2 *e = hw_l2_find(mac, 2);
|
||||
CHECK(e != 0, "entry present in VLAN 2");
|
||||
if (e) {
|
||||
uint8_t m[6]; uint16_t vid, p; bool valid, st, mc;
|
||||
hw_l2_decode(e, m, &vid, &p, &valid, &st, &mc);
|
||||
CHECK(valid && st && !mc, "valid, static, unicast");
|
||||
CHECK(p == CPU_PORT, "on the CPU port");
|
||||
}
|
||||
port_l2_static_mgmt(mac, 0, false);
|
||||
CHECK(hw_l2_find(mac, 1) != 0, "management VLAN 0 means VLAN 1");
|
||||
port_l2_static_mgmt(mac, 2, true);
|
||||
CHECK(hw_l2_find(mac, 2) == 0, "removal deletes the VLAN 2 entry");
|
||||
CHECK(hw_l2_find(mac, 1) != 0, "and leaves the other one");
|
||||
port_l2_static_mgmt(mac, 3, true);
|
||||
CHECK(hw_l2_count() == 1, "removing an entry that is not there changes nothing");
|
||||
}
|
||||
|
||||
static void t_flush(void)
|
||||
{
|
||||
printf("[test] flushing a port forgets its learned entries only\n");
|
||||
hw_reset();
|
||||
const uint8_t a[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x01 };
|
||||
const uint8_t b[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x02 };
|
||||
const uint8_t c[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x03 };
|
||||
hw_l2_put(0x010, a, 1, 4, false);
|
||||
hw_l2_put(0x020, b, 1, 4, true);
|
||||
hw_l2_put(0x030, c, 1, 5, false);
|
||||
port_l2_forget_port(4);
|
||||
CHECK(hw_l2_find(a, 1) == 0, "learned entry on port 5 (index 4) gone");
|
||||
CHECK(hw_l2_find(b, 1) != 0, "static entry on the same port stays");
|
||||
CHECK(hw_l2_find(c, 1) != 0, "entry on another port stays");
|
||||
port_l2_forget();
|
||||
CHECK(hw_l2_find(c, 1) == 0 && hw_l2_find(b, 1) != 0, "forget-all drops every learned entry and keeps the static one");
|
||||
}
|
||||
|
||||
static void t_lag(void)
|
||||
{
|
||||
printf("[test] trunk membership and its hash seed\n");
|
||||
hw_reset();
|
||||
port_lag_members_set(1, 0x0180);
|
||||
CHECK(port_lag_members_get(1) == 0x0180, "members read back");
|
||||
CHECK(port_lag_of(7) == 1 && port_lag_of(8) == 1, "both ports belong to group 2");
|
||||
CHECK(port_lag_of(0) == PORT_LAG_NONE, "a port outside is in no group");
|
||||
CHECK((hw_reg_get(RTL837X_TRK_HASH_CTRL_BASE + 4) & 0xff) == LAG_HASH_DEFAULT, "an unset hash gets the default");
|
||||
hw_reg_set(RTL837X_TRK_HASH_CTRL_BASE + 8, 0x06);
|
||||
port_lag_members_set(2, 0x0060);
|
||||
CHECK((hw_reg_get(RTL837X_TRK_HASH_CTRL_BASE + 8) & 0xff) == 0x06, "a hash already set is kept");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("== rtl837x_port.c table tests ==\n");
|
||||
t_vlan_roundtrip();
|
||||
t_vlan_rtl8372();
|
||||
t_pvid();
|
||||
t_l2mc();
|
||||
t_static_mgmt();
|
||||
t_flush();
|
||||
t_lag();
|
||||
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
|
||||
return tests_failed ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* test_tick_gate.c - the timers of the main loop keep time by the system
|
||||
* tick, however often the loop passes. The gate is the TICKS_DUE macro from
|
||||
* rtl837x_common.h; the loop bodies of idle() and handle_tx() are restated
|
||||
* here, so this checks the arithmetic, not those functions.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rtl837x_common.h"
|
||||
#include "rtl837x_stp.h"
|
||||
#include "support.h"
|
||||
|
||||
volatile uint32_t ticks;
|
||||
|
||||
#define STP_TICK_STEP (SYS_TICK_HZ / STP_HZ)
|
||||
#define STP_CATCH_UP 8
|
||||
|
||||
static uint8_t stp_tick_last, tx_tick_last;
|
||||
static unsigned stp_calls, tx_calls;
|
||||
|
||||
/* One pass of the loop: the STP block of idle() and the gate of handle_tx() */
|
||||
static void pass(void)
|
||||
{
|
||||
uint8_t n = STP_CATCH_UP;
|
||||
while (n-- && TICKS_DUE(stp_tick_last, STP_TICK_STEP)) {
|
||||
stp_tick_last += STP_TICK_STEP;
|
||||
stp_calls++;
|
||||
}
|
||||
if (TICKS_DUE(tx_tick_last, 1)) {
|
||||
tx_tick_last = (uint8_t)ticks;
|
||||
tx_calls++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run `seconds` of wall clock with one pass every `pass_us` microseconds. */
|
||||
static void run(double pass_us, unsigned seconds)
|
||||
{
|
||||
double t = 0, next_tick = 0, tick_us = 1e6 / SYS_TICK_HZ, end = seconds * 1e6;
|
||||
ticks = 0;
|
||||
stp_tick_last = tx_tick_last = 0;
|
||||
stp_calls = tx_calls = 0;
|
||||
while (t < end) {
|
||||
while (next_tick <= t) { ticks++; next_tick += tick_us; }
|
||||
pass();
|
||||
t += pass_us;
|
||||
}
|
||||
}
|
||||
|
||||
static void t_rates(void)
|
||||
{
|
||||
printf("[test] STP time follows the tick whatever the loop does\n");
|
||||
run(5000, 10);
|
||||
CHECK(stp_calls == 10 * STP_HZ, "one pass per tick: 500 STP steps in 10 s");
|
||||
CHECK(tx_calls == 10 * SYS_TICK_HZ, "and 2000 TX periodics");
|
||||
run(16000, 10);
|
||||
CHECK(stp_calls >= 10 * STP_HZ - 1 && stp_calls <= 10 * STP_HZ, "a 16 ms pass, as under an IPv4 stream: still 500 (was 156 when the clock counted passes)");
|
||||
CHECK(tx_calls == 625, "TX periodic once per pass when passes are slower than the tick");
|
||||
run(600, 10);
|
||||
CHECK(stp_calls == 10 * STP_HZ, "a 0.6 ms pass, the loop no longer sleeping: still 500 (was 4166)");
|
||||
CHECK(tx_calls == 10 * SYS_TICK_HZ, "TX periodic capped at the tick rate");
|
||||
run(1300000, 13);
|
||||
CHECK(stp_calls <= 10 * STP_CATCH_UP, "a 1.3 s pass loses time instead of firing 65 steps at once");
|
||||
}
|
||||
|
||||
static void t_wrap(void)
|
||||
{
|
||||
printf("[test] the byte arithmetic survives the tick counter wrapping\n");
|
||||
ticks = 0xfffffffeUL;
|
||||
stp_tick_last = (uint8_t)ticks;
|
||||
stp_calls = 0;
|
||||
for (int i = 0; i < 8; i++) { ticks++; pass(); }
|
||||
CHECK(stp_calls == 2, "two STP steps across 0xffffffff -> 0x00000006");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("== tick gate tests ==\n");
|
||||
t_rates();
|
||||
t_wrap();
|
||||
printf("\n%d checks, %d failed\n", tests_run, tests_failed);
|
||||
return tests_failed ? 1 : 0;
|
||||
}
|
||||
@@ -318,7 +318,7 @@ int main(int argc, char **argv)
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "#include <stdint.h>\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p,
|
||||
"typedef enum mime_type_e {\n mime_HTML = 0,\n mime_SVG,\n mime_ICO,\n mime_PNG,\n mime_JS,\n mime_CSS,\n mime_TXT\n} mime_type_t;\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "struct f_data {\n __code char *file;\n uint32_t start;\n uint16_t len;\n mime_type_t mime;\n uint8_t gzip;\n};\n\n");
|
||||
defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "struct f_data {\n __code const char *file;\n uint32_t start;\n uint16_t len;\n mime_type_t mime;\n uint8_t gzip;\n};\n\n");
|
||||
// defbuf_p += snprintf(&dbuf[defbuf_p], DEF_SIZE - defbuf_p, "typedef uint16_t (* fcall_ptr)(void);\n\n");
|
||||
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "// This file is automatically generated, do not edit!\n\n");
|
||||
@@ -326,9 +326,9 @@ int main(int argc, char **argv)
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#include \"%s.h\"\n\n", arguments.prefix);
|
||||
if (arguments.bank)
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "#pragma codeseg %s\n#pragma constseg %s\n\n", arguments.bank, arguments.bank);
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " __code char * __code mime_strings[] = {\n \"text/html\",\n \"image/svg+xml\",\n"
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, " __code const char * __code const mime_strings[] = {\n \"text/html\",\n \"image/svg+xml\",\n"
|
||||
" \"image/svg+xml\",\n \"image/png\",\n \"text/javascript\",\n \"text/css\",\n \"text/plain\"};\n\n");
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "__code struct f_data f_data[] = {\n");
|
||||
ibuf_p += snprintf(&ibuf[ibuf_p], INDEX_SIZE - ibuf_p, "__code const struct f_data f_data[] = {\n");
|
||||
// fbuf_p += snprintf(&fbuf[fbuf_p], DEF_SIZE - fbuf_p, "\n__code fcall_ptr f_calls[] = {\n");
|
||||
|
||||
// Now that the beginning of the buffer is filled with out image, optionally resize the image
|
||||
@@ -338,15 +338,16 @@ int main(int argc, char **argv)
|
||||
if (stat(arguments.data_file, &s) == 0 && s.st_mode & S_IFDIR) {
|
||||
printf("Adding entries in directory %s\n", arguments.data_file);
|
||||
addsDir = true;
|
||||
DIR *dirptr = opendir(arguments.data_file);
|
||||
if (!dirptr) {
|
||||
struct dirent **entries;
|
||||
int n_entries = scandir(arguments.data_file, &entries, NULL, alphasort);
|
||||
if (n_entries < 0) {
|
||||
fprintf(stderr, "%s: ", arguments.data_file);
|
||||
perror("Error opening directory");
|
||||
return 5;
|
||||
}
|
||||
struct dirent *in_file;
|
||||
int addr = arguments.address;
|
||||
while ( (in_file = readdir(dirptr)) ) {
|
||||
for (int e = 0; e < n_entries; e++) {
|
||||
struct dirent *in_file = entries[e];
|
||||
snprintf(pathbuffer, PATH_SIZE, "%s/%s", arguments.data_file, in_file->d_name);
|
||||
if (stat(pathbuffer, &s) < 0) {
|
||||
fprintf(stderr, "%s: ", pathbuffer);
|
||||
@@ -377,6 +378,9 @@ int main(int argc, char **argv)
|
||||
addidx(in_file->d_name, addr, data_read);
|
||||
addr += data_read;
|
||||
}
|
||||
for (int e = 0; e < n_entries; e++)
|
||||
free(entries[e]);
|
||||
free(entries);
|
||||
} else {
|
||||
size_t data_read = addfile(arguments.data_file, arguments.address);
|
||||
|
||||
@@ -437,7 +441,7 @@ int main(int argc, char **argv)
|
||||
fputs(xbuf, ofile);
|
||||
fputs(fbuf, ofile);
|
||||
fclose(ofile);
|
||||
} else if (addsDir){
|
||||
} else if (addsDir && !argv[arg_index]) {
|
||||
puts(dbuf);
|
||||
puts(xbuf);
|
||||
puts(ibuf);
|
||||
|
||||
@@ -447,13 +447,41 @@ void send_mtu(int s)
|
||||
json_object_object_add(v, "mtu", json_object_new_string(mtu));
|
||||
json_object_array_add(mtus, v);
|
||||
}
|
||||
write(s, header, strlen(header));
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(mtus, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(mtus);
|
||||
}
|
||||
|
||||
void send_lldp(int s)
|
||||
{
|
||||
struct json_object *c, *portStatuses, *p;
|
||||
const char *jstring;
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n\r\n";
|
||||
|
||||
c = json_object_new_object();
|
||||
json_object_object_add(c, "on", json_object_new_int(1));
|
||||
portStatuses = json_object_new_array_ext(PORTS);
|
||||
|
||||
for (int i = 1; i <= PORTS; i++) {
|
||||
p = json_object_new_object();
|
||||
json_object_object_add(p, "portNum", json_object_new_int(i));
|
||||
json_object_object_add(p, "logPort", json_object_new_int(i-1));
|
||||
json_object_object_add(p, "name", json_object_new_string(""));
|
||||
json_object_object_add(p, "permitted", json_object_new_int(1));
|
||||
json_object_array_add(portStatuses, p);
|
||||
}
|
||||
|
||||
json_object_object_add(c, "portStatus", portStatuses);
|
||||
|
||||
write(s, header, strlen(header));
|
||||
|
||||
jstring = json_object_to_json_string_ext(c, JSON_C_TO_STRING_PLAIN);
|
||||
write(s, jstring, strlen(jstring));
|
||||
json_object_put(c);
|
||||
}
|
||||
|
||||
void send_cmd_log(int s)
|
||||
{
|
||||
@@ -468,7 +496,6 @@ void send_cmd_log(int s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void send_config(int s)
|
||||
{
|
||||
char *header = "HTTP/1.1 200 OK\r\n"
|
||||
@@ -701,6 +728,13 @@ void launch(struct Server *server)
|
||||
else
|
||||
send_vlan(new_socket, vlan);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/lldp.json", 10)) {
|
||||
printf("LLDP request");
|
||||
if (!authenticated)
|
||||
send_unauthorized(new_socket);
|
||||
else
|
||||
send_lldp(new_socket);
|
||||
goto done;
|
||||
} else if (!strncmp(&buffer[4], "/cmd_log", 8)) {
|
||||
printf("Request cmd_log\n");
|
||||
if (!authenticated)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define BUFFER_SIZE 131072
|
||||
#define BUFFER_SIZE 262144
|
||||
|
||||
struct Server {
|
||||
int domain;
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
|
||||
#include "../rtl837x_common.h"
|
||||
|
||||
#if UIP_FORWARDING
|
||||
|
||||
/*
|
||||
* The list of registered network interfaces.
|
||||
*/
|
||||
@@ -535,3 +537,5 @@ uip_fw_periodic(void)
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* UIP_FORWARDING */
|
||||
@@ -43,6 +43,8 @@
|
||||
#include "uip-neighbor.h"
|
||||
#include "../rtl837x_common.h"
|
||||
|
||||
#if UIP_CONF_IPV6
|
||||
|
||||
#pragma codeseg BANK1
|
||||
#pragma constseg BANK1
|
||||
|
||||
@@ -170,3 +172,5 @@ uip_neighbor_lookup(__xdata uip_ipaddr_t ipaddr)
|
||||
return NULL;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
@@ -95,6 +95,9 @@
|
||||
#endif /* UIP_CONF_IPV6 */
|
||||
|
||||
#include "../rtl837x_common.h"
|
||||
#include "../rtl837x_regs.h"
|
||||
|
||||
extern __xdata uint8_t rx_headers[16];
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Variable definitions. */
|
||||
@@ -1120,6 +1123,12 @@ uip_process(u8_t flag) __banked
|
||||
goto drop;
|
||||
}
|
||||
#else /* UIP_UDP_CHECKSUMS */
|
||||
if (rx_headers[1] & RX_TAG_L4_CSUM_BAD) {
|
||||
UIP_STAT(++uip_stat.udp.drop);
|
||||
UIP_STAT(++uip_stat.udp.chkerr);
|
||||
UIP_LOG("udp: bad checksum.");
|
||||
goto drop;
|
||||
}
|
||||
uip_len = uip_len - UIP_IPUDPH_LEN;
|
||||
#endif /* UIP_UDP_CHECKSUMS */
|
||||
|
||||
@@ -1200,15 +1209,12 @@ uip_process(u8_t flag) __banked
|
||||
|
||||
/* Start of TCP input header processing code. */
|
||||
|
||||
// BUG: We need to reimplement this with RTL837x TCP checksum checking
|
||||
// i.e. figure out which bit in the RX-tag states the checksum is correct
|
||||
// if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP
|
||||
// checksum. */
|
||||
// UIP_STAT(++uip_stat.tcp.drop);
|
||||
// UIP_STAT(++uip_stat.tcp.chkerr);
|
||||
// UIP_LOG("tcp: bad checksum.");
|
||||
// goto drop;
|
||||
// }
|
||||
if (rx_headers[1] & RX_TAG_L4_CSUM_BAD) {
|
||||
UIP_STAT(++uip_stat.tcp.drop);
|
||||
UIP_STAT(++uip_stat.tcp.chkerr);
|
||||
UIP_LOG("tcp: bad checksum.");
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
||||
/* Demultiplex this segment. */
|
||||
|
||||
@@ -912,8 +912,8 @@ __xdata struct uip_udp_conn *uip_udp_new(__xdata uip_ipaddr_t * __xdata ripaddr,
|
||||
((__xdata u16_t *)addr1)[1] == ((__xdata u16_t *)addr2)[1])
|
||||
#define uip_ipaddr_cmpx(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__xdata u16_t *)addr2)[0] && \
|
||||
((__xdata u16_t *)addr1)[1] == ((__xdata u16_t *)addr2)[1])
|
||||
#define uip_ipaddr_cmpc(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__code u16_t *)addr2)[0] && \
|
||||
((__xdata u16_t *)addr1)[1] == ((__code u16_t *)addr2)[1])
|
||||
#define uip_ipaddr_cmpc(addr1, addr2) (((__xdata u16_t *)addr1)[0] == ((__code const u16_t *)addr2)[0] && \
|
||||
((__xdata u16_t *)addr1)[1] == ((__code const u16_t *)addr2)[1])
|
||||
#else /* !UIP_CONF_IPV6 */
|
||||
#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0)
|
||||
#endif /* !UIP_CONF_IPV6 */
|
||||
|
||||
@@ -464,6 +464,20 @@ extern __xdata uint8_t uip_buf[UIP_CONF_BUFFER_SIZE+2];
|
||||
#define UIP_BROADCAST UIP_CONF_BROADCAST
|
||||
#endif /* UIP_CONF_BROADCAST */
|
||||
|
||||
/**
|
||||
* Build the IP forwarding module.
|
||||
*
|
||||
* uip-fw.c forwards packets between several network interfaces. A
|
||||
* single-interface device does not call it and should not pay for it.
|
||||
*
|
||||
* \hideinitializer
|
||||
*/
|
||||
#ifndef UIP_CONF_FORWARDING
|
||||
#define UIP_FORWARDING 0
|
||||
#else /* UIP_CONF_FORWARDING */
|
||||
#define UIP_FORWARDING UIP_CONF_FORWARDING
|
||||
#endif /* UIP_CONF_FORWARDING */
|
||||
|
||||
/**
|
||||
* Print out a uIP log message.
|
||||
*
|
||||
|
||||