PKG_NAME:=mac80211
-PKG_VERSION:=6.1.102-1
+PKG_VERSION:=6.1.110-1
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0-only
PKG_LICENSE_FILES:=COPYING
-PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v6.1.102/
-PKG_HASH:=c03fd1ed946e5e4b756145ffad7a73fa821630f22c5d442456db16c96be2c9b2
+PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v6.1.110/
+PKG_HASH:=2415bc529ca25be0aa597f9638d8b6fc4138080bbaea96881a38101896df6703
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -6418,18 +6418,16 @@ static int ath11k_mac_op_add_interface(s
+@@ -6425,18 +6425,16 @@ static int ath11k_mac_op_add_interface(s
ath11k_dp_vdev_tx_attach(ar, arvif);
mutex_unlock(&ar->conf_mutex);
return 0;
-@@ -6454,7 +6452,6 @@ err_vdev_del:
+@@ -6461,7 +6459,6 @@ err_vdev_del:
spin_unlock_bh(&ar->data_lock);
err:
exit:
kfree(arg.chan_list);
-@@ -9065,6 +9087,9 @@ static int __ath11k_mac_register(struct
+@@ -9072,6 +9094,9 @@ static int __ath11k_mac_register(struct
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
}
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -6230,6 +6230,40 @@ void ath11k_mac_11d_scan_stop_all(struct
+@@ -6237,6 +6237,40 @@ void ath11k_mac_11d_scan_stop_all(struct
}
}
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
-@@ -6465,10 +6499,7 @@ err_peer_del:
+@@ -6472,10 +6506,7 @@ err_peer_del:
}
err_vdev_del:
spin_lock_bh(&ar->data_lock);
list_del(&arvif->list);
spin_unlock_bh(&ar->data_lock);
-@@ -6496,7 +6527,6 @@ static void ath11k_mac_op_remove_interfa
+@@ -6503,7 +6534,6 @@ static void ath11k_mac_op_remove_interfa
struct ath11k *ar = hw->priv;
struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ath11k_base *ab = ar->ab;
int ret;
int i;
-@@ -6517,29 +6547,13 @@ static void ath11k_mac_op_remove_interfa
+@@ -6524,29 +6554,13 @@ static void ath11k_mac_op_remove_interfa
arvif->vdev_id, ret);
}
struct ath11k_hw_ops {
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -8007,6 +8007,7 @@ ath11k_mac_op_reconfig_complete(struct i
+@@ -8014,6 +8014,7 @@ ath11k_mac_op_reconfig_complete(struct i
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
int recovery_count;
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return;
-@@ -8042,6 +8043,12 @@ ath11k_mac_op_reconfig_complete(struct i
+@@ -8049,6 +8050,12 @@ ath11k_mac_op_reconfig_complete(struct i
ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset success\n");
}
}
if (changed & BSS_CHANGED_FILS_DISCOVERY ||
changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP)
ath11k_mac_fils_discovery(arvif, info);
-@@ -9118,6 +9132,10 @@ static int __ath11k_mac_register(struct
+@@ -9125,6 +9139,10 @@ static int __ath11k_mac_register(struct
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL);
ath11k_control_beaconing(arvif, info);
if (arvif->is_up && vif->bss_conf.he_support &&
-@@ -5389,6 +5512,10 @@ static int ath11k_mac_copy_he_cap(struct
+@@ -5388,6 +5511,10 @@ static int ath11k_mac_copy_he_cap(struct
he_cap_elem->mac_cap_info[1] &=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
he_cap_elem->phy_cap_info[5] &=
~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
-@@ -6023,69 +6150,6 @@ ath11k_mac_setup_vdev_create_params(stru
+@@ -6030,69 +6157,6 @@ ath11k_mac_setup_vdev_create_params(stru
}
}
static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
-@@ -6754,7 +6818,6 @@ ath11k_mac_vdev_start_restart(struct ath
+@@ -6761,7 +6825,6 @@ ath11k_mac_vdev_start_restart(struct ath
struct ath11k_base *ab = ar->ab;
struct wmi_vdev_start_req_arg arg = {};
const struct cfg80211_chan_def *chandef = &ctx->def;
int ret = 0;
lockdep_assert_held(&ar->conf_mutex);
-@@ -6795,15 +6858,6 @@ ath11k_mac_vdev_start_restart(struct ath
+@@ -6802,15 +6865,6 @@ ath11k_mac_vdev_start_restart(struct ath
spin_lock_bh(&ab->base_lock);
arg.regdomain = ar->ab->dfs_region;
spin_unlock_bh(&ab->base_lock);
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -5480,6 +5480,27 @@ static __le16 ath11k_mac_setup_he_6ghz_c
+@@ -5479,6 +5479,27 @@ static __le16 ath11k_mac_setup_he_6ghz_c
return cpu_to_le16(bcap->he_6ghz_capa);
}
static int ath11k_mac_copy_he_cap(struct ath11k *ar,
struct ath11k_pdev_cap *cap,
struct ieee80211_sband_iftype_data *data,
-@@ -5541,18 +5562,7 @@ static int ath11k_mac_copy_he_cap(struct
+@@ -5540,18 +5561,7 @@ static int ath11k_mac_copy_he_cap(struct
break;
}
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -5485,20 +5485,36 @@ static void ath11k_mac_set_hemcsmap(stru
+@@ -5484,20 +5484,36 @@ static void ath11k_mac_set_hemcsmap(stru
struct ieee80211_sta_he_cap *he_cap,
int band)
{
static int ath11k_hw_mac_id_to_pdev_id_ipq8074(struct ath11k_hw_params *hw,
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -9179,6 +9179,11 @@ static int __ath11k_mac_register(struct
+@@ -9186,6 +9186,11 @@ static int __ath11k_mac_register(struct
goto err_free_if_combs;
}
return 0;
}
-@@ -3038,39 +3015,51 @@ static int ath11k_dp_rx_reap_mon_status_
+@@ -3037,39 +3014,51 @@ static int ath11k_dp_rx_reap_mon_status_
spin_lock_bh(&rx_ring->idr_lock);
skb = idr_find(&rx_ring->bufs_idr, buf_id);
(vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_MESH_POINT)) {
arvif->ftm_responder = info->ftm_responder;
-@@ -9239,7 +9239,7 @@ static int __ath11k_mac_register(struct
+@@ -9246,7 +9246,7 @@ static int __ath11k_mac_register(struct
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_SET_SCAN_DWELL);
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -6682,6 +6682,11 @@ static void ath11k_mac_op_remove_interfa
+@@ -6689,6 +6689,11 @@ static void ath11k_mac_op_remove_interfa
ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
arvif->vdev_id);
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
-@@ -3115,8 +3115,11 @@ int ath11k_peer_rx_frag_setup(struct ath
+@@ -3114,8 +3114,11 @@ int ath11k_peer_rx_frag_setup(struct ath
int i;
tfm = crypto_alloc_shash("michael_mic", 0, 0);
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
-@@ -3607,7 +3607,7 @@ static int ath11k_dp_rx_frag_h_mpdu(stru
+@@ -3606,7 +3606,7 @@ static int ath11k_dp_rx_frag_h_mpdu(stru
goto out_unlock;
}
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -5582,10 +5582,6 @@ static int ath11k_mac_copy_he_cap(struct
+@@ -5581,10 +5581,6 @@ static int ath11k_mac_copy_he_cap(struct
he_cap_elem->mac_cap_info[1] &=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
#define ATH11K_QUEUE_LEN 4096
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -9006,19 +9006,23 @@ static int ath11k_mac_setup_iface_combin
+@@ -9013,19 +9013,23 @@ static int ath11k_mac_setup_iface_combin
static const u8 ath11k_if_types_ext_capa[] = {
[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
};
static const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = {
-@@ -9256,6 +9260,9 @@ static int __ath11k_mac_register(struct
+@@ -9263,6 +9267,9 @@ static int __ath11k_mac_register(struct
wiphy_ext_feature_set(ar->hw->wiphy,
NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER);
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -6178,17 +6178,62 @@ static void ath11k_mac_op_stop(struct ie
+@@ -6185,17 +6185,62 @@ static void ath11k_mac_op_stop(struct ie
atomic_set(&ar->num_pending_mgmt_tx, 0);
}
if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) {
params->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains;
-@@ -6203,6 +6248,7 @@ ath11k_mac_setup_vdev_create_params(stru
+@@ -6210,6 +6255,7 @@ ath11k_mac_setup_vdev_create_params(stru
params->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains;
params->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains;
}
}
static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
-@@ -6497,7 +6543,12 @@ static int ath11k_mac_op_add_interface(s
+@@ -6504,7 +6550,12 @@ static int ath11k_mac_op_add_interface(s
for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
vif->hw_queue[i] = i % (ATH11K_HW_MAX_QUEUES - 1);
ret = ath11k_wmi_vdev_create(ar, vif->addr, &vdev_param);
if (ret) {
-@@ -6902,6 +6953,17 @@ ath11k_mac_vdev_start_restart(struct ath
+@@ -6909,6 +6960,17 @@ ath11k_mac_vdev_start_restart(struct ath
arg.pref_tx_streams = ar->num_tx_chains;
arg.pref_rx_streams = ar->num_rx_chains;
if (ret) {
ath11k_warn(ar->ab, "failed to set vdev %d up: %d\n",
arvif->vdev_id, ret);
-@@ -7130,7 +7138,8 @@ ath11k_mac_update_vif_chan(struct ath11k
+@@ -7137,7 +7145,8 @@ ath11k_mac_update_vif_chan(struct ath11k
int n_vifs)
{
struct ath11k_base *ab = ar->ab;
int ret;
int i;
bool monitor_vif = false;
-@@ -7184,8 +7193,15 @@ ath11k_mac_update_vif_chan(struct ath11k
+@@ -7191,8 +7200,15 @@ ath11k_mac_update_vif_chan(struct ath11k
ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
ret);
if (ret) {
ath11k_warn(ab, "failed to bring vdev up %d: %d\n",
arvif->vdev_id, ret);
-@@ -7303,7 +7319,8 @@ static int ath11k_start_vdev_delay(struc
+@@ -7310,7 +7326,8 @@ static int ath11k_start_vdev_delay(struc
}
if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
*/
#include <net/mac80211.h>
-@@ -4335,6 +4335,20 @@ exit:
+@@ -4334,6 +4334,20 @@ exit:
}
static int
ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar,
enum nl80211_band band,
const struct cfg80211_bitrate_mask *mask)
-@@ -7788,20 +7802,6 @@ static void ath11k_mac_op_flush(struct i
+@@ -7795,20 +7809,6 @@ static void ath11k_mac_op_flush(struct i
ath11k_mac_flush_tx_complete(ar);
}
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -4477,6 +4477,54 @@ ath11k_mac_set_peer_he_fixed_rate(struct
+@@ -4476,6 +4476,54 @@ ath11k_mac_set_peer_he_fixed_rate(struct
return ret;
}
static int ath11k_station_assoc(struct ath11k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
-@@ -4488,7 +4536,7 @@ static int ath11k_station_assoc(struct a
+@@ -4487,7 +4535,7 @@ static int ath11k_station_assoc(struct a
struct cfg80211_chan_def def;
enum nl80211_band band;
struct cfg80211_bitrate_mask *mask;
lockdep_assert_held(&ar->conf_mutex);
-@@ -4516,6 +4564,7 @@ static int ath11k_station_assoc(struct a
+@@ -4515,6 +4563,7 @@ static int ath11k_station_assoc(struct a
num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask);
num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask);
/* If single VHT/HE rate is configured (by set_bitrate_mask()),
* peer_assoc will disable VHT/HE. This is now enabled by a peer specific
-@@ -4532,6 +4581,11 @@ static int ath11k_station_assoc(struct a
+@@ -4531,6 +4580,11 @@ static int ath11k_station_assoc(struct a
band);
if (ret)
return ret;
}
/* Re-assoc is run only to update supported rates for given station. It
-@@ -4605,7 +4659,7 @@ static void ath11k_sta_rc_update_wk(stru
+@@ -4604,7 +4658,7 @@ static void ath11k_sta_rc_update_wk(stru
const u16 *vht_mcs_mask;
const u16 *he_mcs_mask;
u32 changed, bw, nss, smps, bw_prev;
const struct cfg80211_bitrate_mask *mask;
struct peer_assoc_params peer_arg;
enum wmi_phy_mode peer_phymode;
-@@ -4721,6 +4775,8 @@ static void ath11k_sta_rc_update_wk(stru
+@@ -4720,6 +4774,8 @@ static void ath11k_sta_rc_update_wk(stru
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
mask = &arvif->bitrate_mask;
num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
mask);
num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band,
-@@ -4743,6 +4799,9 @@ static void ath11k_sta_rc_update_wk(stru
+@@ -4742,6 +4798,9 @@ static void ath11k_sta_rc_update_wk(stru
} else if (sta->deflink.he_cap.has_he && num_he_rates == 1) {
ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask,
band);
if (pdev && pdev->pdev_id == pdev_id)
return (pdev->ar ? pdev->ar : NULL);
-@@ -6268,6 +6271,11 @@ static int ath11k_mac_op_start(struct ie
+@@ -6275,6 +6278,11 @@ static int ath11k_mac_op_start(struct ie
struct ath11k_pdev *pdev = ar->pdev;
int ret;
ath11k_mac_drain_tx(ar);
mutex_lock(&ar->conf_mutex);
-@@ -6282,6 +6290,7 @@ static int ath11k_mac_op_start(struct ie
+@@ -6289,6 +6297,7 @@ static int ath11k_mac_op_start(struct ie
case ATH11K_STATE_RESTARTED:
case ATH11K_STATE_WEDGED:
case ATH11K_STATE_ON:
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -2733,6 +2733,8 @@ static int ieee80211_scan(struct wiphy *
+@@ -2734,6 +2734,8 @@ static int ieee80211_scan(struct wiphy *
*/
fallthrough;
case NL80211_IFTYPE_AP:
.remove_interface = ar5523_remove_interface,
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -8592,6 +8592,7 @@ err_fallback:
+@@ -8599,6 +8599,7 @@ err_fallback:
static const struct ieee80211_ops ath11k_ops = {
.tx = ath11k_mac_op_tx,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -4358,9 +4358,6 @@ static int ieee80211_get_txq_stats(struc
+@@ -4359,9 +4359,6 @@ static int ieee80211_get_txq_stats(struc
struct ieee80211_sub_if_data *sdata;
int ret = 0;
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
-@@ -677,8 +677,7 @@ static void add_common_files(struct ieee
+@@ -675,8 +675,7 @@ static void add_common_files(struct ieee
DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
DEBUGFS_ADD(hw_queues);
NL80211_EXT_FEATURE_AQL))
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
-@@ -2302,7 +2302,6 @@ void ieee80211_wake_queue_by_reason(stru
+@@ -2301,7 +2301,6 @@ void ieee80211_wake_queue_by_reason(stru
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason,
bool refcounted);
void ieee80211_add_pending_skbs(struct ieee80211_local *local,
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -460,12 +460,6 @@ static void ieee80211_do_stop(struct iee
+@@ -481,12 +481,6 @@ static void ieee80211_do_stop(struct iee
if (cancel_scan)
ieee80211_scan_cancel(local);
ieee80211_roc_purge(local, sdata);
switch (sdata->vif.type) {
-@@ -813,25 +807,6 @@ static void ieee80211_uninit(struct net_
+@@ -834,25 +828,6 @@ static void ieee80211_uninit(struct net_
ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
}
static void
ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
-@@ -845,7 +820,6 @@ static const struct net_device_ops ieee8
+@@ -866,7 +841,6 @@ static const struct net_device_ops ieee8
.ndo_start_xmit = ieee80211_subif_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_get_stats64 = ieee80211_get_stats64,
};
-@@ -967,7 +941,6 @@ static const struct net_device_ops ieee8
+@@ -988,7 +962,6 @@ static const struct net_device_ops ieee8
.ndo_start_xmit = ieee80211_subif_start_xmit_8023,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_get_stats64 = ieee80211_get_stats64,
#if LINUX_VERSION_IS_GEQ(5,13,0)
.ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
-@@ -1471,35 +1444,6 @@ int ieee80211_do_open(struct wireless_de
+@@ -1492,35 +1465,6 @@ int ieee80211_do_open(struct wireless_de
ieee80211_recalc_ps(local);
set_bit(SDATA_STATE_RUNNING, &sdata->state);
return 0;
-@@ -1529,17 +1473,12 @@ static void ieee80211_if_setup(struct ne
+@@ -1550,17 +1494,12 @@ static void ieee80211_if_setup(struct ne
{
ether_setup(dev);
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
static void ieee80211_iface_process_skb(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
-@@ -2124,9 +2063,7 @@ int ieee80211_if_add(struct ieee80211_lo
+@@ -2145,9 +2084,7 @@ int ieee80211_if_add(struct ieee80211_lo
struct net_device *ndev = NULL;
struct ieee80211_sub_if_data *sdata = NULL;
struct txq_info *txqi;
ASSERT_RTNL();
-@@ -2149,30 +2086,18 @@ int ieee80211_if_add(struct ieee80211_lo
+@@ -2170,30 +2107,18 @@ int ieee80211_if_add(struct ieee80211_lo
sizeof(void *));
int txq_size = 0;
int i;
sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
-@@ -600,21 +599,18 @@ __sta_info_alloc(struct ieee80211_sub_if
+@@ -603,21 +602,18 @@ __sta_info_alloc(struct ieee80211_sub_if
sta->last_connected = ktime_get_seconds();
}
if (sta_prepare_rate_control(local, sta, gfp))
-@@ -688,8 +684,7 @@ __sta_info_alloc(struct ieee80211_sub_if
+@@ -691,8 +687,7 @@ __sta_info_alloc(struct ieee80211_sub_if
return sta;
free_txq:
free:
sta_info_free_link(&sta->deflink);
#ifdef CPTCFG_MAC80211_MESH
-@@ -1965,9 +1960,6 @@ ieee80211_sta_ps_deliver_response(struct
+@@ -1982,9 +1977,6 @@ ieee80211_sta_ps_deliver_response(struct
* TIM recalculation.
*/
for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
if (!sta->sta.txq[tid] ||
!(driver_release_tids & BIT(tid)) ||
-@@ -2452,7 +2444,7 @@ static void sta_set_tidstats(struct sta_
+@@ -2469,7 +2461,7 @@ static void sta_set_tidstats(struct sta_
tidstats->tx_msdu_failed = sta->deflink.status_stats.msdu_failed[tid];
}
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
-@@ -2780,9 +2772,6 @@ unsigned long ieee80211_sta_last_active(
+@@ -2797,9 +2789,6 @@ unsigned long ieee80211_sta_last_active(
static void sta_update_codel_params(struct sta_info *sta, u32 thr)
{
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -2197,6 +2197,7 @@ int ieee80211_if_add(struct ieee80211_lo
+@@ -2218,6 +2218,7 @@ int ieee80211_if_add(struct ieee80211_lo
ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
ndev->hw_features |= ndev->features &
MAC80211_SUPPORTED_FEATURES_TX;
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 1 Dec 2022 14:57:30 +0100
-Subject: [PATCH] wifi: mac80211: fix and simplify unencrypted drop check for
- mesh
-
-ieee80211_drop_unencrypted is called from ieee80211_rx_h_mesh_fwding and
-ieee80211_frame_allowed.
-
-Since ieee80211_rx_h_mesh_fwding can forward packets for other mesh nodes
-and is called earlier, it needs to check the decryptions status and if the
-packet is using the control protocol on its own, instead of deferring to
-the later call from ieee80211_frame_allowed.
-
-Because of that, ieee80211_drop_unencrypted has a mesh specific check
-that skips over the mesh header in order to check the payload protocol.
-This code is invalid when called from ieee80211_frame_allowed, since that
-happens after the 802.11->802.3 conversion.
-
-Fix this by moving the mesh specific check directly into
-ieee80211_rx_h_mesh_fwding.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Link: https://lore.kernel.org/r/20221201135730.19723-1-nbd@nbd.name
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2405,7 +2405,6 @@ static int ieee80211_802_1x_port_control
-
- static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
- {
-- struct ieee80211_hdr *hdr = (void *)rx->skb->data;
- struct sk_buff *skb = rx->skb;
- struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-
-@@ -2416,31 +2415,6 @@ static int ieee80211_drop_unencrypted(st
- if (status->flag & RX_FLAG_DECRYPTED)
- return 0;
-
-- /* check mesh EAPOL frames first */
-- if (unlikely(rx->sta && ieee80211_vif_is_mesh(&rx->sdata->vif) &&
-- ieee80211_is_data(fc))) {
-- struct ieee80211s_hdr *mesh_hdr;
-- u16 hdr_len = ieee80211_hdrlen(fc);
-- u16 ethertype_offset;
-- __be16 ethertype;
--
-- if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr))
-- goto drop_check;
--
-- /* make sure fixed part of mesh header is there, also checks skb len */
-- if (!pskb_may_pull(rx->skb, hdr_len + 6))
-- goto drop_check;
--
-- mesh_hdr = (struct ieee80211s_hdr *)(skb->data + hdr_len);
-- ethertype_offset = hdr_len + ieee80211_get_mesh_hdrlen(mesh_hdr) +
-- sizeof(rfc1042_header);
--
-- if (skb_copy_bits(rx->skb, ethertype_offset, ðertype, 2) == 0 &&
-- ethertype == rx->sdata->control_port_protocol)
-- return 0;
-- }
--
--drop_check:
- /* Drop unencrypted frames if key is set. */
- if (unlikely(!ieee80211_has_protected(fc) &&
- !ieee80211_is_any_nullfunc(fc) &&
-@@ -2898,8 +2872,16 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
- hdr = (struct ieee80211_hdr *) skb->data;
- mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
-
-- if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
-- return RX_DROP_MONITOR;
-+ if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
-+ int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
-+ sizeof(rfc1042_header);
-+ __be16 ethertype;
-+
-+ if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
-+ skb_copy_bits(rx->skb, offset, ðertype, 2) != 0 ||
-+ ethertype != rx->sdata->control_port_protocol)
-+ return RX_DROP_MONITOR;
-+ }
-
- /* frame is in RMC, don't forward */
- if (ieee80211_is_data(hdr->frame_control) &&
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 2 Dec 2022 13:53:11 +0100
-Subject: [PATCH] wifi: cfg80211: move A-MSDU check in
- ieee80211_data_to_8023_exthdr
-
-When parsing the outer A-MSDU header, don't check for inner bridge tunnel
-or RFC1042 headers. This is handled by ieee80211_amsdu_to_8023s already.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -631,8 +631,9 @@ int ieee80211_data_to_8023_exthdr(struct
- break;
- }
-
-- if (likely(skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
-- ((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
-+ if (likely(!is_amsdu &&
-+ skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
-+ ((ether_addr_equal(payload.hdr, rfc1042_header) &&
- payload.proto != htons(ETH_P_AARP) &&
- payload.proto != htons(ETH_P_IPX)) ||
- ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 2 Dec 2022 13:54:15 +0100
-Subject: [PATCH] wifi: cfg80211: factor out bridge tunnel / RFC1042 header
- check
-
-The same check is done in multiple places, unify it.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -542,6 +542,21 @@ unsigned int ieee80211_get_mesh_hdrlen(s
- }
- EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
-
-+static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
-+{
-+ const __be16 *hdr_proto = hdr + ETH_ALEN;
-+
-+ if (!(ether_addr_equal(hdr, rfc1042_header) &&
-+ *hdr_proto != htons(ETH_P_AARP) &&
-+ *hdr_proto != htons(ETH_P_IPX)) &&
-+ !ether_addr_equal(hdr, bridge_tunnel_header))
-+ return false;
-+
-+ *proto = *hdr_proto;
-+
-+ return true;
-+}
-+
- int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
- const u8 *addr, enum nl80211_iftype iftype,
- u8 data_offset, bool is_amsdu)
-@@ -633,14 +648,9 @@ int ieee80211_data_to_8023_exthdr(struct
-
- if (likely(!is_amsdu &&
- skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
-- ((ether_addr_equal(payload.hdr, rfc1042_header) &&
-- payload.proto != htons(ETH_P_AARP) &&
-- payload.proto != htons(ETH_P_IPX)) ||
-- ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
-- /* remove RFC1042 or Bridge-Tunnel encapsulation and
-- * replace EtherType */
-+ ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
-+ /* remove RFC1042 or Bridge-Tunnel encapsulation */
- hdrlen += ETH_ALEN + 2;
-- tmp.h_proto = payload.proto;
- skb_postpull_rcsum(skb, &payload, ETH_ALEN + 2);
- } else {
- tmp.h_proto = htons(skb->len - hdrlen);
-@@ -756,8 +766,6 @@ void ieee80211_amsdu_to_8023s(struct sk_
- {
- unsigned int hlen = ALIGN(extra_headroom, 4);
- struct sk_buff *frame = NULL;
-- u16 ethertype;
-- u8 *payload;
- int offset = 0, remaining;
- struct ethhdr eth;
- bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
-@@ -811,14 +819,8 @@ void ieee80211_amsdu_to_8023s(struct sk_
- frame->dev = skb->dev;
- frame->priority = skb->priority;
-
-- payload = frame->data;
-- ethertype = (payload[6] << 8) | payload[7];
-- if (likely((ether_addr_equal(payload, rfc1042_header) &&
-- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-- ether_addr_equal(payload, bridge_tunnel_header))) {
-- eth.h_proto = htons(ethertype);
-+ if (likely(ieee80211_get_8023_tunnel_proto(frame->data, ð.h_proto)))
- skb_pull(frame, ETH_ALEN + 2);
-- }
-
- memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth));
- __skb_queue_tail(list, frame);
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 2 Dec 2022 17:01:46 +0100
-Subject: [PATCH] wifi: mac80211: remove mesh forwarding congestion check
-
-Now that all drivers use iTXQ, it does not make sense to check to drop
-tx forwarding packets when the driver has stopped the queues.
-fq_codel will take care of dropping packets when the queues fill up
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/debugfs_netdev.c
-+++ b/net/mac80211/debugfs_netdev.c
-@@ -603,8 +603,6 @@ IEEE80211_IF_FILE(fwded_mcast, u.mesh.ms
- IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
- IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
- IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
--IEEE80211_IF_FILE(dropped_frames_congestion,
-- u.mesh.mshstats.dropped_frames_congestion, DEC);
- IEEE80211_IF_FILE(dropped_frames_no_route,
- u.mesh.mshstats.dropped_frames_no_route, DEC);
-
-@@ -740,7 +738,6 @@ static void add_mesh_stats(struct ieee80
- MESHSTATS_ADD(fwded_frames);
- MESHSTATS_ADD(dropped_frames_ttl);
- MESHSTATS_ADD(dropped_frames_no_route);
-- MESHSTATS_ADD(dropped_frames_congestion);
- #undef MESHSTATS_ADD
- }
-
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -333,7 +333,6 @@ struct mesh_stats {
- __u32 fwded_frames; /* Mesh total forwarded frames */
- __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/
- __u32 dropped_frames_no_route; /* Not transmitted, no route found */
-- __u32 dropped_frames_congestion;/* Not forwarded due to congestion */
- };
-
- #define PREQ_Q_F_START 0x1
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2932,11 +2932,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
- return RX_CONTINUE;
-
- ac = ieee802_1d_to_ac[skb->priority];
-- q = sdata->vif.hw_queue[ac];
-- if (ieee80211_queue_stopped(&local->hw, q)) {
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
-- return RX_DROP_MONITOR;
-- }
- skb_set_queue_mapping(skb, ac);
-
- if (!--mesh_hdr->ttl) {
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 6 Dec 2022 11:15:02 +0100
-Subject: [PATCH] wifi: mac80211: fix receiving A-MSDU frames on mesh
- interfaces
-
-The current mac80211 mesh A-MSDU receive path fails to parse A-MSDU packets
-on mesh interfaces, because it assumes that the Mesh Control field is always
-directly after the 802.11 header.
-802.11-2020 9.3.2.2.2 Figure 9-70 shows that the Mesh Control field is
-actually part of the A-MSDU subframe header.
-This makes more sense, since it allows packets for multiple different
-destinations to be included in the same A-MSDU, as long as RA and TID are
-still the same.
-Another issue is the fact that the A-MSDU subframe length field was apparently
-accidentally defined as little-endian in the standard.
-
-In order to fix this, the mesh forwarding path needs happen at a different
-point in the receive path.
-
-ieee80211_data_to_8023_exthdr is changed to ignore the mesh control field
-and leave it in after the ethernet header. This also affects the source/dest
-MAC address fields, which now in the case of mesh point to the mesh SA/DA.
-
-ieee80211_amsdu_to_8023s is changed to deal with the endian difference and
-to add the Mesh Control length to the subframe length, since it's not covered
-by the MSDU length field.
-
-With these changes, the mac80211 will get the same packet structure for
-converted regular data packets and unpacked A-MSDU subframes.
-
-The mesh forwarding checks are now only performed after the A-MSDU decap.
-For locally received packets, the Mesh Control header is stripped away.
-For forwarded packets, a new 802.11 header gets added.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
-+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
-@@ -33,7 +33,7 @@ static int mwifiex_11n_dispatch_amsdu_pk
- skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
-
- ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
-- priv->wdev.iftype, 0, NULL, NULL);
-+ priv->wdev.iftype, 0, NULL, NULL, false);
-
- while (!skb_queue_empty(&list)) {
- struct rx_packet_hdr *rx_hdr;
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -6324,11 +6324,36 @@ static inline int ieee80211_data_to_8023
- * @extra_headroom: The hardware extra headroom for SKBs in the @list.
- * @check_da: DA to check in the inner ethernet header, or NULL
- * @check_sa: SA to check in the inner ethernet header, or NULL
-+ * @mesh_control: A-MSDU subframe header includes the mesh control field
- */
- 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,
-- const u8 *check_da, const u8 *check_sa);
-+ const u8 *check_da, const u8 *check_sa,
-+ bool mesh_control);
-+
-+/**
-+ * ieee80211_get_8023_tunnel_proto - get RFC1042 or bridge tunnel encap protocol
-+ *
-+ * Check for RFC1042 or bridge tunnel header and fetch the encapsulated
-+ * protocol.
-+ *
-+ * @hdr: pointer to the MSDU payload
-+ * @proto: destination pointer to store the protocol
-+ * Return: true if encapsulation was found
-+ */
-+bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto);
-+
-+/**
-+ * ieee80211_strip_8023_mesh_hdr - strip mesh header from converted 802.3 frames
-+ *
-+ * Strip the mesh header, which was left in by ieee80211_data_to_8023 as part
-+ * of the MSDU data. Also move any source/destination addresses from the mesh
-+ * header to the ethernet header (if present).
-+ *
-+ * @skb: The 802.3 frame with embedded mesh header
-+ */
-+int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb);
-
- /**
- * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2726,6 +2726,174 @@ ieee80211_deliver_skb(struct ieee80211_r
- }
- }
-
-+static ieee80211_rx_result
-+ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
-+ struct sk_buff *skb)
-+{
-+#ifdef CPTCFG_MAC80211_MESH
-+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-+ struct ieee80211_local *local = sdata->local;
-+ uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
-+ struct ieee80211_hdr hdr = {
-+ .frame_control = cpu_to_le16(fc)
-+ };
-+ struct ieee80211_hdr *fwd_hdr;
-+ struct ieee80211s_hdr *mesh_hdr;
-+ struct ieee80211_tx_info *info;
-+ struct sk_buff *fwd_skb;
-+ struct ethhdr *eth;
-+ bool multicast;
-+ int tailroom = 0;
-+ int hdrlen, mesh_hdrlen;
-+ u8 *qos;
-+
-+ if (!ieee80211_vif_is_mesh(&sdata->vif))
-+ return RX_CONTINUE;
-+
-+ if (!pskb_may_pull(skb, sizeof(*eth) + 6))
-+ return RX_DROP_MONITOR;
-+
-+ mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
-+ mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
-+
-+ if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
-+ return RX_DROP_MONITOR;
-+
-+ eth = (struct ethhdr *)skb->data;
-+ multicast = is_multicast_ether_addr(eth->h_dest);
-+
-+ mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
-+ if (!mesh_hdr->ttl)
-+ return RX_DROP_MONITOR;
-+
-+ /* frame is in RMC, don't forward */
-+ if (is_multicast_ether_addr(eth->h_dest) &&
-+ mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
-+ return RX_DROP_MONITOR;
-+
-+ /* Frame has reached destination. Don't forward */
-+ if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
-+ goto rx_accept;
-+
-+ if (!ifmsh->mshcfg.dot11MeshForwarding) {
-+ if (is_multicast_ether_addr(eth->h_dest))
-+ goto rx_accept;
-+
-+ return RX_DROP_MONITOR;
-+ }
-+
-+ /* forward packet */
-+ if (sdata->crypto_tx_tailroom_needed_cnt)
-+ tailroom = IEEE80211_ENCRYPT_TAILROOM;
-+
-+ if (!--mesh_hdr->ttl) {
-+ if (multicast)
-+ goto rx_accept;
-+
-+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-+ return RX_DROP_MONITOR;
-+ }
-+
-+ if (mesh_hdr->flags & MESH_FLAGS_AE) {
-+ struct mesh_path *mppath;
-+ char *proxied_addr;
-+
-+ if (multicast)
-+ proxied_addr = mesh_hdr->eaddr1;
-+ else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
-+ /* has_a4 already checked in ieee80211_rx_mesh_check */
-+ proxied_addr = mesh_hdr->eaddr2;
-+ else
-+ return RX_DROP_MONITOR;
-+
-+ rcu_read_lock();
-+ mppath = mpp_path_lookup(sdata, proxied_addr);
-+ if (!mppath) {
-+ mpp_path_add(sdata, proxied_addr, eth->h_source);
-+ } else {
-+ spin_lock_bh(&mppath->state_lock);
-+ if (!ether_addr_equal(mppath->mpp, eth->h_source))
-+ memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
-+ mppath->exp_time = jiffies;
-+ spin_unlock_bh(&mppath->state_lock);
-+ }
-+ rcu_read_unlock();
-+ }
-+
-+ skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
-+
-+ ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
-+ eth->h_dest, eth->h_source);
-+ hdrlen = ieee80211_hdrlen(hdr.frame_control);
-+ if (multicast) {
-+ int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
-+
-+ fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
-+ IEEE80211_ENCRYPT_HEADROOM,
-+ tailroom, GFP_ATOMIC);
-+ if (!fwd_skb)
-+ goto rx_accept;
-+ } else {
-+ fwd_skb = skb;
-+ skb = NULL;
-+
-+ if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
-+ return RX_DROP_UNUSABLE;
-+ }
-+
-+ fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
-+ memcpy(fwd_hdr, &hdr, hdrlen - 2);
-+ qos = ieee80211_get_qos_ctl(fwd_hdr);
-+ qos[0] = qos[1] = 0;
-+
-+ skb_reset_mac_header(fwd_skb);
-+ hdrlen += mesh_hdrlen;
-+ if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
-+ &fwd_skb->protocol))
-+ hdrlen += ETH_ALEN;
-+ else
-+ fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
-+ skb_set_network_header(fwd_skb, hdrlen);
-+
-+ info = IEEE80211_SKB_CB(fwd_skb);
-+ memset(info, 0, sizeof(*info));
-+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
-+ info->control.vif = &sdata->vif;
-+ info->control.jiffies = jiffies;
-+ if (multicast) {
-+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
-+ memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
-+ /* update power mode indication when forwarding */
-+ ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
-+ } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
-+ /* mesh power mode flags updated in mesh_nexthop_lookup */
-+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
-+ } else {
-+ /* unable to resolve next hop */
-+ if (sta)
-+ mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
-+ hdr.addr3, 0,
-+ WLAN_REASON_MESH_PATH_NOFORWARD,
-+ sta->sta.addr);
-+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
-+ kfree_skb(fwd_skb);
-+ goto rx_accept;
-+ }
-+
-+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
-+ fwd_skb->dev = sdata->dev;
-+ ieee80211_add_pending_skb(local, fwd_skb);
-+
-+rx_accept:
-+ if (!skb)
-+ return RX_QUEUED;
-+
-+ ieee80211_strip_8023_mesh_hdr(skb);
-+#endif
-+
-+ return RX_CONTINUE;
-+}
-+
- static ieee80211_rx_result debug_noinline
- __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
- {
-@@ -2734,8 +2902,10 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- __le16 fc = hdr->frame_control;
- struct sk_buff_head frame_list;
-+ 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;
-@@ -2752,6 +2922,8 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
- break;
- case NL80211_IFTYPE_MESH_POINT:
- check_sa = NULL;
-+ check_da = NULL;
-+ mesh = true;
- break;
- default:
- break;
-@@ -2769,17 +2941,29 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
- ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
- rx->sdata->vif.type,
- rx->local->hw.extra_tx_headroom,
-- check_da, check_sa);
-+ check_da, check_sa, mesh);
-
- while (!skb_queue_empty(&frame_list)) {
- rx->skb = __skb_dequeue(&frame_list);
-
-- if (!ieee80211_frame_allowed(rx, fc)) {
-- dev_kfree_skb(rx->skb);
-+ res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
-+ switch (res) {
-+ case RX_QUEUED:
- continue;
-+ case RX_CONTINUE:
-+ break;
-+ default:
-+ goto free;
- }
-
-+ if (!ieee80211_frame_allowed(rx, fc))
-+ goto free;
-+
- ieee80211_deliver_skb(rx);
-+ continue;
-+
-+free:
-+ dev_kfree_skb(rx->skb);
- }
-
- return RX_QUEUED;
-@@ -2812,6 +2996,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
- if (!rx->sdata->u.mgd.use_4addr)
- return RX_DROP_UNUSABLE;
- break;
-+ case NL80211_IFTYPE_MESH_POINT:
-+ break;
- default:
- return RX_DROP_UNUSABLE;
- }
-@@ -2840,155 +3026,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
- return __ieee80211_rx_h_amsdu(rx, 0);
- }
-
--#ifdef CPTCFG_MAC80211_MESH
--static ieee80211_rx_result
--ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
--{
-- struct ieee80211_hdr *fwd_hdr, *hdr;
-- struct ieee80211_tx_info *info;
-- struct ieee80211s_hdr *mesh_hdr;
-- struct sk_buff *skb = rx->skb, *fwd_skb;
-- struct ieee80211_local *local = rx->local;
-- struct ieee80211_sub_if_data *sdata = rx->sdata;
-- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-- u16 ac, q, hdrlen;
-- int tailroom = 0;
--
-- hdr = (struct ieee80211_hdr *) skb->data;
-- hdrlen = ieee80211_hdrlen(hdr->frame_control);
--
-- /* make sure fixed part of mesh header is there, also checks skb len */
-- if (!pskb_may_pull(rx->skb, hdrlen + 6))
-- return RX_DROP_MONITOR;
--
-- mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
--
-- /* make sure full mesh header is there, also checks skb len */
-- if (!pskb_may_pull(rx->skb,
-- hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
-- return RX_DROP_MONITOR;
--
-- /* reload pointers */
-- hdr = (struct ieee80211_hdr *) skb->data;
-- mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
--
-- if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
-- int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
-- sizeof(rfc1042_header);
-- __be16 ethertype;
--
-- if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
-- skb_copy_bits(rx->skb, offset, ðertype, 2) != 0 ||
-- ethertype != rx->sdata->control_port_protocol)
-- return RX_DROP_MONITOR;
-- }
--
-- /* frame is in RMC, don't forward */
-- if (ieee80211_is_data(hdr->frame_control) &&
-- is_multicast_ether_addr(hdr->addr1) &&
-- mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
-- return RX_DROP_MONITOR;
--
-- if (!ieee80211_is_data(hdr->frame_control))
-- return RX_CONTINUE;
--
-- if (!mesh_hdr->ttl)
-- return RX_DROP_MONITOR;
--
-- if (mesh_hdr->flags & MESH_FLAGS_AE) {
-- struct mesh_path *mppath;
-- char *proxied_addr;
-- char *mpp_addr;
--
-- if (is_multicast_ether_addr(hdr->addr1)) {
-- mpp_addr = hdr->addr3;
-- proxied_addr = mesh_hdr->eaddr1;
-- } else if ((mesh_hdr->flags & MESH_FLAGS_AE) ==
-- MESH_FLAGS_AE_A5_A6) {
-- /* has_a4 already checked in ieee80211_rx_mesh_check */
-- mpp_addr = hdr->addr4;
-- proxied_addr = mesh_hdr->eaddr2;
-- } else {
-- return RX_DROP_MONITOR;
-- }
--
-- rcu_read_lock();
-- mppath = mpp_path_lookup(sdata, proxied_addr);
-- if (!mppath) {
-- mpp_path_add(sdata, proxied_addr, mpp_addr);
-- } else {
-- spin_lock_bh(&mppath->state_lock);
-- if (!ether_addr_equal(mppath->mpp, mpp_addr))
-- memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
-- mppath->exp_time = jiffies;
-- spin_unlock_bh(&mppath->state_lock);
-- }
-- rcu_read_unlock();
-- }
--
-- /* Frame has reached destination. Don't forward */
-- if (!is_multicast_ether_addr(hdr->addr1) &&
-- ether_addr_equal(sdata->vif.addr, hdr->addr3))
-- return RX_CONTINUE;
--
-- ac = ieee802_1d_to_ac[skb->priority];
-- skb_set_queue_mapping(skb, ac);
--
-- if (!--mesh_hdr->ttl) {
-- if (!is_multicast_ether_addr(hdr->addr1))
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh,
-- dropped_frames_ttl);
-- goto out;
-- }
--
-- if (!ifmsh->mshcfg.dot11MeshForwarding)
-- goto out;
--
-- if (sdata->crypto_tx_tailroom_needed_cnt)
-- tailroom = IEEE80211_ENCRYPT_TAILROOM;
--
-- fwd_skb = skb_copy_expand(skb, local->tx_headroom +
-- IEEE80211_ENCRYPT_HEADROOM,
-- tailroom, GFP_ATOMIC);
-- if (!fwd_skb)
-- goto out;
--
-- fwd_skb->dev = sdata->dev;
-- fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
-- fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
-- info = IEEE80211_SKB_CB(fwd_skb);
-- memset(info, 0, sizeof(*info));
-- info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
-- info->control.vif = &rx->sdata->vif;
-- info->control.jiffies = jiffies;
-- if (is_multicast_ether_addr(fwd_hdr->addr1)) {
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
-- memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
-- /* update power mode indication when forwarding */
-- ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
-- } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
-- /* mesh power mode flags updated in mesh_nexthop_lookup */
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
-- } else {
-- /* unable to resolve next hop */
-- mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
-- fwd_hdr->addr3, 0,
-- WLAN_REASON_MESH_PATH_NOFORWARD,
-- fwd_hdr->addr2);
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
-- kfree_skb(fwd_skb);
-- return RX_DROP_MONITOR;
-- }
--
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
-- ieee80211_add_pending_skb(local, fwd_skb);
-- out:
-- if (is_multicast_ether_addr(hdr->addr1))
-- return RX_CONTINUE;
-- return RX_DROP_MONITOR;
--}
--#endif
--
- static ieee80211_rx_result debug_noinline
- ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
- {
-@@ -2997,6 +3034,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
- struct net_device *dev = sdata->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
- __le16 fc = hdr->frame_control;
-+ static ieee80211_rx_result res;
- bool port_control;
- int err;
-
-@@ -3023,6 +3061,10 @@ ieee80211_rx_h_data(struct ieee80211_rx_
- if (unlikely(err))
- return RX_DROP_UNUSABLE;
-
-+ res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
-+ if (res != RX_CONTINUE)
-+ return res;
-+
- if (!ieee80211_frame_allowed(rx, fc))
- return RX_DROP_MONITOR;
-
-@@ -3997,10 +4039,6 @@ static void ieee80211_rx_handlers(struct
- CALL_RXH(ieee80211_rx_h_defragment);
- CALL_RXH(ieee80211_rx_h_michael_mic_verify);
- /* must be after MMIC verify so header is counted in MPDU mic */
--#ifdef CPTCFG_MAC80211_MESH
-- if (ieee80211_vif_is_mesh(&rx->sdata->vif))
-- CALL_RXH(ieee80211_rx_h_mesh_fwding);
--#endif
- CALL_RXH(ieee80211_rx_h_amsdu);
- CALL_RXH(ieee80211_rx_h_data);
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -542,7 +542,7 @@ unsigned int ieee80211_get_mesh_hdrlen(s
- }
- EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
-
--static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
-+bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
- {
- const __be16 *hdr_proto = hdr + ETH_ALEN;
-
-@@ -556,6 +556,49 @@ static bool ieee80211_get_8023_tunnel_pr
-
- return true;
- }
-+EXPORT_SYMBOL(ieee80211_get_8023_tunnel_proto);
-+
-+int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb)
-+{
-+ const void *mesh_addr;
-+ struct {
-+ struct ethhdr eth;
-+ u8 flags;
-+ } payload;
-+ int hdrlen;
-+ int ret;
-+
-+ ret = skb_copy_bits(skb, 0, &payload, sizeof(payload));
-+ if (ret)
-+ return ret;
-+
-+ hdrlen = sizeof(payload.eth) + __ieee80211_get_mesh_hdrlen(payload.flags);
-+
-+ if (likely(pskb_may_pull(skb, hdrlen + 8) &&
-+ ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
-+ &payload.eth.h_proto)))
-+ hdrlen += ETH_ALEN + 2;
-+ else if (!pskb_may_pull(skb, hdrlen))
-+ return -EINVAL;
-+
-+ mesh_addr = skb->data + sizeof(payload.eth) + ETH_ALEN;
-+ switch (payload.flags & MESH_FLAGS_AE) {
-+ case MESH_FLAGS_AE_A4:
-+ memcpy(&payload.eth.h_source, mesh_addr, ETH_ALEN);
-+ break;
-+ case MESH_FLAGS_AE_A5_A6:
-+ memcpy(&payload.eth.h_dest, mesh_addr, 2 * ETH_ALEN);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ pskb_pull(skb, hdrlen - sizeof(payload.eth));
-+ memcpy(skb->data, &payload.eth, sizeof(payload.eth));
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(ieee80211_strip_8023_mesh_hdr);
-
- int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
- const u8 *addr, enum nl80211_iftype iftype,
-@@ -568,7 +611,6 @@ int ieee80211_data_to_8023_exthdr(struct
- } payload;
- struct ethhdr tmp;
- u16 hdrlen;
-- u8 mesh_flags = 0;
-
- if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
- return -1;
-@@ -589,12 +631,6 @@ int ieee80211_data_to_8023_exthdr(struct
- memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
- memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
-
-- if (iftype == NL80211_IFTYPE_MESH_POINT &&
-- skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0)
-- return -1;
--
-- mesh_flags &= MESH_FLAGS_AE;
--
- switch (hdr->frame_control &
- cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
- case cpu_to_le16(IEEE80211_FCTL_TODS):
-@@ -608,17 +644,6 @@ int ieee80211_data_to_8023_exthdr(struct
- iftype != NL80211_IFTYPE_AP_VLAN &&
- iftype != NL80211_IFTYPE_STATION))
- return -1;
-- if (iftype == NL80211_IFTYPE_MESH_POINT) {
-- if (mesh_flags == MESH_FLAGS_AE_A4)
-- return -1;
-- if (mesh_flags == MESH_FLAGS_AE_A5_A6 &&
-- skb_copy_bits(skb, hdrlen +
-- offsetof(struct ieee80211s_hdr, eaddr1),
-- tmp.h_dest, 2 * ETH_ALEN) < 0)
-- return -1;
--
-- hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
-- }
- break;
- case cpu_to_le16(IEEE80211_FCTL_FROMDS):
- if ((iftype != NL80211_IFTYPE_STATION &&
-@@ -627,16 +652,6 @@ int ieee80211_data_to_8023_exthdr(struct
- (is_multicast_ether_addr(tmp.h_dest) &&
- ether_addr_equal(tmp.h_source, addr)))
- return -1;
-- if (iftype == NL80211_IFTYPE_MESH_POINT) {
-- if (mesh_flags == MESH_FLAGS_AE_A5_A6)
-- return -1;
-- if (mesh_flags == MESH_FLAGS_AE_A4 &&
-- skb_copy_bits(skb, hdrlen +
-- offsetof(struct ieee80211s_hdr, eaddr1),
-- tmp.h_source, ETH_ALEN) < 0)
-- return -1;
-- hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
-- }
- break;
- case cpu_to_le16(0):
- if (iftype != NL80211_IFTYPE_ADHOC &&
-@@ -646,7 +661,7 @@ int ieee80211_data_to_8023_exthdr(struct
- break;
- }
-
-- if (likely(!is_amsdu &&
-+ if (likely(!is_amsdu && iftype != NL80211_IFTYPE_MESH_POINT &&
- skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
- ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation */
-@@ -722,7 +737,8 @@ __ieee80211_amsdu_copy_frag(struct sk_bu
-
- static struct sk_buff *
- __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
-- int offset, int len, bool reuse_frag)
-+ int offset, int len, bool reuse_frag,
-+ int min_len)
- {
- struct sk_buff *frame;
- int cur_len = len;
-@@ -736,7 +752,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
- * in the stack later.
- */
- if (reuse_frag)
-- cur_len = min_t(int, len, 32);
-+ cur_len = min_t(int, len, min_len);
-
- /*
- * Allocate and reserve two bytes more for payload
-@@ -746,6 +762,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
- if (!frame)
- return NULL;
-
-+ frame->priority = skb->priority;
- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
- skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
-
-@@ -762,23 +779,37 @@ __ieee80211_amsdu_copy(struct sk_buff *s
- 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,
-- const u8 *check_da, const u8 *check_sa)
-+ const u8 *check_da, const u8 *check_sa,
-+ bool mesh_control)
- {
- unsigned int hlen = ALIGN(extra_headroom, 4);
- struct sk_buff *frame = NULL;
- int offset = 0, remaining;
-- struct ethhdr eth;
-+ struct {
-+ struct ethhdr eth;
-+ uint8_t flags;
-+ } hdr;
- bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
- bool reuse_skb = false;
- bool last = false;
-+ int copy_len = sizeof(hdr.eth);
-+
-+ if (iftype == NL80211_IFTYPE_MESH_POINT)
-+ copy_len = sizeof(hdr);
-
- while (!last) {
- unsigned int subframe_len;
-- int len;
-+ int len, mesh_len = 0;
- u8 padding;
-
-- skb_copy_bits(skb, offset, ð, sizeof(eth));
-- len = ntohs(eth.h_proto);
-+ skb_copy_bits(skb, offset, &hdr, copy_len);
-+ if (iftype == NL80211_IFTYPE_MESH_POINT)
-+ mesh_len = __ieee80211_get_mesh_hdrlen(hdr.flags);
-+ if (mesh_control)
-+ len = le16_to_cpu(*(__le16 *)&hdr.eth.h_proto) + mesh_len;
-+ else
-+ len = ntohs(hdr.eth.h_proto);
-+
- subframe_len = sizeof(struct ethhdr) + len;
- padding = (4 - subframe_len) & 0x3;
-
-@@ -787,16 +818,16 @@ void ieee80211_amsdu_to_8023s(struct sk_
- if (subframe_len > remaining)
- goto purge;
- /* mitigate A-MSDU aggregation injection attacks */
-- if (ether_addr_equal(eth.h_dest, rfc1042_header))
-+ if (ether_addr_equal(hdr.eth.h_dest, rfc1042_header))
- goto purge;
-
- offset += sizeof(struct ethhdr);
- last = remaining <= subframe_len + padding;
-
- /* FIXME: should we really accept multicast DA? */
-- if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
-- !ether_addr_equal(check_da, eth.h_dest)) ||
-- (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
-+ if ((check_da && !is_multicast_ether_addr(hdr.eth.h_dest) &&
-+ !ether_addr_equal(check_da, hdr.eth.h_dest)) ||
-+ (check_sa && !ether_addr_equal(check_sa, hdr.eth.h_source))) {
- offset += len + padding;
- continue;
- }
-@@ -808,7 +839,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
- reuse_skb = true;
- } else {
- frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
-- reuse_frag);
-+ reuse_frag, 32 + mesh_len);
- if (!frame)
- goto purge;
-
-@@ -819,10 +850,11 @@ void ieee80211_amsdu_to_8023s(struct sk_
- frame->dev = skb->dev;
- frame->priority = skb->priority;
-
-- if (likely(ieee80211_get_8023_tunnel_proto(frame->data, ð.h_proto)))
-+ if (likely(iftype != NL80211_IFTYPE_MESH_POINT &&
-+ ieee80211_get_8023_tunnel_proto(frame->data, &hdr.eth.h_proto)))
- skb_pull(frame, ETH_ALEN + 2);
-
-- memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth));
-+ memcpy(skb_push(frame, sizeof(hdr.eth)), &hdr.eth, sizeof(hdr.eth));
- __skb_queue_tail(list, frame);
- }
-
+++ /dev/null
-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,
}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
-@@ -2797,6 +2797,7 @@ ieee80211_rx_mesh_data(struct ieee80211_
+@@ -2778,6 +2778,7 @@ ieee80211_rx_mesh_data(struct ieee80211_
if (mesh_hdr->flags & MESH_FLAGS_AE) {
struct mesh_path *mppath;
char *proxied_addr;
if (multicast)
proxied_addr = mesh_hdr->eaddr1;
-@@ -2812,11 +2813,18 @@ ieee80211_rx_mesh_data(struct ieee80211_
+@@ -2793,11 +2794,18 @@ ieee80211_rx_mesh_data(struct ieee80211_
mpp_path_add(sdata, proxied_addr, eth->h_source);
} else {
spin_lock_bh(&mppath->state_lock);
ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
eth->h_dest, eth->h_source);
hdrlen = ieee80211_hdrlen(hdr.frame_control);
-@@ -2868,6 +2931,7 @@ ieee80211_rx_mesh_data(struct ieee80211_
+@@ -2871,6 +2934,7 @@ ieee80211_rx_mesh_data(struct ieee80211_
info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->control.vif = &sdata->vif;
info->control.jiffies = jiffies;
if (multicast) {
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
-@@ -2889,7 +2953,6 @@ ieee80211_rx_mesh_data(struct ieee80211_
+@@ -2892,7 +2956,6 @@ ieee80211_rx_mesh_data(struct ieee80211_
}
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 20 Feb 2023 12:50:50 +0100
-Subject: [PATCH] mac80211: fix mesh forwarding
-
-Linearize packets (needed for forwarding A-MSDU subframes).
-Fix network header offset to fix flow dissector (and fair queueing).
-
-Fixes: 986e43b19ae9 ("wifi: mac80211: fix receiving A-MSDU frames on mesh interfaces")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2910,6 +2910,9 @@ ieee80211_rx_mesh_data(struct ieee80211_
-
- if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
- return RX_DROP_UNUSABLE;
-+
-+ if (skb_linearize(fwd_skb))
-+ return RX_DROP_UNUSABLE;
- }
-
- fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
-@@ -2924,7 +2927,7 @@ ieee80211_rx_mesh_data(struct ieee80211_
- hdrlen += ETH_ALEN;
- else
- fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
-- skb_set_network_header(fwd_skb, hdrlen);
-+ skb_set_network_header(fwd_skb, hdrlen + 2);
-
- info = IEEE80211_SKB_CB(fwd_skb);
- memset(info, 0, sizeof(*info));
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sun, 26 Feb 2023 20:30:20 +0100
-Subject: [PATCH] wifi: mac80211: fix mesh path discovery based on unicast
- packets
-
-If a packet has reached its intended destination, it was bumped to the code
-that accepts it, without first checking if a mesh_path needs to be created
-based on the discovered source.
-Fix this by moving the destination address check further down
-
-Fixes: 986e43b19ae9 ("wifi: mac80211: fix receiving A-MSDU frames on mesh interfaces")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2830,17 +2830,6 @@ ieee80211_rx_mesh_data(struct ieee80211_
- mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
- return RX_DROP_MONITOR;
-
-- /* Frame has reached destination. Don't forward */
-- if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
-- goto rx_accept;
--
-- if (!ifmsh->mshcfg.dot11MeshForwarding) {
-- if (is_multicast_ether_addr(eth->h_dest))
-- goto rx_accept;
--
-- return RX_DROP_MONITOR;
-- }
--
- /* forward packet */
- if (sdata->crypto_tx_tailroom_needed_cnt)
- tailroom = IEEE80211_ENCRYPT_TAILROOM;
-@@ -2887,6 +2876,17 @@ ieee80211_rx_mesh_data(struct ieee80211_
- rcu_read_unlock();
- }
-
-+ /* Frame has reached destination. Don't forward */
-+ if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
-+ goto rx_accept;
-+
-+ if (!ifmsh->mshcfg.dot11MeshForwarding) {
-+ if (is_multicast_ether_addr(eth->h_dest))
-+ goto rx_accept;
-+
-+ return RX_DROP_MONITOR;
-+ }
-+
- skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
-
- if (!multicast &&
* @tid: the TID to BA on.
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
-@@ -554,6 +554,23 @@ void ieee80211_tx_ba_session_handle_star
+@@ -550,6 +550,23 @@ void ieee80211_tx_ba_session_handle_star
ieee80211_send_addba_with_timeout(sta, tid_tx);
}
MAC80211_SUPPORTED_FEATURES_RX)
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -813,6 +813,21 @@ ieee80211_get_stats64(struct net_device
+@@ -834,6 +834,21 @@ ieee80211_get_stats64(struct net_device
dev_fetch_sw_netstats(stats, dev->tstats);
}
static const struct net_device_ops ieee80211_dataif_ops = {
.ndo_open = ieee80211_open,
.ndo_stop = ieee80211_stop,
-@@ -821,6 +836,7 @@ static const struct net_device_ops ieee8
+@@ -842,6 +857,7 @@ static const struct net_device_ops ieee8
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_set_mac_address = ieee80211_change_mac,
.ndo_get_stats64 = ieee80211_get_stats64,
};
#if LINUX_VERSION_IS_GEQ(5,2,0)
-@@ -945,6 +961,7 @@ static const struct net_device_ops ieee8
+@@ -966,6 +982,7 @@ static const struct net_device_ops ieee8
#if LINUX_VERSION_IS_GEQ(5,13,0)
.ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
#endif
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sun, 26 Mar 2023 17:11:34 +0200
-Subject: [PATCH] wifi: mac80211: fix receiving mesh packets in forwarding=0
- networks
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When forwarding is set to 0, frames are typically sent with ttl=1.
-Move the ttl decrement check below the check for local receive in order to
-fix packet drops.
-
-Reported-by: Thomas Hühn <thomas.huehn@hs-nordhausen.de>
-Reported-by: Nick Hainke <vincent@systemli.org>
-Fixes: 986e43b19ae9 ("wifi: mac80211: fix receiving A-MSDU frames on mesh interfaces")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2834,14 +2834,6 @@ ieee80211_rx_mesh_data(struct ieee80211_
- if (sdata->crypto_tx_tailroom_needed_cnt)
- tailroom = IEEE80211_ENCRYPT_TAILROOM;
-
-- if (!--mesh_hdr->ttl) {
-- if (multicast)
-- goto rx_accept;
--
-- IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-- return RX_DROP_MONITOR;
-- }
--
- if (mesh_hdr->flags & MESH_FLAGS_AE) {
- struct mesh_path *mppath;
- char *proxied_addr;
-@@ -2880,6 +2872,14 @@ ieee80211_rx_mesh_data(struct ieee80211_
- if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
- goto rx_accept;
-
-+ if (!--mesh_hdr->ttl) {
-+ if (multicast)
-+ goto rx_accept;
-+
-+ IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-+ return RX_DROP_MONITOR;
-+ }
-+
- if (!ifmsh->mshcfg.dot11MeshForwarding) {
- if (is_multicast_ether_addr(eth->h_dest))
- goto rx_accept;
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -1276,6 +1276,14 @@ static void __sta_info_destroy_part2(str
+@@ -1290,6 +1290,14 @@ static void __sta_info_destroy_part2(str
WARN_ON_ONCE(ret);
}
struct ieee80211_channel_switch *ch_switch)
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -1281,8 +1281,12 @@ static void __sta_info_destroy_part2(str
+@@ -1295,8 +1295,12 @@ static void __sta_info_destroy_part2(str
* frames sitting on hardware queues might be sent out without
* any encryption at all.
*/
}
new = kzalloc(size, GFP_KERNEL);
-@@ -3395,8 +3395,11 @@ cfg80211_beacon_dup(struct cfg80211_beac
+@@ -3396,8 +3396,11 @@ cfg80211_beacon_dup(struct cfg80211_beac
len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
beacon->proberesp_ies_len + beacon->assocresp_ies_len +
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 11 Jul 2023 13:30:12 +0200
-Subject: [PATCH] wifi: cfg80211: fix receving mesh packets without RFC1042
- header
-
-Fix ethernet header length field after stripping the mesh header
-
-Cc: stable@vger.kernel.org
-Link: https://lore.kernel.org/all/CT5GNZSK28AI.2K6M69OXM9RW5@syracuse/
-Fixes: 986e43b19ae9 ("wifi: mac80211: fix receiving A-MSDU frames on mesh interfaces")
-Reported-by: Nicolas Escande <nico.escande@gmail.com>
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -580,6 +580,8 @@ int ieee80211_strip_8023_mesh_hdr(struct
- hdrlen += ETH_ALEN + 2;
- else if (!pskb_may_pull(skb, hdrlen))
- return -EINVAL;
-+ else
-+ payload.eth.h_proto = htons(skb->len - hdrlen);
-
- mesh_addr = skb->data + sizeof(payload.eth) + ETH_ALEN;
- switch (payload.flags & MESH_FLAGS_AE) {
{
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
-@@ -491,6 +491,8 @@ void cfg80211_set_dfs_state(struct wiphy
+@@ -497,6 +497,8 @@ void cfg80211_set_dfs_state(struct wiphy
enum nl80211_dfs_state dfs_state);
void cfg80211_dfs_channels_update_work(struct work_struct *work);
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
-@@ -277,6 +277,8 @@ struct cfg80211_event {
+@@ -283,6 +283,8 @@ struct cfg80211_event {
} ij;
struct {
u8 bssid[ETH_ALEN];
} pa;
};
};
-@@ -421,7 +423,8 @@ int cfg80211_disconnect(struct cfg80211_
+@@ -427,7 +429,8 @@ int cfg80211_disconnect(struct cfg80211_
bool wextev);
void __cfg80211_roamed(struct wireless_dev *wdev,
struct cfg80211_roam_info *info);
void cfg80211_autodisconnect_wk(struct work_struct *work);
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -17993,7 +17993,8 @@ void nl80211_send_roamed(struct cfg80211
+@@ -18024,7 +18024,8 @@ void nl80211_send_roamed(struct cfg80211
}
void nl80211_send_port_authorized(struct cfg80211_registered_device *rdev,
{
struct sk_buff *msg;
void *hdr;
-@@ -18013,6 +18014,11 @@ void nl80211_send_port_authorized(struct
+@@ -18044,6 +18045,11 @@ void nl80211_send_port_authorized(struct
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))
goto nla_put_failure;
* Use the wdev event list so that if there are pending
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
-@@ -1059,7 +1059,9 @@ void cfg80211_process_wdev_events(struct
+@@ -1065,7 +1065,9 @@ void cfg80211_process_wdev_events(struct
__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
break;
case EVENT_PORT_AUTHORIZED:
*/
#include <linux/module.h>
-@@ -2389,6 +2389,13 @@ static void sta_stats_decode_rate(struct
+@@ -2403,6 +2403,13 @@ static void sta_stats_decode_rate(struct
rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate);
rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate);
break;
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
-@@ -930,6 +930,7 @@ enum sta_stats_type {
+@@ -936,6 +936,7 @@ enum sta_stats_type {
STA_STATS_RATE_TYPE_VHT,
STA_STATS_RATE_TYPE_HE,
STA_STATS_RATE_TYPE_S1G,
};
#define STA_STATS_FIELD_HT_MCS GENMASK( 7, 0)
-@@ -939,12 +940,16 @@ enum sta_stats_type {
+@@ -945,12 +946,16 @@ enum sta_stats_type {
#define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4)
#define STA_STATS_FIELD_HE_MCS GENMASK( 3, 0)
#define STA_STATS_FIELD_HE_NSS GENMASK( 7, 4)
#define STA_STATS_FIELD(_n, _v) FIELD_PREP(STA_STATS_FIELD_ ## _n, _v)
#define STA_STATS_GET(_n, _v) FIELD_GET(STA_STATS_FIELD_ ## _n, _v)
-@@ -983,6 +988,13 @@ static inline u32 sta_stats_encode_rate(
+@@ -989,6 +994,13 @@ static inline u32 sta_stats_encode_rate(
r |= STA_STATS_FIELD(HE_RU, s->he_ru);
r |= STA_STATS_FIELD(HE_DCM, s->he_dcm);
break;
bool mu_mimo_owner;
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -4196,7 +4196,7 @@ static int ieee80211_set_ap_chanwidth(st
+@@ -4197,7 +4197,7 @@ static int ieee80211_set_ap_chanwidth(st
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_link_data *link;
int ret;
NUM_NL80211_EXT_FEATURES,
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -819,6 +819,7 @@ static const struct nla_policy nl80211_p
+@@ -829,6 +829,7 @@ static const struct nla_policy nl80211_p
[NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN),
[NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT },
};
/* policy for the key attributes */
-@@ -3187,6 +3188,21 @@ static bool nl80211_can_set_dev_channel(
+@@ -3197,6 +3198,21 @@ static bool nl80211_can_set_dev_channel(
wdev->iftype == NL80211_IFTYPE_P2P_GO;
}
int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
struct genl_info *info,
struct cfg80211_chan_def *chandef)
-@@ -5938,6 +5954,14 @@ static int nl80211_start_ap(struct sk_bu
+@@ -5969,6 +5985,14 @@ static int nl80211_start_ap(struct sk_bu
goto out;
}
if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, ¶ms->chandef,
wdev->iftype)) {
err = -EINVAL;
-@@ -10076,6 +10100,14 @@ skip_beacons:
+@@ -10107,6 +10131,14 @@ skip_beacons:
if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
params.block_tx = true;
* ieee80211_operating_class_to_band - convert operating class to band
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -3611,7 +3611,8 @@ static int __ieee80211_csa_finalize(stru
+@@ -3612,7 +3612,8 @@ static int __ieee80211_csa_finalize(stru
if (err)
return err;
return 0;
}
-@@ -3883,7 +3884,7 @@ __ieee80211_channel_switch(struct wiphy
+@@ -3884,7 +3885,7 @@ __ieee80211_channel_switch(struct wiphy
cfg80211_ch_switch_started_notify(sdata->dev,
&sdata->deflink.csa_chandef, 0,
/* use driver's channel switch callback */
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -19054,7 +19054,7 @@ static void nl80211_ch_switch_notify(str
+@@ -19085,7 +19085,7 @@ static void nl80211_ch_switch_notify(str
struct cfg80211_chan_def *chandef,
gfp_t gfp,
enum nl80211_commands notif,
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct sk_buff *msg;
-@@ -19088,6 +19088,9 @@ static void nl80211_ch_switch_notify(str
+@@ -19119,6 +19119,9 @@ static void nl80211_ch_switch_notify(str
goto nla_put_failure;
}
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-@@ -19100,7 +19103,7 @@ static void nl80211_ch_switch_notify(str
+@@ -19131,7 +19134,7 @@ static void nl80211_ch_switch_notify(str
void cfg80211_ch_switch_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
-@@ -19109,7 +19112,7 @@ void cfg80211_ch_switch_notify(struct ne
+@@ -19140,7 +19143,7 @@ void cfg80211_ch_switch_notify(struct ne
ASSERT_WDEV_LOCK(wdev);
WARN_INVALID_LINK_ID(wdev, link_id);
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
-@@ -19137,14 +19140,15 @@ void cfg80211_ch_switch_notify(struct ne
+@@ -19168,14 +19171,15 @@ void cfg80211_ch_switch_notify(struct ne
cfg80211_sched_dfs_chan_update(rdev);
nl80211_ch_switch_notify(rdev, dev, link_id, chandef, GFP_KERNEL,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
-@@ -19153,11 +19157,13 @@ void cfg80211_ch_switch_started_notify(s
+@@ -19184,11 +19188,13 @@ void cfg80211_ch_switch_started_notify(s
ASSERT_WDEV_LOCK(wdev);
WARN_INVALID_LINK_ID(wdev, link_id);
if (sdata->vif.type == NL80211_IFTYPE_AP &&
params->mbssid_config.tx_wdev) {
err = ieee80211_set_ap_mbssid_options(sdata,
-@@ -3570,6 +3575,12 @@ static int __ieee80211_csa_finalize(stru
+@@ -3571,6 +3576,12 @@ static int __ieee80211_csa_finalize(stru
lockdep_assert_held(&local->mtx);
lockdep_assert_held(&local->chanctx_mtx);
/*
* using reservation isn't immediate as it may be deferred until later
* with multi-vif. once reservation is complete it will re-schedule the
-@@ -3612,7 +3623,7 @@ static int __ieee80211_csa_finalize(stru
+@@ -3613,7 +3624,7 @@ static int __ieee80211_csa_finalize(stru
return err;
cfg80211_ch_switch_notify(sdata->dev, &sdata->deflink.csa_chandef, 0,
return 0;
}
-@@ -3874,9 +3885,13 @@ __ieee80211_channel_switch(struct wiphy
+@@ -3875,9 +3886,13 @@ __ieee80211_channel_switch(struct wiphy
goto out;
}
if (sdata->deflink.csa_block_tx)
ieee80211_stop_vif_queues(local, sdata,
-@@ -3884,7 +3899,8 @@ __ieee80211_channel_switch(struct wiphy
+@@ -3885,7 +3900,8 @@ __ieee80211_channel_switch(struct wiphy
cfg80211_ch_switch_started_notify(sdata->dev,
&sdata->deflink.csa_chandef, 0,
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
-@@ -521,7 +521,7 @@ static void ieee80211_do_stop(struct iee
+@@ -542,7 +542,7 @@ static void ieee80211_do_stop(struct iee
cancel_work_sync(&sdata->recalc_smps);
sdata_lock(sdata);
"destroying interface with valid links 0x%04x\n",
sdata->vif.valid_links);
-@@ -1834,7 +1834,7 @@ static int ieee80211_runtime_change_ifty
+@@ -1855,7 +1855,7 @@ static int ieee80211_runtime_change_ifty
return -EBUSY;
/* for now, don't support changing while links exist */
+++ /dev/null
-From 1b7c710a8e912d54a24742ed5a87a047be64141a Mon Sep 17 00:00:00 2001
-From: Rameshkumar Sundaram <quic_ramess@quicinc.com>
-Date: Tue, 7 Feb 2023 17:11:46 +0530
-Subject: [PATCH 350/351] wifi: mac80211: Allow NSS change only up to
- capability
-
-Stations can update bandwidth/NSS change in
-VHT action frame with action type Operating Mode Notification.
-(IEEE Std 802.11-2020 - 9.4.1.53 Operating Mode field)
-
-For Operating Mode Notification, an RX NSS change to a value
-greater than AP's maximum NSS should not be allowed.
-During fuzz testing, by forcefully sending VHT Op. mode notif.
-frames from STA with random rx_nss values, it is found that AP
-accepts rx_nss values greater that APs maximum NSS instead of
-discarding such NSS change.
-
-Hence allow NSS change only up to maximum NSS that is negotiated
-and capped to AP's capability during association.
-
-Signed-off-by: Rameshkumar Sundaram <quic_ramess@quicinc.com>
-Link: https://lore.kernel.org/r/20230207114146.10567-1-quic_ramess@quicinc.com
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-(cherry picked from commit 57b341e9ab13e5688491bfd54f8b5502416c8905)
----
- net/mac80211/vht.c | 25 ++++++++++++++++++++-----
- 1 file changed, 20 insertions(+), 5 deletions(-)
-
---- a/net/mac80211/vht.c
-+++ b/net/mac80211/vht.c
-@@ -637,7 +637,7 @@ u32 __ieee80211_vht_handle_opmode(struct
- enum ieee80211_sta_rx_bandwidth new_bw;
- struct sta_opmode_info sta_opmode = {};
- u32 changed = 0;
-- u8 nss;
-+ u8 nss, cur_nss;
-
- /* ignore - no support for BF yet */
- if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
-@@ -648,10 +648,25 @@ u32 __ieee80211_vht_handle_opmode(struct
- nss += 1;
-
- if (link_sta->pub->rx_nss != nss) {
-- link_sta->pub->rx_nss = nss;
-- sta_opmode.rx_nss = nss;
-- changed |= IEEE80211_RC_NSS_CHANGED;
-- sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
-+ cur_nss = link_sta->pub->rx_nss;
-+ /* Reset rx_nss and call ieee80211_sta_set_rx_nss() which
-+ * will set the same to max nss value calculated based on capability.
-+ */
-+ link_sta->pub->rx_nss = 0;
-+ ieee80211_sta_set_rx_nss(link_sta);
-+ /* Do not allow an nss change to rx_nss greater than max_nss
-+ * negotiated and capped to APs capability during association.
-+ */
-+ if (nss <= link_sta->pub->rx_nss) {
-+ link_sta->pub->rx_nss = nss;
-+ sta_opmode.rx_nss = nss;
-+ changed |= IEEE80211_RC_NSS_CHANGED;
-+ sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
-+ } else {
-+ link_sta->pub->rx_nss = cur_nss;
-+ pr_warn_ratelimited("Ignoring NSS change in VHT Operating Mode Notification from %pM with invalid nss %d",
-+ link_sta->pub->addr, nss);
-+ }
- }
-
- switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
+++ /dev/null
-From 32d043fc10f1814e421c0ff90c0ee6b303f2821c Mon Sep 17 00:00:00 2001
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Wed, 28 Feb 2024 12:01:57 +0100
-Subject: [PATCH 351/351] wifi: mac80211: track capability/opmode NSS
- separately
-
-We're currently tracking rx_nss for each station, and that
-is meant to be initialized to the capability NSS and later
-reduced by the operating mode notification NSS.
-
-However, we're mixing up capabilities and operating mode
-NSS in the same variable. This forces us to recalculate
-the NSS capability on operating mode notification RX,
-which is a bit strange; due to the previous fix I had to
-never keep rx_nss as zero, it also means that the capa is
-never taken into account properly.
-
-Fix all this by storing the capability value, that can be
-recalculated unconditionally whenever needed, and storing
-the operating mode notification NSS separately, taking it
-into account when assigning the final rx_nss value.
-
-Cc: stable@vger.kernel.org
-Fixes: dd6c064cfc3f ("wifi: mac80211: set station RX-NSS on reconfig")
-Reviewed-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
-Link: https://msgid.link/20240228120157.0e1c41924d1d.I0acaa234e0267227b7e3ef81a59117c8792116bc@changeid
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-(cherry picked from commit a8bca3e9371dc5e276af4168be099b2a05554c2a)
----
- net/mac80211/cfg.c | 2 +-
- net/mac80211/ieee80211_i.h | 2 +-
- net/mac80211/rate.c | 2 +-
- net/mac80211/sta_info.h | 6 ++++-
- net/mac80211/vht.c | 46 ++++++++++++++++++--------------------
- 5 files changed, 30 insertions(+), 28 deletions(-)
-
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1836,7 +1836,7 @@ static int sta_link_apply_parameters(str
- sband->band);
- }
-
-- ieee80211_sta_set_rx_nss(link_sta);
-+ ieee80211_sta_init_nss(link_sta);
-
- return ret;
- }
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -2103,7 +2103,7 @@ enum ieee80211_sta_rx_bandwidth
- ieee80211_sta_cap_rx_bw(struct link_sta_info *link_sta);
- enum ieee80211_sta_rx_bandwidth
- ieee80211_sta_cur_vht_bw(struct link_sta_info *link_sta);
--void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta);
-+void ieee80211_sta_init_nss(struct link_sta_info *link_sta);
- enum ieee80211_sta_rx_bandwidth
- ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width);
- enum nl80211_chan_width
---- a/net/mac80211/rate.c
-+++ b/net/mac80211/rate.c
-@@ -37,7 +37,7 @@ void rate_control_rate_init(struct sta_i
- struct ieee80211_supported_band *sband;
- struct ieee80211_chanctx_conf *chanctx_conf;
-
-- ieee80211_sta_set_rx_nss(&sta->deflink);
-+ ieee80211_sta_init_nss(&sta->deflink);
-
- if (!ref)
- return;
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -3,7 +3,7 @@
- * Copyright 2002-2005, Devicescape Software, Inc.
- * Copyright 2013-2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015-2017 Intel Deutschland GmbH
-- * Copyright(c) 2020-2022 Intel Corporation
-+ * Copyright(c) 2020-2024 Intel Corporation
- */
-
- #ifndef STA_INFO_H
-@@ -485,6 +485,8 @@ struct ieee80211_fragment_cache {
- * same for non-MLD STA. This is used as key for searching link STA
- * @link_id: Link ID uniquely identifying the link STA. This is 0 for non-MLD
- * and set to the corresponding vif LinkId for MLD STA
-+ * @op_mode_nss: NSS limit as set by operating mode notification, or 0
-+ * @capa_nss: NSS limit as determined by local and peer capabilities
- * @link_hash_node: hash node for rhashtable
- * @sta: Points to the STA info
- * @gtk: group keys negotiated with this station, if any
-@@ -520,6 +522,8 @@ struct link_sta_info {
- u8 addr[ETH_ALEN];
- u8 link_id;
-
-+ u8 op_mode_nss, capa_nss;
-+
- struct rhlist_head link_hash_node;
-
- struct sta_info *sta;
---- a/net/mac80211/vht.c
-+++ b/net/mac80211/vht.c
-@@ -4,7 +4,7 @@
- *
- * Portions of this file
- * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
-- * Copyright (C) 2018 - 2023 Intel Corporation
-+ * Copyright (C) 2018 - 2024 Intel Corporation
- */
-
- #include <linux/ieee80211.h>
-@@ -541,15 +541,11 @@ ieee80211_sta_cur_vht_bw(struct link_sta
- return bw;
- }
-
--void ieee80211_sta_set_rx_nss(struct link_sta_info *link_sta)
-+void ieee80211_sta_init_nss(struct link_sta_info *link_sta)
- {
- u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, eht_rx_nss = 0, rx_nss;
- bool support_160;
-
-- /* if we received a notification already don't overwrite it */
-- if (link_sta->pub->rx_nss)
-- return;
--
- if (link_sta->pub->eht_cap.has_eht) {
- int i;
- const u8 *rx_nss_mcs = (void *)&link_sta->pub->eht_cap.eht_mcs_nss_supp;
-@@ -627,7 +623,15 @@ void ieee80211_sta_set_rx_nss(struct lin
- rx_nss = max(vht_rx_nss, ht_rx_nss);
- rx_nss = max(he_rx_nss, rx_nss);
- rx_nss = max(eht_rx_nss, rx_nss);
-- link_sta->pub->rx_nss = max_t(u8, 1, rx_nss);
-+ rx_nss = max_t(u8, 1, rx_nss);
-+ link_sta->capa_nss = rx_nss;
-+
-+ /* that shouldn't be set yet, but we can handle it anyway */
-+ if (link_sta->op_mode_nss)
-+ link_sta->pub->rx_nss =
-+ min_t(u8, rx_nss, link_sta->op_mode_nss);
-+ else
-+ link_sta->pub->rx_nss = rx_nss;
- }
-
- u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
-@@ -637,7 +641,7 @@ u32 __ieee80211_vht_handle_opmode(struct
- enum ieee80211_sta_rx_bandwidth new_bw;
- struct sta_opmode_info sta_opmode = {};
- u32 changed = 0;
-- u8 nss, cur_nss;
-+ u8 nss;
-
- /* ignore - no support for BF yet */
- if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
-@@ -647,23 +651,17 @@ u32 __ieee80211_vht_handle_opmode(struct
- nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
- nss += 1;
-
-- if (link_sta->pub->rx_nss != nss) {
-- cur_nss = link_sta->pub->rx_nss;
-- /* Reset rx_nss and call ieee80211_sta_set_rx_nss() which
-- * will set the same to max nss value calculated based on capability.
-- */
-- link_sta->pub->rx_nss = 0;
-- ieee80211_sta_set_rx_nss(link_sta);
-- /* Do not allow an nss change to rx_nss greater than max_nss
-- * negotiated and capped to APs capability during association.
-- */
-- if (nss <= link_sta->pub->rx_nss) {
-- link_sta->pub->rx_nss = nss;
-- sta_opmode.rx_nss = nss;
-- changed |= IEEE80211_RC_NSS_CHANGED;
-- sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
-+ if (link_sta->op_mode_nss != nss) {
-+ if (nss <= link_sta->capa_nss) {
-+ link_sta->op_mode_nss = nss;
-+
-+ if (nss != link_sta->pub->rx_nss) {
-+ link_sta->pub->rx_nss = nss;
-+ changed |= IEEE80211_RC_NSS_CHANGED;
-+ sta_opmode.rx_nss = link_sta->pub->rx_nss;
-+ sta_opmode.changed |= STA_OPMODE_N_SS_CHANGED;
-+ }
- } else {
-- link_sta->pub->rx_nss = cur_nss;
- pr_warn_ratelimited("Ignoring NSS change in VHT Operating Mode Notification from %pM with invalid nss %d",
- link_sta->pub->addr, nss);
- }
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
-@@ -3078,6 +3078,19 @@ static int ieee80211_get_tx_power(struct
+@@ -3079,6 +3079,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
static void ieee80211_rfkill_poll(struct wiphy *wiphy)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
-@@ -5008,6 +5021,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -5009,6 +5022,7 @@ const struct cfg80211_ops mac80211_confi
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
local->hw.max_mtu = IEEE80211_MAX_DATA_LEN;
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
-@@ -820,6 +820,7 @@ static const struct nla_policy nl80211_p
+@@ -830,6 +830,7 @@ static const struct nla_policy nl80211_p
[NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT },
[NL80211_ATTR_PUNCT_BITMAP] = NLA_POLICY_RANGE(NLA_U8, 0, 0xffff),
};
/* policy for the key attributes */
-@@ -3547,6 +3548,22 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -3584,6 +3585,22 @@ static int nl80211_set_wiphy(struct sk_b
if (result)
goto out;
}
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
-@@ -2368,6 +2368,13 @@ static void sta_stats_decode_rate(struct
+@@ -2382,6 +2382,13 @@ static void sta_stats_decode_rate(struct
sband = local->hw.wiphy->bands[band];