DSA numbers LAGs from 1 to num_lag_ids. The driver uses the id as it is
to index its LAG arrays and as the hardware trunk group, both of which
start at 0. Group 0 is therefore never used and the last id is refused,
so one LAG fewer than the switch supports can be offloaded.
Accept ids from 1 to num_lag_ids and subtract one where the id becomes
a group.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Quinn O'Shea <qoshea@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25792
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
port_lag_leave returns 0 whatever happened, and it clears the port from
the driver's LAG masks before it asks the hardware to release it. When
the release fails, DSA is told that it worked and the driver no longer
counts the port as a LAG member while the hardware still does.
Release the port in hardware first, update the masks only when that
succeeded, and return the error, which DSA then logs.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Quinn O'Shea <qoshea@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25792
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The first member of a LAG becomes its primary port when lag_primary[]
holds -1, but the array comes zero-filled from devm_kzalloc() and is
never set to -1. Every member is therefore marked non-primary, and the
FDB and MDB code of the RTL83xx skips non-primary ports.
The leave path is wrong as well: it elects a new primary whenever any
member leaves, uses fls64(), which is one-based, as a port number, and
keeps the old primary when the last member leaves, so the next LAG with
that id starts without one.
Set every slot to -1 at probe, record the primary only after the
hardware join succeeded, and on leave elect a new primary only when the
primary itself leaves: the lowest remaining member, or -1 when the LAG
is empty.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Quinn O'Shea <qoshea@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25792
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
port_lag_leave looks the LAG up with dsa_lag_id(). DSA drops its
reference on the LAG before it notifies the switch, so when the last
port leaves, the LAG is already unmapped and the lookup returns -ENODEV.
Without this change, the leave is rejected as "LAG -19 invalid" and the
port stays a member of the hardware trunk. Addresses learned on it
afterwards are stored as trunk entries and frames for them are no
longer delivered, and the port cannot join a LAG again.
DSA passes the id in the notifier for exactly this reason. Use it in
port_lag_leave, and in port_lag_join for symmetry, and drop the check
for a return value dsa_lag_id() never had.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Quinn O'Shea <qoshea@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25792
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
TC functions currently use a mix of rtl83xx_ and rtldsa_ prefixes.
Use otto_tc_ for generic functions and otto_tc_930x_ or otto_tc_931x_
for device-specific functions to make TC module ownership explicit.
Remove redundant tc components from the remaining function names.
Update all declarations, call sites, callback assignments and
function references in comments accordingly.
Assisted-by: ChatGPT (OpenAI GPT-6 Astra)
Link: https://github.com/openwrt/openwrt/pull/25790
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
There is a similar race condition in rtl8214fc_media_set() as in
rtl8214fc_power_set(). It changes the base PHY's page registers in
separate MDIO bus lock sections, so another port can see the internal
page in between and restore it.
This fix holds the MDIO bus lock for the whole page-select sequence in
rtl8214fc_media_set().
Signed-off-by: Harm Kroon <hhhkroon@hotmail.com>
Link: https://github.com/openwrt/openwrt/pull/25766
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
There is a race condition in rtl8214fc_power_set(). It reads the
extended page register (reg 30) with __phy_read() without the MDIO bus
lock. Port 0 of the RTL8214FC is the base PHY. The other ports
poll __rtl8214fc_media_is_fibre(), which sets the base PHY's reg 30 to 8
(INTERNAL) for a short time. If port 0 reads in that window, it
"restores" page 8 and stays there. Its standard registers then point to
the internal page, so no link is seen. Every later power cycle reads 8
and writes 8 again.
This fix holds the MDIO bus lock for the whole page-select sequence in
rtl8214fc_power_set().
Signed-off-by: Harm Kroon <hhhkroon@hotmail.com>
Link: https://github.com/openwrt/openwrt/pull/25766
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
A PIE rule on RTL839x counts the packets it matches into the counter
named by its LOG_IDX field, bits 80:70 of the entry (Realtek GPL SDK,
rtk_cypress_tableField_list.c), which are bits 16:6 of r[14]. The
writer puts the index at bits 14:4, so the hardware reads it divided
by four, and bit 0 of the index lands in MIR_IDX.
The reader shifts the same way, so the route dump in debugfs reads the
counter the driver allocated rather than the one the hardware fills.
Write and read the index at bit 6.
Tested on an HPE 1920-48G (RTL8393) with two offloaded routes, which
got packet counters 0 and 1, and 8 echo requests through one route at
a time. Before, the requests through the second route added 8 to the
first route's counter and nothing to its own. After, each route's
counter grew by 8 for its own requests and stayed put for the other's.
Counters above 1 were not exercised.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25795
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
What an RTL839x does with a routed IPv4 packet whose TTL runs out is
set by the IP4_TTL_EXECEED field of ROUTING_EXCPT_CTRL, and nothing in
the driver writes that register. On main, #25768 found that an echo
request with TTL 1 through an offloaded route got no Time Exceeded
from the switch, and nothing reached the gateway either.
Set the field to trap, so that the CPU gets the packet and the kernel
answers it as it would on a route it forwards itself. The encoding,
0 drop, 1 forward, 2 trap, is the one of the Realtek GPL SDK
(dal_cypress_trap.c). The other fields of the register keep their
value.
Tested on an HPE 1920-48G (RTL8393), with 10.99.1.0/24 offloaded
through a gateway behind the client's own port and 8 echo requests
with TTL 1 per case, in one boot. With the field at 2, the client got
7 Time Exceeded replies, consistent with the kernel's ICMP rate limit,
and none of the requests reached the gateway. With the field forced
to 0 through devmem, the client got no reply and nothing reached the
gateway, the symptom #25768 reported on main. Echo requests with the
default TTL still reached the gateway 8/8, TTL 63, with IPv4
forwarding off.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25794
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
rtldsa_port_fdb_dump() calls cond_resched() every 64 rows, but at the
end of the loop, after the "continue" that skips each row that is not
a valid unicast entry. So it only reschedules when such a 64th row
happens to hold a valid unicast entry.
DSA calls the function once per port. On the 52-port HPE 1920-48G
(RTL8393) a full "bridge fdb show" walks the 16384 rows 52 times:
96 ms per port, 5.0 s in all. With PREEMPT_NONE no other task runs
on that CPU meanwhile. When the kernel's watchdog worker, which
toggles the board's external PT7A7514, waits on that CPU, it misses
its pings and the board resets during the dump, without any console
output.
Move cond_resched() to the top of the loop, as the L3 debugfs dumps
already do, so it runs every 64 rows whatever the row holds.
Tested on the HPE 1920-48G under ping load, with full dumps. Without
this change and the dump pinned to CPU0, 20 of 20 dumps completed
with the watchdog worker on CPU1; moved to CPU0 in the same boot, the
board reset on the first dump. With this change, 20 of 20 completed
with both on CPU0, 20 of 20 with CPU1 kept busy and 20 of 20 with
nothing pinned. Across those 60 dumps no two toggles of the watchdog
GPIO were more than 0.51 s apart. Not tested on other families.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25787
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The port counters hold the multicast and broadcast frame counts, and
the frame totals are already built from them, but the fields that
report them on their own are never assigned. ethtool leaves the
multicast and broadcast members of the standard MAC statistics out, and
the multicast member of the link statistics reads zero.
Assign them from the counters that are already collected.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Quinn O'Shea <qoshea@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25756
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
On RTL839x the ethernet driver turns on the L2 notification engine and
passes its learn and age events to the bridge. It reports them against
the conduit, which is not a bridge port, so br_switchdev_event() drops
every one of them. Nothing else reads them. RTL838x, RTL930x and
RTL931x run without this code.
Drop the notification setup, its interrupt handling and ring, and the
NIC reset code that preserved them. The vendor SDK defines no
interrupt in the mask bits this code also set on the other families:
bits 20-22 of DMA_IF_INTR_MSK on RTL838x, bits 4-6 of
DMA_IF_INTR_TX_DONE_MSK on RTL930x and RTL931x.
Tested on an HPE 1920-48G (RTL8393):
- after boot, L2_NOTIFICATION_CTRL reads 0x00001002 (engine off) and
DMA_IF_INTR_MSK has none of bits 20-22 set;
- the switch still learns the hosts behind its ports;
- a route offloaded with IPv4 forwarding off still delivers 8 of 8
echoes.
This does not stop the resets on a full bridge fdb show on that switch:
they happen with or without this code.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25776
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
An RTL839x has no L3 tables to dump. It routes through PIE rules that
match the destination prefix and forward to the L2 entry of the
gateway, and that entry names the ROUTING table row holding the gateway
MAC. Add realtek_otto_l3/routes for it: it walks the PIE rules and
shows each routing one with its L2 entry, its ROUTING row and its
packet counter.
The setup of the debugfs directory moves into a helper that both
families share.
Tested on an HPE 1920-48G (RTL8393) with 10.99.0.0/16 via one host
and 10.99.5.0/24 via another:
- both rows show the gateway's MAC in the L2 entry and in the ROUTING
row, on the port that host is behind;
- 8 echoes into each prefix raise the counter of the rule that matched
by 8;
- the counters show the /16 rule, installed first, matching 10.99.5.x
as well, and captures saw all 8 of those echoes at the /16 gateway;
- after deleting the /24 route, only the /16 row is left.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25775
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
rtl839x_pie_rule_read() does not read back what rtl839x_pie_rule_write()
writes:
- it takes the forward action, and the drop, from r[14], while the
writer puts them in the low bits of r[13];
- it never reads the forward and log data;
- it reads the masks of the templated fields word aligned, while the
writer puts them 8 bits up;
- it puts the two halves of the destination address in the wrong
order and builds the mask from the address.
Read all of these back from where the writer puts them. The hardware
follows the writer: the routes it programs on an HPE 1920-48G (RTL8393)
forward to their next hop.
Nothing reads a PIE rule back on RTL839x yet, so this changes no
behaviour. The RTL839x L3 debugfs added next uses it.
Checked on that switch through the debugfs dump of the next commit:
- the rules of 10.99.0.0/16 and 10.99.5.0/24 read back as these
prefixes, with the L2 index of their gateway;
- their raw words hold forward action 6 in the low bits of r[13];
- their masks sit 8 bits up, as written.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25775
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The firmware images of Layerscape boards booting from QSPI, e.g. the
LS1046A-FRWY, differ between builds in 4 bytes at the end of the PBL:
-00009e80: 019f 1e98 0000 0000 0000 0000 0000 0000
+00009e80: e10f e4a8 0000 0000 0000 0000 0000 0000
byte_swap pads the PBL to a multiple of 8 bytes from a 4 byte variable,
so fwrite() reads up to 4 bytes of the stack past it, and an aligned
PBL always gets 8 bytes appended, 4 of them random.
Add a patch that pads with an 8 byte buffer of zeros. The output keeps
its length and layout: for an aligned input only the 4 former random
bytes become zeros, an unaligned input gives the same output as before.
Link: https://github.com/openwrt/openwrt/pull/25720
Signed-off-by: Paul Spooren <mail@aparcar.org>
libopenssl3 differs between builds depending on the environment of the
build host, e.g. in the images of the Turris Omnia:
-compiler: arm-openwrt-linux-muslgnueabi-gcc -fPIC -pthread -Os ...
+compiler: arm-openwrt-linux-muslgnueabi-gcc -fPIC -pthread -Wa,--noexecstack -Os ...
- GNU_STACK ... RWE 0x10
+ GNU_STACK ... RW 0x10
Configure probes whether the assembler supports --noexecstack by running
$CROSS_COMPILE$CC, with CC taken from the environment. A host which sets
CC to select its compiler, e.g. CC=gcc-13, makes it run
arm-openwrt-linux-muslgnueabi-gcc-13, which does not exist, so the flag
is silently dropped and libcrypto ends up with an executable stack.
Pass CC=gcc to Configure, so that it always probes the cross compiler.
With CC=gcc-13 in the environment, the configuration now gets
-Wa,--noexecstack like a build without CC set.
Link: https://github.com/openwrt/openwrt/pull/25719
Signed-off-by: Paul Spooren <mail@aparcar.org>
The ports list only full duplex in their MAC capabilities, so the PHY
advertises no half-duplex mode. A link partner with autonegotiation off
is found by parallel detection, which resolves to half duplex, and the
port does not link.
Add MAC_10HD and MAC_100HD to ports 1-6. The GMAC programs half duplex;
USXGMII runs on the XGMAC, which has no duplex setting, so
mac_get_caps() removes both modes for that interface.
On a Xiaomi AX3600 (QCA8075) with the partner forced to 10 or 100 Mbps,
the port stays down before the change and links at half duplex after
it, 3/3 runs each.
Closes: https://github.com/openwrt/openwrt/issues/25657
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Link: https://github.com/openwrt/openwrt/pull/25750
Signed-off-by: Robert Marko <robimarko@gmail.com>
On the PSGMII instance (UNIPHY0 on IPQ8074 and IPQ6018), SGMII and
1000BASE-X run with every mode select bit of UNIPHY_MODE_CTRL clear, as
qca-ssdk's __adpt_hppe_uniphy_sgmii_mode_set() programs it. The driver
sets UNIPHY_SGMII_MODE there instead, and the Zyxel NWA110AX, whose
AR8033 sits on UNIPHY0 channel 0, transmits nothing.
Leave the mode select clear on the instance with a clock pair per
channel, and report 125 MHz for that setting in the clock recalc.
Writing 0x20 or 0x21 to the register on the NWA110AX restores TX.
Closes: https://github.com/openwrt/openwrt/issues/25657
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Link: https://github.com/openwrt/openwrt/pull/25750
Signed-off-by: Robert Marko <robimarko@gmail.com>
The RTL839x applies a port's isolation mask to every frame that came in
on it, routed ones included. The driver leaves the port out of its own
mask, so a route offloaded through a gateway behind the port a packet
came in on, such as routing between two VLANs of one trunk, drops
everything: the kernel shows the route as offloaded, and the drop
counter PORT_ISOLATION counts each packet.
Keep the port in its own mask, as the GPL SDK does at init
(_dal_cypress_port_init_config() sets every port's mask to all ports).
A broadcast is still not sent back out of the port it came in on. Only
RTL839x changes; the other families keep their masks as they are.
Tested on an HPE 1920-48G (RTL8393), with 10.99.1.0/24 routed from VLAN
7 to a gateway on VLAN 3, both behind lan48. On main, 0/8 echo requests
reached the gateway, even with IPv4 forwarding on in the kernel. With
this change and forwarding off, so that only the hardware path delivers,
8/8 arrived, TTL 63, from the switch MAC. Routing to a gateway behind
lan47 still delivers 8/8. Two bursts of 50 broadcasts entering lan48
added nothing to its tx_BroadcastPkts, while the same entering lan47
added 50 and 53.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25764
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
otto_l3_839x_setup_port_macs() fills the RTL839x routing source MAC
table with the switch MAC plus one, plus two and so on, a leftover
marked "BUG: VRRP for testing". A route only ever names entry 0, since
switch_mac_id is never set, so every frame the switch routes in
hardware leaves with the switch MAC plus one, a MAC that no interface
of the switch has.
Write the switch MAC as it is. That is what the GPL SDK puts in entry 0
when it sets the switch MAC (dal_cypress_switch_mgmtMacAddr_set(),
"Patch: Set router mac entry 0").
Tested on an HPE 1920-48G (RTL8393), with 10.99.1.0/24 routed between
VLAN 7 on lan48 and a gateway on VLAN 3 on lan47, and IPv4 forwarding
off in the kernel so that only the hardware path delivers. On main, 8/8
echo requests reached the gateway with the switch MAC plus one in the
last byte as their source. With this change, 8/8 arrived with the switch
MAC.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25759
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The Lianguo LG-SWTGW3C8F is an eight-port SFP+ managed switch based on
the Realtek RTL9303. It is the same vendor board as the Horaco
ZX-SWTGW2C8F and the GoodTop GT-SWTXG8FM (boardmodel RTL9303_8XGE in
the U-Boot environment) and uses the Horaco device tree unchanged.
Device specification:
- SoC: Realtek RTL9303
- RAM: 128 MiB DDR3, Winbond W631GG6KB-12
- Flash: 16 MiB SPI NOR, Winbond W25Q128
- Ethernet: 8x SFP+ cages
- Button: reset, GPIO 5 active-low
- System LED: GPIO 0
- Console: RJ45 RS-232 port, 115200 8N1
- Power input: 12 V DC
- Bootloader: Realtek U-Boot 2011.12 (1.0.0.2)
- Vendor firmware: KT-NOS 1.1.1.30
- Vendor board model: RTL9303_8XGE
The flash layout is the Horaco's. The MAC address is read from ethaddr
in BDINFO through NVMEM. The vendor firmware and bootloader use the
uImage magic 0x83800000, like the Horaco.
Installation from the vendor web interface:
1. Open Management -> Firmware -> Manual Upgrade.
2. Select the action Upgrade and the method HTTP.
3. Upload the squashfs-factory.bix image.
4. Wait for "Upgrade Image Done", then reboot the switch.
Installation over the serial console:
1. Put the initramfs-kernel.bin image on a TFTP server that is reached
through one of the SFP+ cages. The cages are switch ports 0, 8, 16,
20, 24, 25, 26 and 27; the commands below use the eighth one.
2. Stop the bootloader with ESC at the autoboot prompt and enter:
rtk network on
rtk ext-devInit 0
rtk 10g 27 fiber10g
setenv ipaddr <address of the switch>
setenv serverip <address of the TFTP server>
tftpboot 0x84f00000 <name of the initramfs image>
bootm 0x84f00000
3. Write the squashfs-sysupgrade.bin image with sysupgrade from the
running system.
Return to the vendor firmware: with a backup of the 12 MiB firmware
partition taken before OpenWrt was installed, copy it to
/tmp/RUNTIME.bin under OpenWrt and write it back:
mtd -f write /tmp/RUNTIME.bin firmware
mtd verify /tmp/RUNTIME.bin firmware
Tested on hardware: both installation routes, sysupgrade, the return
to the vendor firmware, the MAC address, a 10G link over a DAC in each
of the eight cages and a 1G link over fibre, each with its port LED
(blue at 10G, green at 1G), the system LED and the reset button. With
an SR module and no fibre the port reports loss of signal, and the
laser goes off when the port is set down. A 2.5G link over fibre came
up as well, with a local SFP quirk for the module that is not part of
this change.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Quinn O'Shea <qoshea@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25715
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
LAG helpers use inconsistent prefixes and placement of the lag component.
Use otto_lag_ for generic functions and otto_lag_<family>_ for device
and family helpers, retaining 83xx and 93xx for shared implementations.
Remove redundant lag components so each function name contains lag once.
Update all declarations, call sites, callback assignments and the
outdated function reference in a comment.
No functional changes intended.
Assisted-by: ChatGPT (OpenAI GPT-6 Astra)
Link: https://github.com/openwrt/openwrt/pull/25755
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
With more than one IPv6 table, the kernel also looks the local table up
before main, so a local IPv6 prefix (AnyIP: ip -6 route add local ...
table local) takes the destinations of a longer main route inside it.
The switch matches the longest prefix and forwards them. Commit
bf54d898c7 ("realtek: l3: trap main routes inside a local prefix") made
such a route trap for IPv4 only.
otto_l3_local_covers() now looks at local prefixes of both families. So
that a local prefix that comes or goes is seen for IPv6 too,
otto_l3_route_inside(), otto_l3_gw_seen() and
otto_l3_local_prefix_check() take the struct fib_notifier_info both
notifier infos start with, and tell the family from it. The IPv6 FIB
work calls otto_l3_local_prefix_check() after an add or a delete, and
the check no longer skips a prefix of length zero: otto_l3_fib_trap_v6()
gives a local ::/0 a row, which otto_l3_local_covers() counts as
covering every main route. An IPv4 local default route gets no row from
otto_l3_fib_trap_v4(), so for it the check only resolves the gateways
again and every route stays as it was. Without IPV6_MULTIPLE_TABLES the
local routes are in main, where the kernel matches the longest prefix
as the switch does, and they are not taken for local ones. Otherwise
IPv4 behaves as before.
Tested on a Hasivo S1100W-8XGT-SE (RTL9303), with 2001:db8:1:0:1::/80
via a gateway on switch.3 and echo requests to eight addresses inside
it captured at the gateway. With ip -6 route add local 2001:db8:1::/64
dev lo table local, main kept the row forwarding and all 8/8 reached the
gateway, whether the local prefix came before or after the route. With
this change the row traps and 0/8 reach it, in both orders. Without the
local prefix both forward 8/8. The same run of the IPv4 case traps on
both, as before. That run predates the zero-length part. In a run of
the final change, a local ::/0 made the row trap with 0/8 reaching the
gateway, and once it went the row forwarded 8/8 again.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25753
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
A route's egress interface carries the source MAC that routed frames go
out with, taken from the route's device when the route is added. When
the device then takes a new MAC, NETDEV_CHANGEADDR updates the router
MAC table, but the routes already through it keep their interface, and
hardware-forwarded frames keep leaving with the old source MAC. That
breaks anything that filters on it.
On NETDEV_CHANGEADDR, give every route out of the device the new MAC.
An egress interface that only routes out of the device takes it in
place, which needs no free interface. Otherwise the route moves to an
interface with the new MAC, through the same refcount, and the next hop
it has programmed is pointed at it before the old interface is let go;
if no interface is left, the log says once that they keep the old MAC.
This runs on the queue that the neighbour work runs on, since that work
writes the same next hops, and under RTNL, as the FIB work does. A
device left with no valid MAC (a bridge with no port) keeps its routes
as they are until it gets one back. Only a family with a router MAC
table has the notifier.
Tested on a Hasivo S1100W-8XGT-SE (RTL9303): with 10.99.87.0/24
forwarding through switch.3, switch.3 took a new MAC. On main the routed
echo requests kept arriving with the old source MAC (8/8); with this
change they came with the new one (8/8).
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25739
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Move the netdevice notifier below the egress interface helpers, so that
the next commit can call them from it without a forward declaration.
This is a pure move, with no functional change.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25739
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
A row move that fails partway, or a lookup that times out, leaves the
prefix rows no longer where the route list says, which prefix_rows_stale
records. Placing stops there, but a route that already has a row is
still written there when a neighbour update, a trap or the policy rules
change it, and that row may hold another route by now: the write
replaces a live route.
Once the rows are stale, a prefix route whose row no longer reads back
as it, checked with otto_l3_route_is_at(), is left as it is: both what
it says and its row. otto_l3_route_update_hw() and
otto_l3_route_trap_hw() pass it by, and so does otto_l3_rules_check()
when it suspends forwarding, so nothing is written over the other
route; resuming only asks for the gateway, and the update that follows
goes through otto_l3_route_update_hw(). A route whose row still reads
back as it is updated as before, route and row together, so its removal
still finds it. The two messages that mark the rows stale say "no
prefix route will be placed again" instead of "no route": host routes
still are. Nothing changes while the rows are not stale.
Compile-tested for rtl930x, rtl838x and rtl839x. The stale state needs a
table engine timeout, which was not reproduced, so this path was not
exercised on hardware. An earlier form of this change, which left every
placed prefix route alone, passed the route offload regression run for
the earlier L3 changes (46/46) on an RTL9303 build carrying the other
fixes from issue 25731.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25738
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
otto_l3_route_is_at() decides whether a row still holds a route, and
among other fields it compares the row's action with the route's. The
action is what the route last asked for, not what tells the row apart:
when a write of the route does not land, such as a table write that
times out after the route already says trap or forward, the row keeps
the old action and is taken for another route. Removing the route then
logs "row %d holds another route" and leaves the row valid in hardware.
The next hop index already tells two routes for one destination apart.
A route that forwards carries its own id; two routes share one only
when neither gateway has resolved, and then both trap. Drop the action
from the comparison.
Compile-tested for rtl930x, rtl838x and rtl839x. A write that does not
land needs a table engine timeout, which was not reproduced. Where the
write lands, the row's action and the route's are the same, so nothing
changes there.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25738
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Move otto_l3_route_is_at() above the code that writes routes, so that
the next commit can use it there without a forward declaration. This is
a pure move, with no functional change.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25738
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The gen2 and later Aquantia PHYs take their system interface from the
per-speed global configuration words their firmware loads from flash.
Where the board firmware selects XFI with pause-frame rate adaptation,
the driver reports 10GBASE-R as the only possible interface and the MAC
gets throttled by pause frames at every media speed below 10G, although
the device tree asks for USXGMII.
Apart from being ugly, this also causes the PHY's microcontroller to
hang when ever a link-partner enters 100M mode (eg. during S3 idle with
WoL active) and never returns to a working state, observed on CUX3410
running firmware 5.7, ironically even with an Aquantia AQtion AQC107
NIC on the other end (ie. the inter-Aquantia magic between the two
same-vendor PHYs could be the actual root of the problem).
Add a hack patch that rewrites the words to XFI with USX rate
adaptation when phy-mode is usxgmii, with the PHY held in low power as
the existing AQR112/AQR412 patch does. The PHY then runs USXGMII with
symbol replication at the lower speeds (and no longer crashes when
ever the link-partner enters S3 and reduces speed to 100M).
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
On the Keenetic MT7981 boards the LAN port takes its MAC from rf-eeprom
0x4, and mt76 reads the same slot for phy0. The 2.4 GHz radio and the
LAN port therefore share one address. Found on a Keenetic KN-1012 while
writing down its MAC map: eth0, br-lan and phy0 all read
d4:9c:53:xx:xx:a1.
This is the phy0 side of the collision fixed for phy1 in commit
cc96ed1e6d ("mediatek: filogic: fix Keenetic phy1 MAC collision"). Give
phy0 the slot with the LA bit set. The userspace VIF allocator keeps bit
7 of the first octet, so the extra phy0 VIFs stay apart from phy1 and
its VIFs, which have bit 7 flipped, and from the ethernet addresses,
which have the LA bit clear. With num_global_macaddr set, the allocator
adds to the base instead, and phy0 + 1 was the WAN address wherever the
0xa slot holds the base + 1, as on the KN-1012; that goes away too. The
2.4 GHz BSSID of these boards changes accordingly. On KAP-630 and
NAP-630 the ethernet port uses the 0xa slot instead, so there it only
changes the BSSID, and the family keeps one 2.4 GHz addressing
convention.
The Buddy 6 and Buddy 6 SE extenders (KN-3411, KN-4410, NC-3411,
NC-4410) have the same collision on their single port: on an NC-4410,
phy0-ap0 came up with d4:9c:53:xx:xx:23, the address its LAN has. They
only need the phy0 part. Their 0xa slot is empty (zeros on that unit),
so mt76 already derives phy1 as the family fixup does, 56:9c:53:xx:xx:23
there.
Tested on the KN-1012: phy0 comes up as d6:9c:53:xx:xx:a1 and phy1 stays
56:9c:53:xx:xx:a1. The VIF allocator hands phy0 d2/de/da and phy1
52/5e/5a in the first octet, none of them equal to the LAN or WAN
address. With two APs on phy0 and one on phy1, all bridged into br-lan,
every bridge port has its own local address.
Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Link: https://github.com/openwrt/openwrt/pull/25450
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
The NXP patch that added PHY_INTERFACE_MODE_2500SGMII inserted it right
after 2500BASEX, so on layerscape every later mainline mode was shifted
by one. The mode is a synonym of 2500base-x without in-band
autonegotiation, kept for NXP device trees that say "sgmii-2500".
Drop the extra mode and parse that string as 2500BASEX instead. The
ppfe driver checks 2500BASEX where it checked 2500SGMII, and device
trees stay as they are.
Suggested-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Link: https://github.com/openwrt/openwrt/pull/25399
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
Because of a race condition in the USB driver, using the regulator with
two USB interfaces ends up failing on a reboot where a USB3 port ends up
with USB2 speeds. Fix the driver up.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/25472
Signed-off-by: Jonas Jelonek <jonas@jonasjelonek.de>
On RTL930x, the L2 entry of a next hop names the DMAC entry from which
routed frames take their destination MAC (the field that replaces the
VID), and the driver wrote that DMAC entry per route, at the route's id.
Routes through one gateway share its L2 entry, which keeps naming the id
of the route that claimed it first. When that route goes, another one
takes its id and writes its own gateway MAC there, and the routes still
going through the shared entry leave with that MAC.
Hold the DMAC entry per gateway MAC instead, refcounted by the routes
through it as the Realtek GPL SDK does (dal_longan_l3.c,
_dal_longan_l3_dmacEntry_alloc()), and have the L2 entry name it. An
entry that is already a next hop is pointed at it again on every claim,
as the SDK writes it on every add, so an entry that stayed a next hop
while its DMAC entry was given up does not keep naming it. A route holds
at most one DMAC entry, and the table has one for every route id; entry
0 stays unused, as before. An entry whose write fails is not taken, and
the route is left as it was. RTL838x and RTL839x still put the route id
in that field, as before, and allocate nothing.
Tested on a Hasivo S1100W-8XGT-SE (RTL9303) with a kprobe on
otto_table_write_bytes() logging the DMAC writes. 10.99.80.0/24 (A) and
10.99.81.0/24 (B) went through one gateway; A was deleted and
10.99.82.0/24 (C) added through another. On main, C took A's id and
wrote its own gateway MAC into the DMAC entry that the shared L2 entry
named, and echo requests routed through B fell from 8/8 to 0/8 at their
gateway. With this change that gateway's MAC was written once, to entry
1, which the L2 entry named; C's gateway got entry 2, and B still
delivered 8/8.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25736
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The kernel looks up the whole local table before main, so an IPv4 local
prefix shorter than a host address, which is what AnyIP sets up
(ip route add local 10.0.0.0/16 dev lo table local), takes every
destination in it, even one with a longer route in main. The switch
looks up the longest prefix, and the local row sorts ahead of main only
at the same length, so it forwards those destinations through the main
route instead of trapping them for local delivery.
Make a main IPv4 route inside such a local prefix trap instead of
forward. When the local prefix comes or goes, the main routes inside it
decide again through their gateway, as the policy rules bring a route
back: one whose gateway still answers forwards or traps as it now
should. Stock configurations have no such local prefix, and nothing
changes for them. An IPv6 local prefix is not handled; IPv6 local
addresses are /128.
Tested on a Hasivo S1100W-8XGT-SE (RTL9303): with 10.99.88.0/24
forwarding through a gateway, adding local 10.99.0.0/16 to the local
table left the row forwarding on main, and 8/8 echo requests reached the
gateway instead of being delivered locally. With this change the row
traps and none reach it; deleting the local prefix brings the row back
to forwarding, 8/8.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25740
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
otto_l3_930x_get_router_mac() reconstructs the MAC mask with data[4]
and data[5] reversed relative to the setter and hardware layout.
This turns a full 0xffffffffffff mask into 0xffff0000ffff on readback.
Use the lower 16 bits of data[4] as the upper mask bits and data[5]
as the lower 32 bits, excluding reserved bits from the result.
Assisted-by: ChatGPT (OpenAI GPT-6 Astra)
Link: https://github.com/openwrt/openwrt/pull/25735
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The FIB notifier follows only init_net, so every route the driver
offloads comes from there, but the netevent notifier takes neighbour
updates from every namespace. An ifindex is only unique within one
namespace, so a device over a switch port in another namespace, with the
same ifindex and gateway address as an offloaded route, can rewrite that
route's next hop or make it trap.
Drop neighbour events from devices outside init_net, as the router MAC
notifier already does. Nothing changes for neighbours in init_net.
Tested on a Hasivo S1100W-8XGT-SE (RTL9303): with 10.99.86.0/24
forwarding through 10.90.3.2 on switch.3, a VLAN device on lan6 was
created in another namespace with the ifindex of switch.3, and a
permanent neighbour 10.90.3.2 with another MAC was added there. On main
the route in init_net turned to trap ("no port for 10.90.3.2, routing
10.99.86.0/24 in software"); with this change it kept forwarding.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25737
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Move the four static L2 unicast reference helpers from common.c to l2.c.
Move their nexthop add/delete callers with them so that the helpers remain
private to the L2 translation unit.
Rename the six functions to the otto_l2_ naming scheme and update all
references, including the explanatory comment in l3.c. Move the public
nexthop declarations and their forward declaration to l2.h. Include l3.h
in l2.c for the existing nexthop structure, and include l2.h explicitly
at the L3 call sites.
Keep function signatures, bodies, reference accounting and locking
unchanged apart from symbol names and signature indentation. Diagnostics
using __func__ now report the new names.
Assisted-by: ChatGPT (OpenAI GPT-6 Astra)
Link: https://github.com/openwrt/openwrt/pull/25732
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Use otto_vlan_ for generic VLAN functions and otto_vlan_<family>_ for
RTL838x, RTL839x, RTL930x and RTL931x implementations. Keep a single
vlan component in each function name.
Make port-level operations explicit with port_, spell out forward_on_inner,
and separate pvid_mode for readability. Update declarations, direct calls
and callback assignments throughout the supplied driver.
This is a naming-only change; function signatures and behavior are
preserved, apart from the function names emitted by __func__ diagnostics.
Assisted-by: ChatGPT (OpenAI GPT-6 Astra)
Link: https://github.com/openwrt/openwrt/pull/25732
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The router MAC entries this driver writes, one for each MAC a route's
device has, were never given back, so a box whose interfaces take new
MACs or come and go runs out of them, 64 in all. A router MAC is what
makes the switch route what arrives on that MAC, so it belongs to the
devices that have the MAC rather than to the routes out of them.
Remember every device in the initial namespace found with the MAC of an
entry this driver wrote, the one a route gave it to and any other that
receives on it: the allocation looks for them, and so does a resync on
each NETDEV_REGISTER, NETDEV_CHANGEUPPER, NETDEV_CHANGEADDR and
NETDEV_UNREGISTER there. A port of a bridge, bond or team receives for
its master, so it is neither remembered nor counted while it has one.
While a remembered device exists, it keeps an entry for the MAC it has
now, whether routes still go out of it or ports are still under it, and
an entry none of them has the MAC of any more is written back invalid,
as the Realtek GPL SDK frees one (dal_longan_l3.c,
_dal_longan_l3_macEntry_free()). A device that changes its MAC takes its
entry along and gets it back when it returns, a bridge left with no port
and so no MAC gets one back with its first port, and a deleted device
gives its entry back unless another still has the MAC. The resync on
NETDEV_CHANGEUPPER frees nothing, as a port joining a bridge stops
counting before the bridge, which may take its MAC, sends its
NETDEV_CHANGEADDR. Were there more MACs in use than entries, nothing
would be freed and the log would say so. This runs under RTNL, as the
FIB work that allocates does. Only a family with a router MAC table
registers the notifier.
Tested on a Hasivo S1100W-8XGT-SE (RTL9303) with a kprobe on
otto_table_write_bytes() logging the writes to the router MAC table. On
main, switch.3 going to a new MAC and back, and a VLAN device with a MAC
of its own being deleted, write nothing; 70 rounds of a new MAC on
switch.3 with a /24 through it run out of entries after 61, so the last
9 routes get no row and the log has 9 "No free router MACs". With this
change switch.3 gets an entry for its new MAC as it changes and gives it
back when it returns to its own, the VLAN device's entry goes with the
device, an IPv6 bridge over lan6 keeps its entry after its gateway route
is deleted and lan6 leaves and rejoins it, and gives it back when it is
deleted. The entry a VLAN device on such a bridge gets through its IPv4
address stays when the VLAN device is deleted, as the bridge, with no
address of its own, still has the MAC; it follows the bridge to a new
MAC and back, and goes with the bridge. A port of that bridge taking its
MAC and then one of its own gets no entry. A standalone port that takes
the MAC of an entry keeps it once the bridge and the VLAN device it came
from are deleted, and still when it joins a bridge with no MAC set,
which takes that MAC. Joining a bridge with a MAC of its own, it gives
the entry back at the next resync, and gets it back on leaving. All 70
rounds get a row with no "No free" in the log.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25703
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Stock F1100W does not detect the MCU, and OpenWrt cannot arm its
watchdog. Disable the management I2C bus on non-PoE F1100W and
drop its unused MCU kmods. Re-enable the bus in the PoE DTSI
alongside the STC8 watchdog, sensor and PoE controller.
Signed-off-by: Oskari Lemmelä <oskari@lemmela.net>
Link: https://github.com/openwrt/openwrt/pull/25515
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Install OpenWrt on F1100W variants through the stock CLI without
booting an initramfs. Check board identity, partition sizes, image
hashes and U-Boot MAC before writing RUNTIME2 and RUNTIME. Correct
the stock partition layout comments.
Serve the generated archive over TFTP, then run at the stock CLI:
download patch <TFTP-IP> <generated-archive-name>
The stock CLI does not report progress and the switch will reboot
after successful flash. Process will take 4-5min to complete.
Signed-off-by: Oskari Lemmelä <oskari@lemmela.net>
Link: https://github.com/openwrt/openwrt/pull/25515
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
The PPPoA plugin only uses text2atm() and text2qos() from libatm. ppp
ships copies of both and uses them unless configured --with-atm, so
link the bundled copies and drop the dependency on linux-atm.
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
Link: https://github.com/openwrt/openwrt/pull/25707
Signed-off-by: Robert Marko <robimarko@gmail.com>
162f8985525f wifi: mt76: mt7925: don't put the band auto marker in TGID
047558e81f6b wifi: mt76: mt792x: fix UAF in SDIO TX path when out of memory
f3e7928585db wifi: mt76: fix memory leak in USB TX path
c50f17ec046e wifi: mt76: mt7603: initialize global station WCID
1297eb4e49fc wifi: mt76: mt7615: restore DBDC state after ext PHY failure
2009416d3f90 wifi: mt76: mt792x: treat 0xff ACPI SAR entries as no limit
7f30d9cb0d3e wifi: mt76: mt792x: pick the SAR table layout from the table itself
20f0979088b3 wifi: mt76: mt7915: publish wcid before MCU add commands
8f69e214f057 wifi: mt76: fix unlocked wcid check in mt76_tx_status_skb_add()
7ff2f295a629 wifi: mt76: fix wcid teardown ordering in mt76_reset_device()
7fec0ac4e12c wifi: mt76: connac2: fill TXD spe_idx for connac2 fixed-rate frames
5073b08ce0c4 wifi: mt76: take rcu_read_lock in the USB/SDIO tx completion path
d7675366ff03 wifi: mt76: mt7925: cancel mlo_pm_work on the USB stop path
bbde131e8f2c wifi: mt76: move the channel survey when the channel changes
9e96501e32e5 wifi: mt76: mt7996: fix uninitialized buf read in mt7996_variant_fem_init()
a2a78703435c wifi: mt76: mt7915: check default EEPROM firmware size before copying
56c8b4a4b407 wifi: mt76: mt7996: validate firmware event lengths before parsing
fee59a3f8bca wifi: mt76: mt7915: unregister thermal cooling device on hwmon failure
fd3dc2614c73 wifi: mt76: mt7915: guard firmware memory dump write on disabled memdump
40bd3ff75a69 wifi: mt76: mt7996: bound RRO session id before indexing addr_elem[]
27a48eed077f wifi: mt76: mt76x02: validate RX padding before use
17bfd775f483 wifi: mt76: mt7615: cancel reset work during unregister
c228f918e321 wifi: mt76: mt7925: keep MLD membership consistent during link add
c02187d15016 wifi: mt76: mt7928: makes struct beacon_tlv 4-byte aligned.
3318ff5daa93 wifi: mt76: mt7921: keep the join ROC until the station is authorized
fddc43d51481 wifi: mt76: mt7925: keep the join ROC until the station is authorized
790d1ae1e534 wifi: mt76: mt792x: defer the MCU shutdown past unregister on USB
4e819092f203 wifi: mt76: usb: fix source overread in mt76u_copy
be33bbd93f1a wifi: mt76: mt7615: usb: fix source overread in mt7663u_copy
a0a409c3091d wifi: mt76: mt7915: fix thermal zone use-after-free
a374cac12909 wifi: mt76: mt7603: don't drop short frames looped back on PS entry
210948383adf wifi: mt76: mt7996: refresh the tx BA session timer on NPU devices
9559d859e64e wifi: mt76: avoid iter_keys_rcu() where not needed
d17b8d5eff29 wifi: mt76: mt7996: validate TLV length in mt7996_mcu_ie_countdown()
e51abae4a28e wifi: mt76: Fix spelling mistake "dowload" -> "download"
ecc63ee35093 wifi: mt76: mt7996: Fix spelling mistake "retriving" -> "retrieving"
b1bc93f95379 wifi: mt76: fix wcid->pktid corruption in mt76_wcid_cleanup()
c4809c50393c wifi: mt76: mt7925: Remove useless condition
08dd35bb504c wifi: mt76: mt7615: read MT7663 temperature from the correct offset
b94b75e4edcf wifi: mt76: Fix of_node reference leak in mt76_get_rate_power_limits()
1c9854c4365a wifi: mt76: mt7615: validate MCU response lengths
6163958192b9 wifi: mt76: connac: pass the command to mt76_connac_mcu_chip_config()
2fe9842d4a5f wifi: mt76: mt7921: enable thermal protection
c7dba52baf55 wifi: mt76: mt7996: guard station-only MLO TX handling
d855630e62e2 wifi: mt76: mt792x: fix negative errno truncation in offload capability
175a9b92ff39 wifi: mt76: mt7996: fix PCI device reference leak in mt7996_pci_init_hif2()
0f7f2f6fd028 wifi: mt76: mt7925: fix reset panic caused by the WM2 rx irq mask
ed623597107c wifi: mt76: feed the station RSSI average from the chain signals
aa0868c8a105 wifi: mt76: mt7921: clear WM2 from MT7902 RX all_complete_mask
7adc7a8e8398 wifi: mt76: mt7925: Fix MCU command timeouts during module unload
42bd01d693c6 wifi: mt76: mt7925: add AXI DMA calibration cache for MT7928
b260b1861071 wifi: mt76: abort a scan only for a link change on the scanning radio
5a9b590919a6 wifi: mt76: mt7996: enable the SKU power limit table
490519f8fb53 wifi: mt76: mt7996: set sniffer mode on a radio that is already running
53c7bed27b21 wifi: mt76: mt7996: update the address of an AP link that is added again
bc69664723f9 wifi: mt76: mt7996: size the MLD setup TLV by the links it describes
45f8f94c7cf1 wifi: mt76: mt7996: find the last MLD link among the links torn down
39bd92a3a5d7 wifi: mt76: mt7996: upload only the keys of the link being set up
a2464b215715 wifi: mt76: mt7996: do not walk the vif keys when a link is destroyed
b0ce6b0d6143 wifi: mt76: mt7996: report station statistics from the primary link
f2d50d200941 wifi: mt76: mt7996: clear all link wcid entries in sta_pre_rcu_remove
e46d47df718d wifi: mt76: mt7996: free the WTBL index if a link allocation fails
3aa923dc58e2 wifi: mt76: mt7996: pick the secondary link from links with driver state
965aa0ec734c wifi: mt76: mt7996: make a returning link primary if a station has none
50193c8fba22 wifi: mt76: mt7996: do not reuse the deflink of a removed station link
cf73928ba1a5 wifi: mt76: mt7996: keep a returning link when adding station links fails
f06234e078fa wifi: mt76: mt7996: add the station BMC entry as new once per BSSID
df395b4054af wifi: mt76: mt7996: keep 4-address and decap state per station
f6bb3fab6315 wifi: mt76: mt7996: do not add a station link in disconnected state
6db96c229855 wifi: mt76: mt7996: record the connection state of a station
bfa293034c38 wifi: mt76: mt7996: keep the block ack session parameters per station
0ea35bbe67f7 wifi: mt76: mt7996: set up the BSS of a late station link before its peer
8fce9b01ca98 wifi: mt76: mt7996: bring up station links added after association
42f455d1c817 wifi: mt76: mt7996: set up block ack sessions on station links added later
9ff341e9c17e wifi: mt76: mt7996: restore a station link that returns after a removal
8d6bbe90bedf wifi: mt76: mt7996: fix PLE free page and AC queue register offsets
8d0f3dbd4708 wifi: mt76: mt7996: fix the hw-queues debugfs queue requests
d39a5b53249c wifi: mt76: mt7996: disable the RX NAPIs before the DMA cleanup
dbdcc627e24c wifi: mt76: mt7996: keep the airtime weight of a station for HW ATF
d5ead84240fe wifi: mt76: mt7996: refuse scan and ROC until the hardware restart is done
960c1a94baf5 wifi: mt76: report an aborted scan or ROC to mac80211 during a reset
f6dbd94a444c wifi: mt76: mt7921: fix of_node reference leaks in regd update
b68c3cb175e6 wifi: mt76: mt792x: compute the assoc RSSI from the chain signals
0f37e419a340 wifi: mt76: remove the unused signal field from struct mt76_rx_status
bd5d316e5604 wifi: mt76: mt7996: take the offchannel link of a frame from its wcid
44625d0665e7 wifi: mt76: scan all radios of a request at the same time
65dce9c22385 wifi: mt76: mt7996: scan all bands with one request
d80e427a17db wifi: mt76: keep beacons from queueing the scan work during an abort
467ae2e3f190 wifi: mt76: bypass DPD on a scan channel while a monitor is active
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The spatial reuse settings that a radio runs with were not visible at
runtime: get_status did not report them, and nl80211 does not carry
them. A radio with he_spr_sr_control=3 could not be told apart from an
unrestricted one.
get_status now adds, beside the BSS Color fields, at the top level and
in each entry of the links of an AP MLD, the running values of the
radio's configuration:
- he_spr_sr_control, he_spr_non_srg_obss_pd_max_offset,
he_spr_srg_obss_pd_min_offset and he_spr_srg_obss_pd_max_offset, as
numbers;
- he_spr_srg_bss_colors and he_spr_srg_partial_bssid, as the bitmap
value with bit n for colour or partial BSSID n (IEEE Std 802.11-2024
9.4.2.251), in 16 lowercase hex digits. The element holds the value
little-endian; a ubus integer is signed, and colour 63 is bit 63.
he_spr_srg_bss_colors=7 8 reads "0000000000000180".
Signed-off-by: Felix Fietkau <nbd@nbd.name>
When several stations match addr2 of a data frame, a failed link lookup
for one station kept every station after it from getting the frame.
Also, the link_id of an MLO station leaked to the stations after it,
which dropped the frame for a non-MLO station.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
On an EHT BSS or an AP MLD with sae, psk3, sae-mixed or psk3-mixed, the
RSNE Override 2 element carries SAE-EXT-KEY and GCMP-256 (CCMP without
phy support). An explicit sae_ext_key 1 and gcmp256 1 also put both
items into the RSNE, and the element stayed as a duplicate.
A configuration that asks for an RSNE with AKM 24 and GCMP-256 and an
RSNXE only sets sae_ext_key 1 and gcmp256 1. The Beacon then had an
RSNO2E and an RSNXOE in addition.
A duplicate RSNO2E adds nothing. A client sees both items in the RSNE,
and the RSNE meets WPA3 Specification v3.5 2.5 items 4 and 5.
Build the element only when the RSNE lacks its AKM or its pairwise
cipher. Without an RSNO2E, hostapd writes no RSNXOE either
(wpa_auth_gen_wpa_ie()). The default keeps the element as before, with
the client fixes of commits fc652db52a and 5e067465ff, and so does a
BSS with one of the two options. One exception: without phy support for
GCMP-256, the element carries SAE-EXT-KEY and CCMP, which an RSNE with
sae_ext_key 1 already offers, so that BSS sends no element. 0 still
keeps an item out of both elements. sae-compat keeps its own elements.
On an AP MLD, the decision covers all links (ap.uc mld_rsno2()): WPA3
Specification v3.5 14.2 requires an identical RSNE Override 2 element
on all links of an AP MLD that uses RSN overriding. The element goes
only where the RSNE of every link offers both items. A psk2 or
psk-mixed AP MLD has PSK in the RSNE of its 2.4 and 5 GHz links, so all
its links keep the element, also the 6 GHz link, whose RSNE has SAE. An
AP MLD of sae whose RSNE has both items on every link uses no RSN
overriding. IEEE 802.11be-2024 12.6.2 then requires the same RSNE on
every link except the AKM list and MFPR, and one common AKM. The links
share SAE and SAE-EXT-KEY, also on a 6 GHz link.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
The DEFAULT_INCLUDES override adds -I. to the src directory. There,
upstream deliberately clears DEFAULT_INCLUDES: with libc++, <format>
includes <stack>, which then resolves to the stack binary in src.
Leave out -I. for the src directory.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
iface_restart() aborts the pending setup of a phy before it removes the
interface, but iface_config_remove() does not. A config_set without
interfaces, the shutdown and the removal of the last link of an AP MLD
left the setup pending, and its wpa_supplicant reply later added an
interface for a configuration that no longer exists.
Abort the pending setup in iface_config_remove() as well.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
When nl80211_setup_ap() fails in wpa_driver_nl80211_if_add(), the new
i802_bss stays linked into the driver and in *drv_priv. For an AP MLD
BSS, the caller's cleanup then runs driver_nl80211_link_remove() on
that BSS, which reports EVENT_MLD_INTERFACE_FREED with a NULL context,
and hostapd crashes in hostapd_wpa_event(). A failure of
nl80211_set_mode() leaks the BSS.
198-nl80211-undo-a-failed-ap-bss-add undoes the add on both failures,
as the other error paths of the function do. Upstream hostap has the
same code.
Signed-off-by: Felix Fietkau <nbd@nbd.name>