Commit Graph
186 Commits
Author SHA1 Message Date
d00f 024c8cef49 stp: arm the management failsafe only where an operator asked for it
Your console session shows the shape of this better than I could have. STP found
a loop, blocked the port, unblocked the other side of the pair, and then the
failsafe turned STP off. It had been disarmed by your first console command and
re-armed by the loop detection itself, so a mechanism that exists to protect
against a lockout ended up removing loop protection while a loop was physically
present. That is the part that did not make sense, and it wasn't the console.

Two changes, both narrowing.

Loop detection and root guard no longer arm the window. Those are the protocol
doing its job on evidence off the wire. Nothing an operator did needs undoing
there, and nobody is waiting to confirm anything.

Typing on the serial console no longer disarms it. The failsafe asks one
question, whether the operator can still reach management over the network, and
serial activity doesn't answer it. It proves somebody is standing at the box,
which is the one case where a lockout doesn't matter, and it took the safety net
away from a remote operator on behalf of someone not using it. HTTP activity
still confirms, because that is the path being measured, and the console in the
web interface counts for the same reason.

What is left arms on stp on, stp port N on and stp failsafe, each of them an
operator choosing something whose outcome the protocol then decides.

Gives back 61 bytes of BANK2, 31 of the common area and a byte of xdata.
2026-08-18 23:29:18 +02:00
d00f c72d36af36 stp: turn the management failsafe into a one-shot window
The failsafe used to watch management traffic for as long as STP ran, so
three minutes of nobody looking at the web UI took the tree down on any
quiet network. That made a standing STP config impractical, which is the
problem raised in the review of the original PR.

Enabling STP arms a window of stp_failsafe_s seconds. One HTTP request
inside it confirms that management survived the new tree and disarms the
watchdog; a silent window disables STP and restores forwarding. Both
outcomes print to the console and the syslog.

The window re-arms on any later event that newly takes a port out of
forwarding: a port rejoining via "stp port N on", root guard firing, the
loop latch. Those were covered by the old always-on surveillance and a
disarmed window would have left them able to cut management off for good.
If management traffic keeps flowing past the new block, the next request
confirms straight away, which is the correct verdict, the block did not
cut it. The arming deliberately does not refresh an already armed window:
root guard can re-fire on every hello, and refreshing the countdown on
each one would keep a cut-off window from ever expiring. A stable network
with nothing newly blocked never re-arms, which is the reviewed-for
behaviour.

The request or console command that causes the arming never counts as its
own confirmation: mgmt_alive is cleared when a command arms, and the
console hook only disarms when the window predates the command. Without
that, enabling from the web UI or the console would confirm the window
before the new tree had any chance to cut management off.

A command on the serial console confirms like HTTP does. An operator at
the console has out-of-band access that no tree can cut, so the automatic
restore only takes STP away from someone equipped to deal with the
situation. The hook sits on the interactive console path only, identified
by cmd_available, so neither the config replay at boot nor HTTP commands
pass through it.

After a confirmation STP runs unsupervised until something new blocks.
Headless installs where nobody will confirm should set stp failsafe 0;
doc/stp.md says so.

Costs two bytes of XDATA, the armed flag and the console-path snapshot;
stp.rel and rtlplayground.rel keep their segment sizes.
2026-08-18 23:29:08 +02:00
d00f 2110cf128a stp: management failsafe (commit-confirm) + bounded NIC waits
Enabling STP on a bridge whose management rides an in-band VLAN can cut
off that very management - and not only by our own blocking: on this
network the upstream TP-Link Easy Smart switch's "loop prevention"
reacted to our BPDU hellos by blocking ITS port towards us while our
ASIC was all-forwarding, isolating the whole segment until a power
cycle. Recoverable only by going quiet.

Add a commit-confirm watchdog: while STP is enabled, any HTTP request
re-arms a countdown ("stp failsafe <seconds>", default 180, 0 disables);
if management stays silent for the whole window, STP disables itself,
which also stops BPDU TX so a neighbour's loop protection can release
its block. The web UI polls /stp.json every 2 s, so an open browser
naturally keeps the watchdog re-armed. The trip is reported via
/stp.json (fs, fsT) and as a warning on the Spanning Tree page.

