diff --git a/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch index 62607cc..714d89e 100644 --- a/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch @@ -6,6 +6,103 @@ Date: Wed Sep 14 14:25:55 2022 +0200 %% original patch: 0002-backport-of-subsys-patches-from-openwrt.patch +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +index 8ff3330..2997959 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +@@ -4817,9 +4817,6 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, + return; + } + +- if (vif->type != NL80211_IFTYPE_STATION) +- return; +- + /* Make sure we're done with the deferred traffic before flushing */ + flush_work(&mvm->add_stream_wk); + +@@ -4837,9 +4834,6 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, + if (mvmsta->vif != vif) + continue; + +- /* make sure only TDLS peers or the AP are flushed */ +- WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls); +- + if (drop) { + if (iwl_mvm_flush_sta(mvm, mvmsta, false)) + IWL_ERR(mvm, "flush request fail\n"); +@@ -4859,6 +4853,31 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, + iwl_trans_wait_tx_queues_empty(mvm->trans, msk); + } + ++static void iwl_mvm_mac_flush_sta(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta) ++{ ++ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); ++ int i; ++ ++ mutex_lock(&mvm->mutex); ++ for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) { ++ struct iwl_mvm_sta *mvmsta; ++ struct ieee80211_sta *tmp; ++ ++ tmp = rcu_dereference_protected(mvm->fw_id_to_mac_id[i], ++ lockdep_is_held(&mvm->mutex)); ++ if (tmp != sta) ++ continue; ++ ++ mvmsta = iwl_mvm_sta_from_mac80211(sta); ++ ++ if (iwl_mvm_flush_sta(mvm, mvmsta, false)) ++ IWL_ERR(mvm, "flush request fail\n"); ++ } ++ mutex_unlock(&mvm->mutex); ++} ++ + static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) + { +@@ -5372,6 +5391,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { + .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, + .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, + .flush = iwl_mvm_mac_flush, ++ .flush_sta = iwl_mvm_mac_flush_sta, + .sched_scan_start = iwl_mvm_mac_sched_scan_start, + .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, + .set_key = iwl_mvm_mac_set_key, +diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +index 7beb203..d4c7d45 100644 +--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c ++++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +@@ -551,8 +551,9 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb, + + static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, + struct ieee80211_tx_info *info, +- struct ieee80211_hdr *hdr) ++ struct sk_buff *skb) + { ++ struct ieee80211_hdr *hdr = (void *)skb->data; + struct iwl_mvm_vif *mvmvif = + iwl_mvm_vif_from_mac80211(info->control.vif); + __le16 fc = hdr->frame_control; +@@ -571,7 +572,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, + * reason 7 ("Class 3 frame received from nonassociated STA"). + */ + if (ieee80211_is_mgmt(fc) && +- (!ieee80211_is_bufferable_mmpdu(fc) || ++ (!ieee80211_is_bufferable_mmpdu(skb) || + ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc))) + return mvm->probe_queue; + +@@ -689,7 +690,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) + else + sta_id = mvmvif->mcast_sta.sta_id; + +- queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr); ++ queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, skb); + } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { + queue = mvm->snif_queue; + sta_id = mvm->snif_sta.sta_id; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index bfc2b1f..ea0749c 100644 --- a/drivers/net/wireless/mac80211_hwsim.c @@ -80,6 +177,85 @@ index bfc2b1f..ea0749c 100644 rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); hdr = (void *)skb->data; +diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h +index 6942645..637e9fd 100644 +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -737,20 +737,6 @@ static inline bool ieee80211_is_any_nullfunc(__le16 fc) + return (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)); + } + +-/** +- * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU +- * @fc: frame control field in little-endian byteorder +- */ +-static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc) +-{ +- /* IEEE 802.11-2012, definition of "bufferable management frame"; +- * note that this ignores the IBSS special case. */ +- return ieee80211_is_mgmt(fc) && +- (ieee80211_is_action(fc) || +- ieee80211_is_disassoc(fc) || +- ieee80211_is_deauth(fc)); +-} +- + /** + * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set + * @seq_ctrl: frame sequence control bytes in little-endian byteorder +@@ -3188,7 +3174,7 @@ enum ieee80211_pub_actioncode { + WLAN_PUB_ACTION_NETWORK_CHANNEL_CONTROL = 30, + WLAN_PUB_ACTION_WHITE_SPACE_MAP_ANN = 31, + WLAN_PUB_ACTION_FTM_REQUEST = 32, +- WLAN_PUB_ACTION_FTM = 33, ++ WLAN_PUB_ACTION_FTM_RESPONSE = 33, + WLAN_PUB_ACTION_FILS_DISCOVERY = 34, + }; + +@@ -3667,6 +3653,44 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) + return hdr->addr1; + } + ++/** ++ * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU ++ * @skb: the skb to check, starting with the 802.11 header ++ */ ++static inline bool ieee80211_is_bufferable_mmpdu(struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)skb->data; ++ __le16 fc = mgmt->frame_control; ++ ++ /* ++ * IEEE 802.11 REVme D2.0 definition of bufferable MMPDU; ++ * note that this ignores the IBSS special case. ++ */ ++ if (!ieee80211_is_mgmt(fc)) ++ return false; ++ ++ if (ieee80211_is_disassoc(fc) || ieee80211_is_deauth(fc)) ++ return true; ++ ++ if (!ieee80211_is_action(fc)) ++ return false; ++ ++ if (skb->len < offsetofend(typeof(*mgmt), u.action.u.ftm.action_code)) ++ return true; ++ ++ /* action frame - additionally check for non-bufferable FTM */ ++ ++ if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && ++ mgmt->u.action.category != WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION) ++ return true; ++ ++ if (mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_REQUEST || ++ mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_RESPONSE) ++ return false; ++ ++ return true; ++} ++ + /** + * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame + * @hdr: the frame (buffer must include at least the first octet of payload) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 30c9ebd..ab83553 100644 --- a/include/net/cfg80211.h @@ -271,7 +447,7 @@ index 30c9ebd..ab83553 100644 /** * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying diff --git a/include/net/mac80211.h b/include/net/mac80211.h -index a331431..4c2760d 100644 +index a331431..7293174 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1566,6 +1566,7 @@ enum ieee80211_smps_mode { @@ -325,7 +501,18 @@ index a331431..4c2760d 100644 /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS -@@ -3937,6 +3946,16 @@ struct ieee80211_prep_tx_info { +@@ -3685,6 +3694,10 @@ struct ieee80211_prep_tx_info { + * Note that vif can be NULL. + * The callback can sleep. + * ++ * @flush_sta: Flush or drop all pending frames from the hardware queue(s) for ++ * the given station, as it's about to be removed. ++ * The callback can sleep. ++ * + * @channel_switch: Drivers that need (or want) to offload the channel + * switch operation for CSAs received from the AP may implement this + * callback. They must then call ieee80211_chswitch_done() to indicate +@@ -3937,6 +3950,16 @@ struct ieee80211_prep_tx_info { * twt structure. * @twt_teardown_request: Update the hw with TWT teardown request received * from the peer. @@ -342,7 +529,16 @@ index a331431..4c2760d 100644 */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, -@@ -4265,6 +4284,15 @@ struct ieee80211_ops { +@@ -4103,6 +4126,8 @@ struct ieee80211_ops { + #endif + void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); ++ void (*flush_sta)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta); + void (*channel_switch)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *ch_switch); +@@ -4265,6 +4290,15 @@ struct ieee80211_ops { struct ieee80211_twt_setup *twt); void (*twt_teardown_request)(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 flowid); @@ -358,7 +554,7 @@ index a331431..4c2760d 100644 }; /** -@@ -4916,12 +4944,14 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); +@@ -4916,12 +4950,14 @@ void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets * to countdown counters. This array can contain zero values which * should be ignored. @@ -373,7 +569,7 @@ index a331431..4c2760d 100644 }; /** -@@ -6642,6 +6672,9 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) +@@ -6642,6 +6678,9 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) { } @@ -383,7 +579,7 @@ index a331431..4c2760d 100644 /** * ieee80211_schedule_txq - schedule a TXQ for transmission * -@@ -6654,7 +6687,11 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) +@@ -6654,7 +6693,11 @@ static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac) * The driver may call this function if it has buffered packets for * this TXQ internally. */ @@ -396,7 +592,7 @@ index a331431..4c2760d 100644 /** * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() -@@ -6666,8 +6703,12 @@ void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); +@@ -6666,8 +6709,12 @@ void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); * The driver may set force=true if it has buffered packets for this TXQ * internally. */ @@ -1275,10 +1471,32 @@ index 8be28cf..afac8d4 100644 } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h -index 912c75d..bd1e46e 100644 +index 912c75d..5e10e24 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h -@@ -1486,4 +1486,28 @@ static inline void drv_twt_teardown_request(struct ieee80211_local *local, +@@ -639,6 +639,21 @@ static inline void drv_flush(struct ieee80211_local *local, + trace_drv_return_void(local); + } + ++static inline void drv_flush_sta(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta) ++{ ++ might_sleep(); ++ ++ if (sdata && !check_sdata_in_driver(sdata)) ++ return; ++ ++ trace_drv_flush_sta(local, sdata, &sta->sta); ++ if (local->ops->flush_sta) ++ local->ops->flush_sta(&local->hw, &sdata->vif, &sta->sta); ++ trace_drv_return_void(local); ++} ++ + static inline void drv_channel_switch(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_channel_switch *ch_switch) +@@ -1486,4 +1501,28 @@ static inline void drv_twt_teardown_request(struct ieee80211_local *local, trace_drv_return_void(local); } @@ -3219,7 +3437,7 @@ index 887f945..e692a24 100644 ieee80211_hw_config(local, 0); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c -index dccaf4b..d67dfdc 100644 +index dccaf4b..24a7d57 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, @@ -3247,7 +3465,26 @@ index dccaf4b..d67dfdc 100644 } for (i = 0; i < IEEE80211_NUM_TIDS; i++) -@@ -1888,59 +1893,29 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, +@@ -1065,6 +1070,18 @@ static void __sta_info_destroy_part2(struct sta_info *sta) + WARN_ON_ONCE(ret); + } + ++ /* Flush queues before removing keys, as that might remove them ++ * from hardware, and then depending on the offload method, any ++ * frames sitting on hardware queues might be sent out without ++ * any encryption at all. ++ */ ++ if (local->ops->set_key) { ++ if (local->ops->flush_sta) ++ drv_flush_sta(local, sta->sdata, sta); ++ else ++ ieee80211_flush_queues(local, sta->sdata, false); ++ } ++ + /* now keys can no longer be reached */ + ieee80211_free_sta_keys(local, sta); + +@@ -1888,59 +1905,29 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta, } EXPORT_SYMBOL(ieee80211_sta_set_buffered); @@ -3279,9 +3516,15 @@ index dccaf4b..d67dfdc 100644 - /* Weights scale so the unit weight is 256 */ - airtime <<= 8; -- ++ spin_lock_bh(&local->active_txq_lock[ac]); ++ sta->airtime[ac].tx_airtime += tx_airtime; ++ sta->airtime[ac].rx_airtime += rx_airtime; + - spin_lock_bh(&air_sched->lock); -- ++ diff = (u32)jiffies - sta->airtime[ac].last_active; ++ if (diff <= AIRTIME_ACTIVE_DURATION) ++ sta->airtime[ac].deficit -= airtime; + - air_info->tx_airtime += tx_airtime; - air_info->rx_airtime += rx_airtime; - @@ -3292,20 +3535,14 @@ index dccaf4b..d67dfdc 100644 - weight_sum = air_info->weight; - weight_sum_reciprocal = air_info->weight_reciprocal; - } -+ spin_lock_bh(&local->active_txq_lock[ac]); -+ sta->airtime[ac].tx_airtime += tx_airtime; -+ sta->airtime[ac].rx_airtime += rx_airtime; - +- - /* Round the calculation of global vt */ - air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) * - weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64; - air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) * - air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32; - ieee80211_resort_txq(&local->hw, txq); -+ diff = (u32)jiffies - sta->airtime[ac].last_active; -+ if (diff <= AIRTIME_ACTIVE_DURATION) -+ sta->airtime[ac].deficit -= airtime; - +- - spin_unlock_bh(&air_sched->lock); -} - @@ -3322,7 +3559,7 @@ index dccaf4b..d67dfdc 100644 } EXPORT_SYMBOL(ieee80211_sta_register_airtime); -@@ -1959,6 +1934,7 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, +@@ -1959,6 +1946,7 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, &sta->airtime[ac].aql_tx_pending); atomic_add(tx_airtime, &local->aql_total_pending_airtime); @@ -3330,7 +3567,7 @@ index dccaf4b..d67dfdc 100644 return; } -@@ -1970,14 +1946,17 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, +@@ -1970,14 +1958,17 @@ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, tx_pending, 0); } @@ -3351,7 +3588,7 @@ index dccaf4b..d67dfdc 100644 } int sta_info_move_state(struct sta_info *sta, -@@ -2384,7 +2363,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, +@@ -2384,7 +2375,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo, } if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { @@ -3608,10 +3845,24 @@ index 45e532a..137be9e 100644 } diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h -index 9e8381b..ffa1b7b 100644 +index 9e8381b..a564f54 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h -@@ -2892,6 +2892,15 @@ TRACE_EVENT(drv_twt_teardown_request, +@@ -1140,6 +1140,13 @@ TRACE_EVENT(drv_flush, + ) + ); + ++DEFINE_EVENT(sta_event, drv_flush_sta, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta), ++ TP_ARGS(local, sdata, sta) ++); ++ + TRACE_EVENT(drv_channel_switch, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, +@@ -2892,6 +2899,15 @@ TRACE_EVENT(drv_twt_teardown_request, ) ); @@ -3628,7 +3879,7 @@ index 9e8381b..ffa1b7b 100644 #undef TRACE_INCLUDE_PATH diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c -index 15888e4..50025ff 100644 +index 15888e4..9fc4e7b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -18,7 +18,6 @@ @@ -3639,6 +3890,24 @@ index 15888e4..50025ff 100644 #include #include #include +@@ -488,7 +487,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) + int ac = skb_get_queue_mapping(tx->skb); + + if (ieee80211_is_mgmt(hdr->frame_control) && +- !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { ++ !ieee80211_is_bufferable_mmpdu(tx->skb)) { + info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; + return TX_CONTINUE; + } +@@ -1283,7 +1282,7 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, + if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && + unlikely(!ieee80211_is_data_present(hdr->frame_control))) { + if ((!ieee80211_is_mgmt(hdr->frame_control) || +- ieee80211_is_bufferable_mmpdu(hdr->frame_control) || ++ ieee80211_is_bufferable_mmpdu(skb) || + vif->type == NL80211_IFTYPE_STATION) && + sta && sta->uploaded) { + /* @@ -1480,7 +1479,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, codel_vars_init(&txqi->def_cvars); codel_stats_init(&txqi->cstats);