Commit Graph
539 Commits
Author SHA1 Message Date
Felix Fietkau 044081b202 wifi: mt76: mt7996: program a link we already hold again
The firmware wants active links removed from the BSSINFO table as the interface
is destroyed, so a link stays registered from its first chanctx assignment until
the interface goes away, and adding one the driver already holds does nothing.
mac80211 hands a non-AP MLD a fresh address whenever it sets a link up, though,
so a link coming back after a failed attempt carries an address the hardware was
never told about, on a BSS that was never revisited: it authenticates from an
address nothing answers, every time, until the interface is torn down for good.

Program the address and the BSS again, the pair the initial add sets up, which
is for a station what mt7996_mcu_mld_link_oper() does for an AP.

Signed-off-by: Felix Fietkau <[email protected]>
2026-08-04 11:40:37 +02:00
Sriram RandFelix Fietkau 4ad4e6a6dc wifi: mac80211: fetch FILS discovery template by link ID
Currently, the FILS discovery template is always fetched from the default
link of a virtual interface in both Multi-Link Operation (MLO) and
non-MLO cases. However, in the MLO case there is a need to fetch the FILS
discovery template from a specific link instead of the default link.

Hence, add support for fetching the FILS discovery template based on the
link ID from the corresponding link data.

Signed-off-by: Sriram R <[email protected]>
Co-developed-by: Raj Kumar Bhagat <[email protected]>
Signed-off-by: Raj Kumar Bhagat <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Johannes Berg <[email protected]>
2026-08-03 18:27:36 +02:00
Sriram RandFelix Fietkau ffeb5d8e16 wifi: mac80211: fetch unsolicited probe response template by link ID
Currently, the unsolicited probe response template is always fetched from
the default link of a virtual interface in both Multi-Link Operation (MLO)
and non-MLO cases. However, in the MLO case there is a need to fetch the
unsolicited probe response template from a specific link instead of the
default link.

Hence, add support for fetching the unsolicited probe response template
based on the link ID from the corresponding link data.

Signed-off-by: Sriram R <[email protected]>
Co-developed-by: Raj Kumar Bhagat <[email protected]>
Signed-off-by: Raj Kumar Bhagat <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Johannes Berg <[email protected]>
2026-08-03 17:52:58 +02:00
Johannes BergandFelix Fietkau 6ff9f07cdd wifi: move action code from per-type frame structs
The action code actually serves to identify the type of action
frame, so it really isn't part of the per-type structure. Pull
it out and have it in the general action frame format.

In theory, whether or not the action code is present in this
way is up to each category, but all categories that are defined
right now all have that value.

While at it, and since this change requires changing all users,
remove the 'u' and make it an anonymous union in this case, so
that all code using this changes.

Change IEEE80211_MIN_ACTION_SIZE to take an argument which says
how much of the frame is needed, e.g. category, action_code or
the specific frame type that's defined in the union. Again this
also ensures that all code is updated.

In some cases, fix bugs where the SKB length was checked after
having accessed beyond the checked length, in particular in FTM
code, e.g. ieee80211_is_ftm().

Link: https://patch.msgid.link/20260226183607.67e71846b59e.I9a24328e3ffcaae179466a935f1c3345029f9961@changeid
Signed-off-by: Johannes Berg <[email protected]>
2026-08-03 17:52:28 +02:00
Jose Ignacio Tornos MartinezandFelix Fietkau 3ad249ed8d wifi: mt76: mt7996: remove beacon_int_min_gcd from ADHOC interface combinations
The driver fails to register with error -22 (EINVAL) due to a cfg80211
validation failure in wiphy_verify_iface_combinations().