Deliberately not conditioned on our own MSTP port states - the incident
above proves the uplink can be dead while every local port forwards.

Also bound the NIC DMA busy-waits (nic_tx_packet, nic_rx_header,
nic_rx_packet): an unbounded spin on SFR_NIC_CTRL freezes the entire
main loop (timers, HTTP, ARP) if the ASIC ever fails to consume a
transfer; give up after ~65k polls and drop the frame instead.

Hardware-verified end to end: with priority 15 against a live RSTP
bridge the uplink died 6 s after "stp on" and the network recovered BY
ITSELF 66 s later (trip at 45 s + neighbour release), fsT=1, LACP and
LAN intact. Telemetry via syslog-to-edge-port host confirmed the full
chain: countdown 44->4, trip, hello TX stopping at the trip.

(cherry picked from commit 1fa9775156fd6d7ebfdda2382f73430b86601230)
2026-08-18 23:28:26 +02:00
d00f 524c37d7c7 stp: full RSTP configuration (bridge + per-port), CLI + GUI + persistence
Implements the standard 802.1D-2004/802.1w configuration surface:

Bridge:  priority (0-15 x4096), hello time, max age, forward delay,
         force-version (RSTP v2 / STP-compatible v0 Config BPDUs), tx hold
         count (per-port per-second BPDU budget).
Per port: enable, admin edge (forwarding immediately - no listen gap),
         auto edge (forwarding after 3 s of BPDU silence; DEFAULT, so
         host-facing ports no longer take the full forward delay),
         path cost (0=auto/20000), port priority, BPDU guard (port disabled
         on BPDU receipt), root guard (never accept a better root on the
         port), BPDU filter (no BPDUs in or out).

Engine additions: root max-age expiry (reclaim the tree when the root goes
silent), root path cost accounting (rx cost + root-port cost, advertised in
our BPDUs), loop detection (our own BPDU coming back blocks the port for a
listen period), topology-change counter, approximated per-port roles
(Root/Designated/Alternate) for diagnostics.

CLI: "stp prio|hello|maxage|fwd|txhold|version ..." and
"stp port <n> on|off|edge|cost|prio|guard|filter ..." (stp_parse, delegated
from cmd_parser); all forms accepted by the startup-config validator so the
whole configuration persists. /stp.json now reports config + status; the
Spanning Tree page exposes everything with immediate-apply controls and live
state/role columns (edit-in-flight guard against the 2 s refresh).

8051 memory: the module moves to code BANK2; internal-RAM pressure from
cross-bank calls resolved by xdata loop iterators/scratch, __reentrant on
the small helpers, and moving httpd's header-pointer globals to xdata.

Verified on hardware (SWTGW218AS): defaults land per standard; priority and
hello change live; admin-edge ports (the LACP bond uplinks) keep the LAN at
0% loss THROUGH "stp on"; auto-edge ports forward after 3 s; a port that
heard real BPDUs (a VM bridge behind physical port 6) correctly declined
auto-edge, sat out the full listen period and became Designated; tc counts
promotions; we win the root election at priority 16384 vs 32768.

(cherry picked from commit 09a34dc6acdc81ab9cab0727d2f4a59c68131a3e)
2026-08-18 23:28:23 +02:00
d00f 56fa96c494 igmp: only hand reports to the CPU while snooping is on
handle_rx() dispatched to igmp_packet_handler() on the destination
address alone, so an ordinary IGMPv3 report off the wire reached the
handler and could write a table entry whether or not anyone had asked
for snooping. The STP branch right above it is gated on stpEnabled;
this brings the IGMP branch in line.

Snooping state lived only in the per-port registers, and the receive
path cannot afford to read one per packet, so the flag shadows it:
igmp_enable() sets it, igmp_setup() clears it, and igmp_setup() runs
from both the boot path and "igmp off".

While here, igmp off becomes an explicit subcommand instead of the
fall-through, and an unrecognised igmp subcommand prints the usage
line rather than silently turning snooping off.

