developer | a143290 | 2023-04-01 04:45:58 +0800 | [diff] [blame] | 1 | From: Johannes Berg <johannes.berg@intel.com> |
| 2 | Date: Wed, 29 Mar 2023 16:46:26 +0200 |
| 3 | Subject: [PATCH] wifi: ieee80211: correctly mark FTM frames non-bufferable |
| 4 | |
| 5 | The checks of whether or not a frame is bufferable were not |
| 6 | taking into account that some action frames aren't, such as |
| 7 | FTM. Check this, which requires some changes to the function |
| 8 | ieee80211_is_bufferable_mmpdu() since we need the whole skb |
| 9 | for the checks now. |
| 10 | |
| 11 | Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| 12 | Reviewed-by: Greenman, Gregory <gregory.greenman@intel.com> |
| 13 | Reviewed-by: Peer, Ilan <ilan.peer@intel.com> |
| 14 | --- |
| 15 | |
| 16 | --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c |
| 17 | +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c |
| 18 | @@ -551,8 +551,9 @@ static void iwl_mvm_skb_prepare_status(s |
| 19 | |
| 20 | static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, |
| 21 | struct ieee80211_tx_info *info, |
| 22 | - struct ieee80211_hdr *hdr) |
| 23 | + struct sk_buff *skb) |
| 24 | { |
| 25 | + struct ieee80211_hdr *hdr = (void *)skb->data; |
| 26 | struct iwl_mvm_vif *mvmvif = |
| 27 | iwl_mvm_vif_from_mac80211(info->control.vif); |
| 28 | __le16 fc = hdr->frame_control; |
| 29 | @@ -571,7 +572,7 @@ static int iwl_mvm_get_ctrl_vif_queue(st |
| 30 | * reason 7 ("Class 3 frame received from nonassociated STA"). |
| 31 | */ |
| 32 | if (ieee80211_is_mgmt(fc) && |
| 33 | - (!ieee80211_is_bufferable_mmpdu(fc) || |
| 34 | + (!ieee80211_is_bufferable_mmpdu(skb) || |
| 35 | ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc))) |
| 36 | return mvm->probe_queue; |
| 37 | |
| 38 | @@ -689,7 +690,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mv |
| 39 | else |
| 40 | sta_id = mvmvif->mcast_sta.sta_id; |
| 41 | |
| 42 | - queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr); |
| 43 | + queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, skb); |
| 44 | } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { |
| 45 | queue = mvm->snif_queue; |
| 46 | sta_id = mvm->snif_sta.sta_id; |
| 47 | --- a/include/linux/ieee80211.h |
| 48 | +++ b/include/linux/ieee80211.h |
| 49 | @@ -738,20 +738,6 @@ static inline bool ieee80211_is_any_null |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | - * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU |
| 54 | - * @fc: frame control field in little-endian byteorder |
| 55 | - */ |
| 56 | -static inline bool ieee80211_is_bufferable_mmpdu(__le16 fc) |
| 57 | -{ |
| 58 | - /* IEEE 802.11-2012, definition of "bufferable management frame"; |
| 59 | - * note that this ignores the IBSS special case. */ |
| 60 | - return ieee80211_is_mgmt(fc) && |
| 61 | - (ieee80211_is_action(fc) || |
| 62 | - ieee80211_is_disassoc(fc) || |
| 63 | - ieee80211_is_deauth(fc)); |
| 64 | -} |
| 65 | - |
| 66 | -/** |
| 67 | * ieee80211_is_first_frag - check if IEEE80211_SCTL_FRAG is not set |
| 68 | * @seq_ctrl: frame sequence control bytes in little-endian byteorder |
| 69 | */ |
| 70 | @@ -3672,6 +3658,44 @@ static inline u8 *ieee80211_get_DA(struc |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | + * ieee80211_is_bufferable_mmpdu - check if frame is bufferable MMPDU |
| 75 | + * @skb: the skb to check, starting with the 802.11 header |
| 76 | + */ |
| 77 | +static inline bool ieee80211_is_bufferable_mmpdu(struct sk_buff *skb) |
| 78 | +{ |
| 79 | + struct ieee80211_mgmt *mgmt = (void *)skb->data; |
| 80 | + __le16 fc = mgmt->frame_control; |
| 81 | + |
| 82 | + /* |
| 83 | + * IEEE 802.11 REVme D2.0 definition of bufferable MMPDU; |
| 84 | + * note that this ignores the IBSS special case. |
| 85 | + */ |
| 86 | + if (!ieee80211_is_mgmt(fc)) |
| 87 | + return false; |
| 88 | + |
| 89 | + if (ieee80211_is_disassoc(fc) || ieee80211_is_deauth(fc)) |
| 90 | + return true; |
| 91 | + |
| 92 | + if (!ieee80211_is_action(fc)) |
| 93 | + return false; |
| 94 | + |
| 95 | + if (skb->len < offsetofend(typeof(*mgmt), u.action.u.ftm.action_code)) |
| 96 | + return true; |
| 97 | + |
| 98 | + /* action frame - additionally check for non-bufferable FTM */ |
| 99 | + |
| 100 | + if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC && |
| 101 | + mgmt->u.action.category != WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION) |
| 102 | + return true; |
| 103 | + |
| 104 | + if (mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM_REQUEST || |
| 105 | + mgmt->u.action.u.ftm.action_code == WLAN_PUB_ACTION_FTM) |
| 106 | + return false; |
| 107 | + |
| 108 | + return true; |
| 109 | +} |
| 110 | + |
| 111 | +/** |
| 112 | * _ieee80211_is_robust_mgmt_frame - check if frame is a robust management frame |
| 113 | * @hdr: the frame (buffer must include at least the first octet of payload) |
| 114 | */ |
| 115 | --- a/net/mac80211/tx.c |
| 116 | +++ b/net/mac80211/tx.c |
| 117 | @@ -487,7 +487,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee |
| 118 | int ac = skb_get_queue_mapping(tx->skb); |
| 119 | |
| 120 | if (ieee80211_is_mgmt(hdr->frame_control) && |
| 121 | - !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) { |
| 122 | + !ieee80211_is_bufferable_mmpdu(tx->skb)) { |
| 123 | info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER; |
| 124 | return TX_CONTINUE; |
| 125 | } |
| 126 | @@ -1282,7 +1282,7 @@ static struct txq_info *ieee80211_get_tx |
| 127 | if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && |
| 128 | unlikely(!ieee80211_is_data_present(hdr->frame_control))) { |
| 129 | if ((!ieee80211_is_mgmt(hdr->frame_control) || |
| 130 | - ieee80211_is_bufferable_mmpdu(hdr->frame_control) || |
| 131 | + ieee80211_is_bufferable_mmpdu(skb) || |
| 132 | vif->type == NL80211_IFTYPE_STATION) && |
| 133 | sta && sta->uploaded) { |
| 134 | /* |