From e3e0ca32cf478e78c579b02cd9c1657d93c97add Mon Sep 17 00:00:00 2001 From: Aloka Dixit Date: Mon, 10 Apr 2023 13:03:32 -0700 Subject: wifi: mac80211: set EHT support flag in AP mode Set 'eht_support' flag if EHT capabilities are present. Signed-off-by: Aloka Dixit Link: https://lore.kernel.org/r/20230410200332.32265-1-quic_alokad@quicinc.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 473915606715..7317e4a5d1ff 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1342,6 +1342,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, } if (params->eht_cap) { + if (!link_conf->he_support) + return -EOPNOTSUPP; + + link_conf->eht_support = true; link_conf->eht_puncturing = params->punct_bitmap; changed |= BSS_CHANGED_EHT_PUNCTURING; -- cgit v1.2.3 From 2c9abe653bc5134eeab411c46dde008d8a1c37b0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Mar 2023 16:59:08 +0200 Subject: wifi: ieee80211: correctly mark FTM frames non-bufferable The checks of whether or not a frame is bufferable were not taking into account that some action frames aren't, such as FTM. Check this, which requires some changes to the function ieee80211_is_bufferable_mmpdu() since we need the whole skb for the checks now. Reviewed-by: Ilan Peer Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 7 ++-- drivers/net/wireless/mediatek/mt76/tx.c | 2 +- include/linux/ieee80211.h | 52 +++++++++++++++++++++-------- net/mac80211/tx.c | 4 +-- 4 files changed, 45 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 51f21cbf7a20..478442e16d43 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -604,8 +604,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 iwl_mvm_vif_link_info *link, struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr) + struct sk_buff *skb) { + struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; switch (info->control.vif->type) { @@ -622,7 +623,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 link->mgmt_queue; @@ -755,7 +756,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) sta_id = link->mcast_sta.sta_id; queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info, - hdr); + 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/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 1f309d05380a..3ad9742364ba 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -330,7 +330,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { + !ieee80211_is_bufferable_mmpdu(skb)) { qid = MT_TXQ_PSD; } diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 0583b2b0ce1f..c4cf296e7eaf 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -782,20 +782,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 @@ -4132,6 +4118,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/net/mac80211/tx.c b/net/mac80211/tx.c index dfe6b9c9b29e..1a3327407552 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -488,7 +488,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; } @@ -1323,7 +1323,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) { /* -- cgit v1.2.3 From 0b75a1b1e42e07ae84e3a11d2368b418546e2bec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Mar 2023 16:59:16 +0200 Subject: wifi: mac80211: flush queues on STA removal When we remove a station, we first make it unreachable, then we (must) remove its keys, and then remove the station itself. Depending on the hardware design, if we have hardware crypto at all, frames still sitting on hardware queues may then be transmitted without a valid key, possibly unencrypted or with a fixed key. Fix this by flushing the queues when removing stations so this cannot happen. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 941bda9141fa..ce7c3b997269 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1294,6 +1294,14 @@ 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) + ieee80211_flush_queues(local, sta->sdata, false); + /* now keys can no longer be reached */ ieee80211_free_sta_keys(local, sta); -- cgit v1.2.3 From d00800a289c9349bb659a698cbd7bc04521dc927 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 31 Mar 2023 16:59:17 +0200 Subject: wifi: mac80211: add flush_sta method Some drivers like iwlwifi might have per-STA queues, so we may want to flush/drop just those queues rather than all when removing a station. Add a separate method for that. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 6 ++++++ net/mac80211/driver-ops.h | 15 +++++++++++++++ net/mac80211/sta_info.c | 8 ++++++-- net/mac80211/trace.h | 7 +++++++ 4 files changed, 34 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 679421d37a42..a8dadbd83d95 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3950,6 +3950,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 @@ -4415,6 +4419,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); diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 0bf208f5bbc5..45d3e53c7383 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -649,6 +649,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) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ce7c3b997269..1400512e0dde 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1299,8 +1299,12 @@ static void __sta_info_destroy_part2(struct sta_info *sta) * frames sitting on hardware queues might be sent out without * any encryption at all. */ - if (local->ops->set_key) - ieee80211_flush_queues(local, sta->sdata, false); + 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); diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index e0ccf5fe708a..de5d69f21306 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1177,6 +1177,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, -- cgit v1.2.3 From 9ae708f00161e1d789268fa9cc05bf6bec2af474 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 17 Apr 2023 15:37:51 +0200 Subject: wifi: mac80211: remove ieee80211_tx_status_8023 It is unused and should not be used. In order to avoid limitations in 4-address mode, the driver should always use ieee80211_tx_status_ext for 802.3 frames with a valid sta pointer. Signed-off-by: Felix Fietkau Link: https://lore.kernel.org/r/20230417133751.79160-1-nbd@nbd.name Signed-off-by: Johannes Berg --- include/net/mac80211.h | 20 -------------------- net/mac80211/status.c | 24 ------------------------ 2 files changed, 44 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a8dadbd83d95..ac0370e76874 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -5215,26 +5215,6 @@ static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw, void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); -/** - * ieee80211_tx_status_8023 - transmit status callback for 802.3 frame format - * - * Call this function for all transmitted data frames after their transmit - * completion. This callback should only be called for data frames which - * are using driver's (or hardware's) offload capability of encap/decap - * 802.11 frames. - * - * This function may not be called in IRQ context. Calls to this function - * for a single hardware must be synchronized against each other and all - * calls in the same tx status family. - * - * @hw: the hardware the frame was transmitted by - * @vif: the interface for which the frame was transmitted - * @skb: the frame that was transmitted, owned by mac80211 after this call - */ -void ieee80211_tx_status_8023(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct sk_buff *skb); - /** * ieee80211_report_low_ack - report non-responding station * diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3f9ddd7f04b6..2b13a52ce96c 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -1244,30 +1244,6 @@ void ieee80211_tx_rate_update(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_tx_rate_update); -void ieee80211_tx_status_8023(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct sk_buff *skb) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_status status = { - .skb = skb, - .info = IEEE80211_SKB_CB(skb), - }; - struct sta_info *sta; - - sdata = vif_to_sdata(vif); - - rcu_read_lock(); - - if (!ieee80211_lookup_ra_sta(sdata, skb, &sta) && !IS_ERR(sta)) - status.sta = &sta->sta; - - ieee80211_tx_status_ext(hw, &status); - - rcu_read_unlock(); -} -EXPORT_SYMBOL(ieee80211_tx_status_8023); - void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) { struct sta_info *sta = container_of(pubsta, struct sta_info, sta); -- cgit v1.2.3 From eb74bfcfa99415f1a65ce021b8ac2256b7ed50bc Mon Sep 17 00:00:00 2001 From: Yingsha Xu Date: Wed, 19 Apr 2023 18:45:47 +0800 Subject: wifi: mac80211: remove return value check of debugfs_create_dir() Smatch complains that: debugfs_hw_add() warn: 'statsd' is an error pointer or valid Debugfs checks are generally not supposed to be checked for errors and it is not necessary here. Just delete the dead code. Signed-off-by: Yingsha Xu Reviewed-by: Dongliang Mu Link: https://lore.kernel.org/r/20230419104548.30124-1-ysxu@hust.edu.cn Signed-off-by: Johannes Berg --- net/mac80211/debugfs.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index dfb9f55e2685..207f772bd8ce 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -673,10 +673,6 @@ void debugfs_hw_add(struct ieee80211_local *local) statsd = debugfs_create_dir("statistics", phyd); - /* if the dir failed, don't put all the other things into the root! */ - if (!statsd) - return; - #ifdef CONFIG_MAC80211_DEBUG_COUNTERS DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount); DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount); -- cgit v1.2.3