Six bytes of BANK1 and one of xdata, no internal RAM.
2026-08-16 23:42:46 +02:00
bloqaudio 3853a2701d machine: read a factory MAC from flash via mac_flash_offset
Adds an optional per-board mac_flash_offset. When non-zero, RTLPlayground
reads a 6-byte MAC from that flash address and uses it if it is a valid
globally-administered unicast address; otherwise it falls back to the
generated locally-administered MAC. Offset 0 (default for every board)
preserves current behaviour.

Enable it for the SWTGW218AS, whose stock firmware keeps the factory MAC
in nvcfg at 0x1FC000. RTLPlayground images and web upgrades only touch
flash below that region, so the factory MAC survives flashing.
2026-08-11 02:32:31 -05:00
René van Dorst 3f7db7e430 Merge pull request #297 from DrDoof/hostname
system: configurable hostname + show model on the System page
2026-08-07 18:10:34 +00:00
d00f 108ac9b8fc system: derive the default hostname after the startup config
Move the MAC-derived default name out of main() into its own function and
call it after execute_config(), returning early when the config already
set a name - a configured switch then does no work for it at all.

The body deliberately has no local variables. Locals here - counters and
pointers alike - land in the 8051's internal-RAM overlay, and on an image
with LACP and STP both enabled that overlay is exhausted: a loop makes the
linker fail with "Could not get 8 consecutive bytes in internal RAM for
area OSEG". Moving the code into its own function does not help, since the
overlay is shared across the whole image, and hoisting the locals to xdata
does not either, because itohex() is inline and brings its own frame. This
only shows up in an integrated build; the branch on its own links fine.

Suggested-by: vDorst
2026-08-05 16:48:36 +02:00
d00f 94716ceb5d system: derive the default hostname from the MAC address
Every switch came up as "RTLPlayground", so several of them on one
network were indistinguishable until someone configured a name. Append
the last three MAC octets (e.g. RTLPlayground-1ef924) - unique in
practice, still recognisable, and any "hostname ..." line in the startup
config overrides it as before.

Suggested-by: plaes
2026-08-04 05:43:05 +02:00
d00f f21b3a32bd system: configurable hostname (device identity)
Add a device hostname settable from the CLI (`hostname <text>`) and the
System Settings page. The value is sanitized on ingest to JSON-safe
printable ASCII (<=23 chars), stored in a shared __xdata buffer, seeded
to "RTLPlayground" at boot, persisted through the startup-config, and
reported in /information.json. It lives in the common header so other
modules can advertise it (LLDP uses it as the System Name TLV).
2026-07-25 13:07:09 +02:00
Sempr c473646389 Fix rate range for SDS_10GR return value
Broaden range of SFP+ rates mapped to SDS_10GR
A commonly used SFP+ form-factor 10GBASE-LR (Hisense LTF1303-BH+) reports 0x62(	BR Nominal: 9800MBd) at
power on and then switches to 0x64 after booting up.

0x62 -> 9.8gbps
0x63 -> 9.9gbps
0x64 -> 10gbps
0x6f -> 11.1gbps
0x70 -> 11.2gbps

These are outside of the previous 0x63-0x6f range which prevented the link from ever being brought up. So I changed the range to 0x62-0x6f
2026-07-24 16:02:20 +08:00
Matt Merhar 2221f0fa32 Add SFP quirk for devices that misreport DDM capability
On a QSFPTEK QT-SFP+-T (RTL8261C) 10GBase-T module, the diag type field
(92) comes back as 0x00, but there's actually some statistics available
like temperature. Other metrics may be hard-coded values.

Add a basic struct that allows matching on vendor and/or model, using a
bitfield to allow multiple quirks for a given SFP module. Only
SFP_QUIRK_DDM is implemented.

For modules matching SFP_QUIRK_DDM, attempt an I2C read of the MSB of
module voltage during probe if DDM is "unsupported" - if it's not 0xff,
override the reported options so we can pull the diagnostic data.

To allow simpler comparisons, convert the ASCII fields (vendor,
model, serial) from space-padded to standard NULL-terminated strings.