Commit 5ef0e8e2653b ("wifi: mt76: mt7996: fix iface combination for
different chipsets") added beacon_int_min_gcd to if_comb_global and
if_comb_global_7992, but these combinations include ADHOC (IBSS)
interface type. This violates a cfg80211 rule from commit 56271da29c52
("cfg80211: disallow beacon_int_min_gcd with IBSS") that explicitly
forbids combining ADHOC with beacon_int_min_gcd.

The restriction exists because beacon_int_min_gcd requires static,
predictable beacon intervals to coordinate multiple beaconing interfaces,
but ADHOC interfaces have dynamic beacon intervals that change when
joining different networks, making the GCD constraint unenforceable.

Remove beacon_int_min_gcd from the interface combinations that include
ADHOC because they are not necessary for ADHOC operation. The if_comb
combination (AP/MESH/STA only, without ADHOC) correctly retains
beacon_int_min_gcd for multi-AP coordination.

Fixes: 5ef0e8e2653b ("wifi: mt76: mt7996: fix iface combination for different chipsets")
Signed-off-by: Jose Ignacio Tornos Martinez <[email protected]>
Tested-by: Alex Gavin <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 19:56:12 +02:00
Felix Fietkau 20d1568e2d wifi: mt76: mt7996: do not leave state behind after a failed WED attach
mt7996_mmio_wed_init() set dev->mt76.hwrro_mode and rx_token_size while
building the WED configuration, before knowing whether the WED attach
can succeed. A failed attach left the enlarged rx_token_size behind and
reset hwrro_mode to MT76_HWRRO_OFF, clobbering the values that another
RX datapath owner may have configured earlier in probe: on Airoha
platforms with the wed_enable module parameter set, this broke the NPU
offload configuration set up by mt76_npu_init() (NPU offload requires
HW-RRO and a larger rx token space, and the attach always fails there
since no SoC has both an Airoha NPU and MTK WED).

Move both assignments after a successful attach, next to the existing
success-only dma_dev/irq assignments. This is safe for the regular WED
attach case: the first consumer of either field runs after probe
continues (mtk_wed_device_attach() only invokes the init_buf callback;
rx buffers are allocated via init_rx_buf from mtk_wed_start(), long
after mt7996_mmio_wed_init() has returned).

Within the WED configuration the HW-RRO checks were constant: the mode
was assigned unconditionally right before them, and the hif2 path is
only reachable after a successful main attach has set it. Resolve them
to their constant values and drop the dead branches.

Fixes: 377aa17d2aed ("wifi: mt76: mt7996: Add NPU offload support to MT7996 driver")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Howard HsuandFelix Fietkau f723115440 wifi: mt76: mt7996: reject iTWT setup requests from MLD stations
The firmware does not support individual TWT agreements with non-AP MLDs,
and the driver only tracks TWT flow state on the default link, which may
not be the link the agreement was negotiated on. Reject TWT setup
requests from MLD stations instead of programming an unsupported
configuration.

Signed-off-by: Howard Hsu <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
StanleyYP WangandFelix Fietkau 95c614cc6b wifi: mt76: mt7996: remove repeater muar config
Repeater mode is not supported currently, so remove it.
get_omac_idx() only hands out HW_BSSID/EXT_BSSID indices, so the
omac_idx >= REPEATER_BSSID_START call sites are unreachable.

Signed-off-by: StanleyYP Wang <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
StanleyYP WangandFelix Fietkau f3541c1fc3 wifi: mt76: mt7996: add scan dwell time hw cap
Add NL80211_EXT_FEATURE_SET_SCAN_DWELL support in driver.
This allows user to specify channel dwell time during scanning.

Signed-off-by: StanleyYP Wang <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Felix Fietkau fa98398ec4 wifi: mt76: mt7996: do not attach hif2 WED when the main WED attach failed
If the WED attach for the primary PCIe function fails, the probe path
still attached wed_hif2 for the secondary function, leaving the device
in an inconsistent half-WED configuration that crashes later. The hif2
call also re-enabled hwrro_mode, which the failed primary attach had
just turned off.

Skip the hif2 WED setup when the primary WED device is not active.

Fixes: 83eafc9251d6 ("wifi: mt76: mt7996: add wed tx support")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Felix Fietkau be7e2fa433 wifi: mt76: mt7996: fix MIB TX aggregation counter registers for mt7990
The MIB_TSCR0-7 counters read by mt7996_mac_update_stats() are
hardcoded at the mt7996/mt7992 offsets 0x6b0-0x6d0, but mt7990 moved
them to 0x750-0x770, so TX AMPDU statistics were read from unrelated
registers on that chip. Move the offsets into the per-chip register
tables.

Fixes: f6c87411d15f ("wifi: mt76: mt7996: rework register mapping for mt7990")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Felix Fietkau 00107991a2 wifi: mt76: mt7996: use the default timeout for STA_REC and BSS_INFO updates
STA_REC_UPDATE and BSS_INFO_UPDATE carry variable-size payloads,
including beacon templates that grow considerably with 11v MBSS and
MLD configurations, and firmware can legitimately take longer than 2
seconds to process them. Since a message timeout now triggers a full
device reset, a false timeout on these commands is punished harshly.

Keep the shorter timeout for the small fixed-size commands and move
STA_REC_UPDATE/BSS_INFO_UPDATE back to the 5 second default.

Fixes: beb01caa570c ("wifi: mt76: mt7996: decrease timeout for commonly issued MCU commands")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
StanleyYP WangandFelix Fietkau c85317f1d4 wifi: mt76: mt7996: fix reg addr remap when addr is 0
When addr is less than the hardcoded threshold in __mt7996_reg_addr,
it indicates that remapping is unnecessary.
Currently, the flow remaps address 0x0 to MT_HIF_REMAP_BASE_L2,
which is incorrect.
To address this, modify __mt7996_reg_addr to return INVALID_REG_ADDR
if the address is not below the hardcoded value or is not present in
the mt7996_reg_map array.
Additionally, update the remap condition to check if addr is equal to
INVALID_REG_ADDR.

Fixes: 3687854d3e7e ("wifi: mt76: mt7996: add locking for accessing mapped registers")
Signed-off-by: StanleyYP Wang <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Felix Fietkau 686b509b9f wifi: mt76: mt7996: bound RRO session id before indexing addr_elem[]
seq_id from the WED RRO indication is a 12-bit field (0-4095), but only
values up to MT7996_RRO_MAX_SESSION map into wed_rro.addr_elem[], which
has MT7996_RRO_ADDR_ELEM_LEN (128) entries. A larger session id computes
an out-of-bounds element index that is then read and, on a signature
mismatch, written. Reject an out-of-range session id.

Fixes: a09d2f9d69af ("wifi: mt76: Convert mt76_wed_rro_ind to LE")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Felix Fietkau 5367804a6a wifi: mt76: mt7915: guard firmware memory dump write on disabled memdump
mt7915_coredump_build()/mt7996_coredump_build() wrote dump_mem->len
unconditionally, but the allocation only reserves room for the memory
dump header when coredump_memdump is enabled and memdump_buf_len is
non-zero. In the default configuration the allocation ends right after
the fixed header, so the write landed one struct past the buffer. Only
populate the memory-dump section when it was actually allocated.

Fixes: 4dbcb9125cc3 ("wifi: mt76: mt7915: enable coredump support")
Fixes: 878161d5d4a4 ("wifi: mt76: mt7996: enable coredump support")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:21 +02:00
Felix Fietkau a06dbaf0c3 wifi: mt76: mt7996: validate firmware event lengths before parsing
Two unsolicited event handlers trusted firmware-provided lengths:
mt7996_mcu_rx_all_sta_info_event() looped over res->sta_num without
checking it against skb->len, reading the flex array out of bounds; and
mt7996_mcu_rx_log_message() could compute a negative or oversized length
from tlv->len and feed it to %.*s and the debugfs log path. Bound both
against the actual skb length.

Fixes: adde3eed4a75 ("wifi: mt76: mt7996: Add mcu commands for getting sta tx statistic")
Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:20 +02:00
Felix Fietkau 591568f4e6 wifi: mt76: mt7996: bound EEPROM access event before copying
mt7996_mcu_get_eeprom() copied the event->eeprom payload out of the
firmware response skb without checking that the response actually held
the bytes being read. A short or malformed response could read past the
end of the skb. Reject a response shorter than the event header and bound
each copy to the payload present in the skb.

Fixes: 0da2e410705e ("wifi: mt76: mt7996: extend flexibility of mt7996_mcu_get_eeprom()")
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:46:20 +02:00
Felix Fietkau b2704cf5a4 wifi: mt76: mt7996: fix out-of-bounds link array access in mt7996_tx()
When mac80211 leaves the link unspecified, mt7996_tx() substitutes the
primary link id of the station or vif. That value is
IEEE80211_LINK_UNSPECIFIED (0xf) until the first link has been added,
and it is then used unchecked to index vif->link_conf[],
mvif->mt76.link[] and sta->link[], all of which hold
IEEE80211_MLD_MAX_NUM_LINKS (15) entries.

Clamp the primary link id to the default link before using it, and use
the clamped value for the link_sta fallback as well.

Fixes: 1609b014aa29 ("wifi: mt76: mt7996: Overwrite unspecified link_id in mt7996_tx()")
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-08-01 17:45:48 +02:00
Felix Fietkau da2c90d216 wifi: mt76: mt7996: send the STA_REC before the per-station VoW setup
mt7996_mcu_add_sta() issued the VoW DRR control commands for a station
before sending the STA_REC that instantiates it in the firmware. On a
fresh peer entry there is no station context yet, so the firmware
rejects UNI_VOW_DRR_CTRL with 0xC0000001, logging "GetDisablePerStaTx
Failed". That error was returned to the caller, which freed the STA_REC
skb without ever sending it, so bringing up client mode occasionally
failed with "failed to move station to desired state".

Send the STA_REC first and set up the airtime scheduler afterwards.
Airtime fairness is not required for the link to work and the station
record has already been committed at that point, so a failure there no
longer aborts the connection.

Fixes: 910db36ae5 ("wifi: mt76: mt7996: HW ATF support")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-29 18:02:19 +02:00
Felix Fietkau 06b69763f2 wifi: mt76: mt7996: fix infinite loop in PS sync event parsing
A zero-length TLV makes the parser loop spin forever, since neither
skb_pull() nor the remaining length advance, hanging the RX NAPI thread
until RCU reports a stall.

Reject TLVs shorter than their header, and validate the per-tag payload
lengths before dereferencing them.

Fixes: https://github.com/openwrt/mt76/issues/1109
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-27 17:01:10 +02:00
Chad MonroeandFelix Fietkau 50480826f5 wifi: mt76: mt7996: hold dev->mutex in remove_interface teardown
mt7996_remove_interface() destroys the remaining vif links, clearing
omac_mask, vif_mask and mld_idx_mask, with only the wiphy mutex held.
Those masks are modified under dev->mutex everywhere else, so the
unlocked clears can race the scan-link teardown and the reset work
and lose updates.

Take dev->mutex around the link destroy loop, matching
mt7996_add_interface() and mt7915_remove_interface(). The mutex is
released before mt76_vif_cleanup(), which aborts a pending scan and
takes the mutex itself.

Signed-off-by: Chad Monroe <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 31f1fdb7cd wifi: mt76: mt7996: clear stale link state on full reset
After a full chip reset, mac80211 reconfig replays interface, link and
channel context setup. mt7996_vif_link_add() short-circuits when the
link_id is still marked in mvif->valid_links, a state introduced for
postponing link teardown to interface removal. The reset path frees the
link structures without clearing those bits, so the replayed setup never
re-creates dev_info/bss_info/STA records in the restarted firmware and
never re-registers the link wcid, leaving the device inoperative.

The reset path also leaks every allocated MLD index: per-link indices
and the per-vif group/remap indices are re-allocated from scratch during
reconfig, but the old bits stay set in the masks, so repeated full
resets exhaust the index space.

Clear valid_links in the reset vif iterator and reset the MLD index
masks alongside the existing omac_mask clearing.

Fixes: ace5d3b6b49e ("wifi: mt76: mt7996: improve hardware restart reliability")
Fixes: 08813703ac41 ("wifi: mt76: mt7996: Destroy vif active links in mt7996_remove_interface()")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 386fd21557 wifi: mt76: mt7996: free vif links after clearing wcid entries on full reset
mt7996_mac_reset_vif_iter() queues non-default vif links for kfree_rcu
while dev->wcid[] still holds pointers to the wcid embedded in each
freed link; mt76_reset_device() then dereferences those entries and
runs mt76_wcid_cleanup() on them. If a grace period elapses in between,
the cleanup operates on freed memory.

Run mt76_reset_device() first, so the wcid entries are cleaned up and
cleared while the links are still valid.

Fixes: ace5d3b6b49e ("wifi: mt76: mt7996: improve hardware restart reliability")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Chad MonroeandFelix Fietkau 130273a947 wifi: mt76: fix stuck TX queues after SER with no active interfaces
When a firmware watchdog triggers full SER recovery before any VAPs
are up, mac80211 skips drv_reconfig_complete() because open_count is
zero. This leaves the DRIVER queue stop reason set permanently,
blocking all TX when interfaces eventually start.

Signed-off-by: Chad Monroe <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Chad MonroeandFelix Fietkau 5ecae46405 wifi: mt76: mt7996: select net_setup_tc handler at runtime
The net_setup_tc callback is chosen at compile time and the WED
handler shadows the NPU one when CONFIG_NET_MEDIATEK_SOC_WED is
enabled. mt76_wed_net_setup_tc() returns -EOPNOTSUPP without an
active WED device, so on boards using the Airoha NPU with a WED
enabled kernel the tc offload block is never bound and PPE flow
offload for wireless traffic is silently disabled.

Dispatch on the active offload backend instead: use the WED handler
when a WED device is attached and fall back to the NPU handler
otherwise. Builds without MT76_NPU keep the old behavior through the
mt76_npu_net_setup_tc() stub.

Signed-off-by: Chad Monroe <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau be8657a1cd wifi: mt76: mt7996: wake MCU waiters before aborting scan in L1 SER
The L1 reset path calls mt76_abort_scan() between setting MT76_MCU_RESET
and waking mcu.wait. A scan work blocked on an in-flight MCU command
does not re-evaluate its wait condition until woken, so the
cancel_delayed_work_sync() inside the abort sleeps out the full MCU
timeout before recovery can proceed, adding several seconds of SER
latency. mt7996_mac_full_reset() and the mt7915 counterpart already
order the wake-up first.

Wake mcu.wait immediately after setting MT76_MCU_RESET so in-flight
commands bail out before the abort synchronises against them.

Fixes: b36d55610215 ("wifi: mt76: abort scan/roc on hw restart")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau e14869fcee wifi: mt76: mt7996: skip key upload when adding an offchannel link
No hw keys are ever uploaded for scanning/roc links and the link remove
path already skips the key iteration for them. The add path still runs
it, and since mt7996_set_hw_key() resolves the target through
mvif->link[link_id] rather than the offchannel link, starting a scan on
another band re-uploads the group keys of the link sharing the same
link_id, re-sending its BSS cipher info and, for BIGTK with beacon
protection on an AP link, toggling its beacons off and on.

Skip the key iteration for offchannel links, mirroring the remove path.

Fixes: 69d54ce7491d ("wifi: mt76: mt7996: switch to single multi-radio wiphy")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Peter ChiuandFelix Fietkau ffabf1e53b wifi: mt76: mt7996: leave PS when a 4-address connection is established
Because 4 address non-AMSDU packets do not have a bssid field, the
hardware cannot get the bssid. Without the bssid, stations are not
able to leave PS mode due to HW design. Wake up non-setup links when
4-address mode is established to prevent this issue.

mt7992 and mt7990 handle this via the BSSID mapping band config
instead, so restrict the command to mt7996.

Signed-off-by: Peter Chiu <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Peter ChiuandFelix Fietkau eeb07a4edc wifi: mt76: mt7996: add mcu command to set bssid mapping address
When receiving a 4 address non-AMSDU packet, there is no bssid in the
address fields, which breaks powersave handling for 4-address peers.
Set the mcu command to use A1 as bssid when receiving 4 address
non-AMSDU packets on mt7992 and mt7990.

Also skip mt7996_mac_init_band() for invalid bands, so the command is
only sent for bands that actually exist on the device.

Signed-off-by: Peter Chiu <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
StanleyYP WangandFelix Fietkau 1ece37f8a9 wifi: mt76: mt7996: add missing rdd_idx check when enabling background radar
Add the missing rdd idx check (< 0) in
mt7996_mcu_rdd_background_enable(). mt7996_get_rdd_idx() returns -1
for phys without 5 GHz support, and the negative index was passed to
the RDD MCU command unchecked.

Fixes: 1529e335f93d ("wifi: mt76: mt7996: rework radar HWRDD idx")
Signed-off-by: StanleyYP Wang <[email protected]>
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 10a1541fb2 wifi: mt76: report data NSS for STBC frames in RX rate decode
The RX rate decoder set status->nss straight from the PRXV NSTS field,
which for STBC frames is twice the data spatial-stream count. cfg80211
then reported a doubled RX bitrate in station dumps and radiotap. Halve
nss for STBC, matching the TX status path.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Fixes: d832f5e73815 ("mt76: connac: move mt76_connac2_mac_fill_rx_rate in connac module")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 3def033512 wifi: mt76: cancel reset and rc work on device unregister
Both drivers cancelled dump_work on unregister but left reset_work and
rc_work to be flushed only by destroy_workqueue() in mt76_free_device(),
which runs after the hw is unregistered and the hardware stopped. A
reset_work that fires in that window calls ieee80211_restart_hw() and
re-arms mac_work on an unregistered hw, and rc_work touches station state
being torn down. Cancel both up front, alongside dump_work.

Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau d67367ec32 wifi: mt76: mt7996: don't leak MLD group index on remap alloc failure
mt7996_change_vif_links() sets the mld_idx_mask group bit before
allocating the remap index. If the remap allocation fails it jumped to
the exit without clearing that bit, permanently consuming one of the 16
MLD group slots. Release the group bit on the error path.

Fixes: 4fb3b4e7d1ca ("wifi: mt76: mt7996: fix MLD group index assignment")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau f66cff22fb wifi: mt76: mt7996: reserve space for the CSA-abort countdown TLV
When a CSA countdown is active, mt7996_mcu_beacon_cntdwn() emits two
bss_bcn_cntdwn_tlv entries (the CSA countdown and the CCA-abort BCC), but
MT7996_BEACON_UPDATE_SIZE only reserved one. With MBSSID enabled and a
near-maximum beacon template the extra 8 bytes could push the offload
command past MT7996_MAX_BSS_OFFLOAD_SIZE and trigger skb_over_panic().
Reserve room for both countdown TLVs.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau f012f82a81 wifi: mt76: fix ER-SU 106-tone RU check in RX rate decode
MT_PHY_TYPE_HE_EXT_SU is an enum value (9), not a bit flag, so the
bitwise test "*mode & MT_PHY_TYPE_HE_EXT_SU" also matches OFDM, HT-GF and
several HE/EHT modes. Only genuine ER-SU should be classified as a
106-tone RU at 40 MHz; use an equality comparison.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Fixes: d832f5e73815 ("mt76: connac: move mt76_connac2_mac_fill_rx_rate in connac module")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 41cecc382b wifi: mt76: decode the full VHT Rx STBC capability field
The Rx STBC subfield of the VHT capabilities is a 3-bit cumulative value,
but the driver only tested the RXSTBC_1 bit when advertising the peer's
Rx STBC support to firmware. A peer reporting Rx STBC of 2, 3 or 4 has
that bit clear, so STBC was never used towards it. Test the full
IEEE80211_VHT_CAP_RXSTBC_MASK, matching the HT path.

Fixes: 046d2e7c50e3 ("mac80211: prepare sta handling for MLO support")
Fixes: 2660fde82f65 ("wifi: mt76: mt7996: Update mt7996_mcu_add_rate_ctrl to MLO")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 2a574ac536 wifi: mt76: mt7996: hold dev->mt76.mutex while disabling tx worker in SER
mt7996_mac_reset_work() parked the tx worker and disabled the RX/TX NAPIs
before taking dev->mt76.mutex. mt76_worker_disable()/_enable() are plain
kthread park/unpark, not refcounted, and __mt76_set_channel() toggles the
same worker and the MT76_RESET bit under the mutex. An L1 SER racing a
channel switch could therefore have the worker unparked and MT76_RESET
cleared while the reset path resets the DMA rings, corrupting descriptors
or tokens. Take the mutex before disabling the worker, as mt7915 does.

Fixes: 27015b6fbcca ("wifi: mt76: mt7996: enable full system reset support")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:39 +02:00
Felix Fietkau 48c4d99acd wifi: mt76: mt7996: bound TLV walk in mt7996_mcu_get_chip_config
The response TLV loop advanced by tlv->len without a minimum, so a
theoretical firmware response containing a zero-length TLV could spin
forever, hanging the CPU during device probe.
The u32 payload was also read without bounds checking.
Reject a short fixed field, stop on a TLV whose length underruns the
header or overruns the skb.

Fixes: 5d33053be609 ("wifi: mt76: mt7996: add variants support")
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-24 14:45:25 +02:00
Felix Fietkau f67ffb60cd wifi: mt76: allow TX aggregation on the VO queue
The TX aggregation check skipped TIDs 6 and 7, so all voice-priority
traffic was sent without a BA session and therefore unaggregated,
limiting throughput for stations that map bulk traffic to VO. The
hardware handles aggregation on the VO queue fine, and a peer that
prefers unaggregated voice frames can still decline the ADDBA request.

Remove the skip from both the connac2 and the mt7996 aggregation setup
paths.

Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 10:51:13 +02:00
Felix Fietkau cdc6c0d07c wifi: mt76: fix 4th chain ACK RSSI bitmask in sta_poll
The per-chain response-frame RSSI values are packed one per byte, but the
4th chain was extracted with GENMASK(31, 14) instead of GENMASK(31, 24).
The wrong mask overlaps chains 1-3 and shifts by 14, producing a garbage
chain-3 value that corrupts ack_signal/avg_ack_signal on 4x4 radios.
Extract the correct byte.

Fixes: a71b648e3527 ("wifi: mt76: mt7915: add ack signal support")
Fixes: ea5d99d07fbf ("wifi: mt76: mt7996: enable ack signal support")
Fixes: 67fc7a304bf5 ("wifi: mt76: mt7921: add ack signal support")
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 10:51:04 +02:00
Felix Fietkau 8ad57c3cca wifi: mt76: mt7996: don't report a zero TX bitrate
mt7996_sta_statistics() set NL80211_STA_INFO_TX_BITRATE unconditionally
after the block that already sets it, so a station with no rate info yet
was reported to userspace with a valid-but-zero TX rate. Drop the
redundant unconditional assignments; the in-block ones are sufficient.

Fixes: b34f346b917e ("wifi: mt76: mt7996: drop return in mt7996_sta_statistics")
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 10:51:04 +02:00
Felix Fietkau a3b62f2330 wifi: mt76: mt7996: set MT76_MCU_RESET before waking MCU waiters on full reset
mt7996_mac_full_reset() called wake_up(&dev->mt76.mcu.wait) without first
setting MT76_MCU_RESET. The MCU response wait condition only checks the
response queue and that bit, so the wake-up released nobody: a thread
blocked in an MCU command against the dead firmware (typically holding
dev->mt76.mutex) stayed asleep until its multi-second timeout, stalling
recovery. Set the bit before the wake-up, as mt7915 does.

Fixes: 27015b6fbcca ("wifi: mt76: mt7996: enable full system reset support")
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 10:51:04 +02:00
Felix Fietkau fc74da790f wifi: mt76: mt7996: validate RX band_idx before dereferencing phys[]
band_idx comes from a 2-bit descriptor field (0-3) and was used directly
to index dev->mt76.phys[] (size __MT_MAX_BAND == 3) and dereference the
result. A corrupt or reserved descriptor value could index out of bounds
or hit a NULL phy on parts with fewer bands. Reject invalid band indices,
mirroring mt7996_rx_get_wcid().

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 10:51:04 +02:00
Peter ChiuandFelix Fietkau 4efe882252 wifi: mt76: mt7996: fix MLD ID in MAC TXD and HIF TXP
Problem:
MCU command timeout while the firmware state is normal, and the
firmware keeps showing the error log "ERROR!! NO PAUSE...".

Root cause:
If the MLD_ID field in the TXD is neither the primary link id nor the
secondary link id, it may lead to a firmware busy loop when the third
link is in power saving mode.

Remap frames directed to a third link to the primary link wcid. Since
TX status events and txfree completions carry the wcid the firmware
saw, use the remapped wcid for packet id tracking and non-AQL packet
accounting as well, while the frame keeps its original link context
for addressing, band and OMAC selection.

Fixes: 85cd5534a3f2 ("wifi: mt76: mt7996: use correct link_id when filling TXD and TXP")
Signed-off-by: Peter Chiu <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 10:51:04 +02:00
Shayne ChenandFelix Fietkau 968dc6335a wifi: mt76: mt7996: fix capability of EHT-MCS 15 in MRU
According to the definition in IEEE Std 802.11be-2024, Table 9-417r:
- If 80 MHz is not supported, bit 1-3 are set to 0.
- If 160 MHz is not supported, bit 2-3 are set to 0.
- If 320 MHz is not supported, bit 3 is set to 0.

Fixes: 348533eb968d ("wifi: mt76: mt7996: add EHT capability init")
Signed-off-by: Shayne Chen <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-22 09:49:38 +02:00
Lorenzo BianconiandFelix Fietkau 763e99aadb wifi: mt76: mt7996: fix possible NULL-pointer deref in mt7996_mcu_sta_bfer_eht()
mt76_connac_get_eht_phy_cap routine can theoretically return NULL so
check cap pointer before dereferencing it.

Fixes: ba01944adee9f ("wifi: mt76: mt7996: add EHT beamforming support")
Signed-off-by: Lorenzo Bianconi <[email protected]>
Link: https://patch.msgid.link/20260621-mt76_connac_get_he_phy_cap-fix-v1-4-ed4ccf7a0363@kernel.org
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-21 12:39:16 +02:00
Lorenzo BianconiandFelix Fietkau 89b69012de wifi: mt76: mt7996: check pointer returned by mt76_connac_get_he_phy_cap()
mt76_connac_get_he_phy_cap routine can theoretically return NULL so
check cap pointer before dereferencing it.

Fixes: 98686cd21624c ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Signed-off-by: Lorenzo Bianconi <[email protected]>
Link: https://patch.msgid.link/20260621-mt76_connac_get_he_phy_cap-fix-v1-3-ed4ccf7a0363@kernel.org
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-21 12:39:16 +02:00
Kenneth KasilagandFelix Fietkau 1ee3e2f6c2 wifi: mt76: mt7996: expose per-band MAC addresses to cfg80211
mt7996/mt7992 are single-wiphy, multi-band devices. The driver assigns
each band its own MAC address from a per-band EEPROM entry, or derives
it from the primary band's address when that entry is empty, however
only the primary band's is published as perm_addr. The per-band
addresses are not exposed to cfg80211, so consumers usually fall back
to deriving one from perm_addr.

Store each band's address in wiphy->addresses[], indexed by radio, so
cfg80211 exposes the address the hardware actually uses for that radio.
addresses[0] is the primary band and matches perm_addr, as cfg80211
requires.

Link: https://github.com/openwrt/openwrt/issues/23578
Tested-on: Gemtek W1700K (MT7996)
Signed-off-by: Kenneth Kasilag <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-21 12:39:16 +02:00
Bryam VargasandFelix Fietkau 76c38706bb wifi: mt76: mt7996: bound the device EEPROM address before the EFUSE copy
mt7996_mcu_get_eeprom() derives the destination of the EFUSE/EXT block
copy from the address reported by the MCU response (event->addr, a
device-controlled __le32) and clamps only the copy length, never the
destination offset into dev->mt76.eeprom.data. A malicious or
malfunctioning device can report an arbitrary address and drive an
out-of-bounds write of up to MT7996_EXT_EEPROM_BLOCK_SIZE bytes past
eeprom.data.

Reject a response whose address would place the copy outside eeprom.data
before deriving the destination pointer. Devices that echo the requested
in-bounds offset are unaffected.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Cc: [email protected]
Signed-off-by: Bryam Vargas <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-21 12:39:16 +02:00
Laxman Acharya PadhyaandFelix Fietkau 3eb3ab6b43 wifi: mt76: mt7996: validate default EEPROM firmware size
The default EEPROM firmware is parsed and copied as a full EEPROM
without checking its length. A truncated file can make the driver
read beyond the firmware buffer during variant validation or the
fallback copy.

Reject files shorter than MT7996_EEPROM_SIZE before parsing or
copying the firmware.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Cc: [email protected]
Signed-off-by: Laxman Acharya Padhya <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Felix Fietkau <[email protected]>
2026-07-21 12:38:45 +02:00