mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-01 11:36:49 +00:00
323e249ce8
This updates mac80211 to version 6.1.97-1. This code is based on Linux 6.1.97 and contains all fixes included in the upstream wireless subsystem from that kernel version. This includes many bugfixes and also some security fixes. The removed patches are already integrated in upstream Linux 6.1.97 or in backports. The following patches were integrated in upstream Linux: ath11k/0013-wifi-ath11k-synchronize-ath11k_mac_he_gi_to_nl80211_.patch ath11k/0035-wifi-ath11k-Use-platform_get_irq-to-get-the-interrup.patch ath11k/0036-wifi-ath11k-fix-SAC-bug-on-peer-addition-with-sta-ba.patch ath11k/0047-wifi-ath11k-fix-deinitialization-of-firmware-resourc.patch ath11k/0053-wifi-ath11k-fix-writing-to-unintended-memory-region.patch ath11k/0060-wifi-ath11k-Ignore-frags-from-uninitialized-peer-in-.patch ath11k/0065-wifi-ath11k-fix-tx-status-reporting-in-encap-offload.patch ath11k/0067-wifi-ath11k-Fix-SKB-corruption-in-REO-destination-ri.patch ath11k/0069-wifi-ath11k-fix-registration-of-6Ghz-only-phy-withou.patch ath11k/0080-wifi-ath11k-add-support-default-regdb-while-searchin.patch ath11k/0085-wifi-ath11k-fix-memory-leak-in-WMI-firmware-stats.patch ath11k/0086-wifi-ath11k-Add-missing-check-for-ioremap.patch ath11k/0096-wifi-ath11k-fix-boot-failure-with-one-MSI-vector.patch subsys/337-wifi-mac80211-fix-race-condition-on-enabling-fast-xm.patch The following patches were integrated in upstream backports: ath11k/901-wifi-ath11k-pci-fix-compilation-in-5.16-and-older.patch build/080-resv_start_op.patch build/110-backport_napi_build_skb.patch The following files are missing in backports, we do not have to remove them any more. Some were already missing before some were removed in this update: include/linux/cordic.h include/linux/crc8.h include/linux/eeprom_93cx6.h include/linux/wl12xx.h include/net/ieee80211.h backport-include/linux/bcm47xx_nvram.h include/linux/ath9k_platform.h include/net/bluetooth/ backports ships a dummy Mediatek wed header for older kernel versions. We backported the feature in our kernel, remove the dummy header: backport-include/linux/soc/mediatek/mtk_wed.h Remove header files for subsystems used form the mainline kernel: include/trace/events/qrtr.h include/net/rsi_91x.h backport-include/linux/platform_data/brcmnand.h Link: https://github.com/openwrt/openwrt/pull/15827 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
146 lines
4.4 KiB
Diff
146 lines
4.4 KiB
Diff
From: Felix Fietkau <nbd@nbd.name>
|
|
Date: Fri, 9 Dec 2022 21:15:04 +0100
|
|
Subject: [PATCH] wifi: mac80211: add a workaround for receiving
|
|
non-standard mesh A-MSDU
|
|
|
|
At least ath10k and ath11k supported hardware (maybe more) does not implement
|
|
mesh A-MSDU aggregation in a standard compliant way.
|
|
802.11-2020 9.3.2.2.2 declares that the Mesh Control field is part of the
|
|
A-MSDU header. As such, its length must not be included in the subframe
|
|
length field.
|
|
Hardware affected by this bug treats the mesh control field as part of the
|
|
MSDU data and sets the length accordingly.
|
|
In order to avoid packet loss, keep track of which stations are affected
|
|
by this and take it into account when converting A-MSDU to 802.3 + mesh control
|
|
packets.
|
|
|
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
---
|
|
|
|
--- a/include/net/cfg80211.h
|
|
+++ b/include/net/cfg80211.h
|
|
@@ -6310,6 +6310,19 @@ static inline int ieee80211_data_to_8023
|
|
}
|
|
|
|
/**
|
|
+ * ieee80211_is_valid_amsdu - check if subframe lengths of an A-MSDU are valid
|
|
+ *
|
|
+ * This is used to detect non-standard A-MSDU frames, e.g. the ones generated
|
|
+ * by ath10k and ath11k, where the subframe length includes the length of the
|
|
+ * mesh control field.
|
|
+ *
|
|
+ * @skb: The input A-MSDU frame without any headers.
|
|
+ * @mesh_hdr: use standard compliant mesh A-MSDU subframe header
|
|
+ * Returns: true if subframe header lengths are valid for the @mesh_hdr mode
|
|
+ */
|
|
+bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr);
|
|
+
|
|
+/**
|
|
* ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
|
|
*
|
|
* Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
|
|
--- a/net/mac80211/rx.c
|
|
+++ b/net/mac80211/rx.c
|
|
@@ -2905,7 +2905,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
|
|
static ieee80211_rx_result res;
|
|
struct ethhdr ethhdr;
|
|
const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
|
|
- bool mesh = false;
|
|
|
|
if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
|
|
check_da = NULL;
|
|
@@ -2923,7 +2922,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
check_sa = NULL;
|
|
check_da = NULL;
|
|
- mesh = true;
|
|
break;
|
|
default:
|
|
break;
|
|
@@ -2938,10 +2936,21 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
|
|
data_offset, true))
|
|
return RX_DROP_UNUSABLE;
|
|
|
|
+ if (rx->sta && rx->sta->amsdu_mesh_control < 0) {
|
|
+ bool valid_std = ieee80211_is_valid_amsdu(skb, true);
|
|
+ bool valid_nonstd = ieee80211_is_valid_amsdu(skb, false);
|
|
+
|
|
+ if (valid_std && !valid_nonstd)
|
|
+ rx->sta->amsdu_mesh_control = 1;
|
|
+ else if (valid_nonstd && !valid_std)
|
|
+ rx->sta->amsdu_mesh_control = 0;
|
|
+ }
|
|
+
|
|
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
|
rx->sdata->vif.type,
|
|
rx->local->hw.extra_tx_headroom,
|
|
- check_da, check_sa, mesh);
|
|
+ check_da, check_sa,
|
|
+ rx->sta->amsdu_mesh_control);
|
|
|
|
while (!skb_queue_empty(&frame_list)) {
|
|
rx->skb = __skb_dequeue(&frame_list);
|
|
--- a/net/mac80211/sta_info.c
|
|
+++ b/net/mac80211/sta_info.c
|
|
@@ -594,6 +594,9 @@ __sta_info_alloc(struct ieee80211_sub_if
|
|
|
|
sta->sta_state = IEEE80211_STA_NONE;
|
|
|
|
+ if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
|
|
+ sta->amsdu_mesh_control = -1;
|
|
+
|
|
/* Mark TID as unreserved */
|
|
sta->reserved_tid = IEEE80211_TID_UNRESERVED;
|
|
|
|
--- a/net/mac80211/sta_info.h
|
|
+++ b/net/mac80211/sta_info.h
|
|
@@ -702,6 +702,7 @@ struct sta_info {
|
|
struct codel_params cparams;
|
|
|
|
u8 reserved_tid;
|
|
+ s8 amsdu_mesh_control;
|
|
|
|
struct cfg80211_chan_def tdls_chandef;
|
|
|
|
--- a/net/wireless/util.c
|
|
+++ b/net/wireless/util.c
|
|
@@ -776,6 +776,38 @@ __ieee80211_amsdu_copy(struct sk_buff *s
|
|
return frame;
|
|
}
|
|
|
|
+bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr)
|
|
+{
|
|
+ int offset = 0, remaining, subframe_len, padding;
|
|
+
|
|
+ for (offset = 0; offset < skb->len; offset += subframe_len + padding) {
|
|
+ struct {
|
|
+ __be16 len;
|
|
+ u8 mesh_flags;
|
|
+ } hdr;
|
|
+ u16 len;
|
|
+
|
|
+ if (skb_copy_bits(skb, offset + 2 * ETH_ALEN, &hdr, sizeof(hdr)) < 0)
|
|
+ return false;
|
|
+
|
|
+ if (mesh_hdr)
|
|
+ len = le16_to_cpu(*(__le16 *)&hdr.len) +
|
|
+ __ieee80211_get_mesh_hdrlen(hdr.mesh_flags);
|
|
+ else
|
|
+ len = ntohs(hdr.len);
|
|
+
|
|
+ subframe_len = sizeof(struct ethhdr) + len;
|
|
+ padding = (4 - subframe_len) & 0x3;
|
|
+ remaining = skb->len - offset;
|
|
+
|
|
+ if (subframe_len > remaining)
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
|
|
+
|
|
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|
const u8 *addr, enum nl80211_iftype iftype,
|
|
const unsigned int extra_headroom,
|