strcmp() is moved from httpd.c to rtlplayground.c alongside other string
functions and shared between them.

The __reentrant keyword is used for the new functions to avoid using up
additional OSEG space. This allocates the variables on the stack, which
is OK for this particular code path.

The JSON assembly in send_status() is slightly modified to treat the
sfp_module_* data as standard NULL-terminated strings, and a repeated
subtraction was moved into a uint8_t to declutter the code.
2026-07-13 01:31:29 -04:00
logicog 842d68af97 Add support for 100M on RTL8221B ports 2026-06-15 18:40:03 +02:00
TylerDurden-23 62065875e3 Revert "Don't disable flash DIO operation before flashing" 2026-06-07 10:42:39 +02:00
feelfree69 4ca5b4e87a Don't disable flash DIO operation before flashing - it works fine with DIO 2026-06-01 15:07:37 +02:00
René van Dorst ad64e450e1 Merge pull request #246 from logicog/sfp_speed
Add support for configuring SFP modules speeds via CLI
2026-05-31 18:33:05 +00:00
logicog 1a457c29ac Add support for 100FX modules and forcing 100FX 2026-05-30 23:08:44 +02:00
logicog 8c61010a84 Add support for configuring SFP modules speeds 2026-05-29 20:46:08 +02:00
Matt Merhar 73b99b2f08 Broaden range of SFP+ rates mapped to SDS_10GR
A commonly used SFP+ form-factor XGS-PON ONT (WAS-110) reports 0x63 at
power on and then switches to 0x64 after booting up.

0x63 -> 9.9gbps
0x64 -> 10gbps

These are outside of the previous 0x66-0x69 range which prevented the
link from ever being brought up.
2026-05-25 21:45:42 -04:00
UAb5eSMn 2316ffd493 Support for executing multiple commands via /cmd 2026-05-15 13:27:09 +02:00
René van Dorst 09d90d6d97 Merge pull request #175 from logicog/ZX310S-4T2XH
10GBit Ethernet Switch support (Horaco ZX310S-4T2XH)
2026-05-02 17:22:52 +00:00
feelfree69 3f66a18104 Merge branch 'main' into syslog 2026-04-24 12:01:30 +02:00
logicog 441340a4d4 Add SMI configuration support for dual 10G Ethernet 2026-04-24 10:53:05 +02:00
logicog 4f4f69ecc1 Handle RTL8261BE SerDes configuration
The RTL8261BE uses a 10GBit QSGMII connection. Add handler for initial
configuration of the SerDes speed and upon link changes.
2026-04-24 10:52:24 +02:00
logicog e280ccd2f9 Use RTL descriptor definition 2026-04-24 08:42:00 +02:00
logicog baa4e5e142 Use header structures of TX and RX, add dot1q for management VLAN TX 2026-04-22 22:36:26 +02:00
feelfree69 da8ec8fe88 Merge branch 'logicog:main' into syslog 2026-04-21 21:26:45 +02:00
René van Dorst d2e79d4d80 Fix: In commit 8cbafaa cmd_tokenize() has changed. Missed that it also used
outside cmd_parser.c.
Fix the other location and headerfile.
2026-04-21 21:17:22 +02:00
feelfree69 f7989cc737 Merge branch 'logicog:main' into syslog 2026-04-21 14:29:44 +02:00
René van Dorst 52d943d5e4 rtlplayground: de-__gptrput()-call in read_reg_timer() 2026-04-19 22:18:39 +02:00
feelfree69 e130777b24 serial console cosmetic change 2026-04-13 14:55:50 +02:00
feelfree69 c1a414833d Various refactorings 2026-04-12 13:02:42 +02:00
feelfree69 d776118815 Revert unneeded changes 2026-04-12 13:02:42 +02:00
feelfree69 eaa21d5975 rebase First try to make use of uIP for sending syslog 2026-04-12 13:02:37 +02:00
feelfree69 b60811b984 initialize all vars; remove unused code 2026-04-12 12:58:02 +02:00
feelfree69 b21bfac917 rebase first prototype 2026-04-12 12:57:49 +02:00
Tobias Diedrich fd9a7717ce Fix declaration of tx_buf_empty bit var
__sbit is for SFRs, for regular data __bit should be used.
Otherwise the variables is not correctly declared in the BSEG
section, leading to bit temporaries being allocated in the same
location.

When this causes the tx_buf_empty to be overwritten to 0, then
the next write_char will hang forever.
2026-04-04 22:02:45 +02:00
René van Dorst 97e73d95aa Merge pull request #183 from janh/fix-i2c-and-sfp-ddm
Fix I2C access and SFP diagnostic monitoring in web interface
2026-03-30 17:21:51 +00:00
Jan Hoffmann efe0c282ba Fix I2C access code
While the current implementation works for what it is actually used, it
is broken when trying to do larger transfers.

The length field in the control register has a size of 4 bits. In every
transfer, length+1 bytes are read. Thus, each transfer is limited to a
maximum of 16 bytes. Add a check for the length, and write the correct
value to the register.

Also update the loop in "sfp_send_data" to properly increment the output
register. Remove the unused special case for a length of 128 bytes.
2026-03-28 18:14:15 +01:00
René van Dorst 8b4e09ad69 Merge pull request #181 from janh/improve-1g-sfp-compat
Improve compatibility with 1G SFP modules
2026-03-27 22:58:30 +00:00
René van Dorst 34d53dddf2 Merge pull request #179 from bennydiamond/Early_boot_wipe_config
Wipe config if button held at boot
2026-03-27 20:05:55 +00:00
Jan Hoffmann 9f800bae01 Improve compatibility with 1G SFP modules
Some modules report a nominal signaling rate of 1200 MBd.
2026-03-27 17:56:40 +01:00
logicog df498b0879 Merge pull request #173 from diijkstra/vlan_console
Console: Add Ingress type & VLAN show table
2026-03-26 21:02:33 +01:00
bennydiamond 2bfbe5358b LED pattern definition on early boot reset
LED Double blink while button is held

FAST blink for 3 seconds when config is reset
2026-03-26 12:31:20 -04:00
bennydiamond dba3679e2f Wipe config if button held at boot
Blocking by design to prevent loading config

Button must be held between 10 and 30 seconds to trigger reset.

If held more than 30 seconds, boot normally. This is to prevent lock-up in case of weird hardware variants.
2026-03-25 23:15:04 -04:00
Jan Hoffmann ed6c95e522 Improve compatibility with 2.5G SFP modules
Some modules might report a nominal bitrate of 2500 Mbd or 3200 Mbd
instead of 3100 Mbd. Accept the entire range to make them work.
2026-03-24 15:26:29 +01:00
diijkstra f7fcf0eda7 Console: Add Ingress type & VLAN show table
Added new `vlan show` command to dump current VLAN settings.
Supports printing PVID & ingress filtering per port.

Added new `ingress [p]<mode>` command to setup ingress filtering.
Added wrappers for enabling/disabling vlan filtering. Currently
not configurable, but state in console is read via ASIC registers.

Full VLAN dump & web support of new commands will be added later.
2026-03-21 12:29:26 +01:00
logicog 59e7a21955 Merge pull request #159 from diijkstra/web_sfp_state
Web: Add SFP state/pin status
2026-03-19 05:22:24 +01:00
chriz baa3e7edb7 Fix 1GBase-T SFP module not working on serdes port 1. 2026-03-14 16:33:54 +01:00
diijkstra 1f6e07a1af Web: Add SFP state/pin status
The state of the SFP module is being already send in status.json,
but was not parsed via Web UI. When debuging SFP LOS/Signal detection
it is usefull to see what module is reporting back.

Extended the SFP mouse-over information with:
 - RX LOS as reported in 0x02 bit of register 238
 - External TX Disabled from 0x80 bit of register 238
 - TX fault from 0x04 of the same register
 - The last state of RX LOS pin (available also when there is no 0x40
   option on the module)

This should help identify missing/incorrect setup of TX disabled pin.
2026-03-13 23:56:43 +01:00