mac80211: fix HT-Control field reception for management frames
If we receive management frames with an HT-Control field, we cannot parse them properly, as we assume a fixed length management header. Since we don't even need the HTC field (for these frames, or really at all), just remove it at the beginning of RX. Reported-by: Haggai Abramovsky <haggai.abramovsky@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Link: https://lore.kernel.org/r/20200526143346.cf5ce70521c5.I333251a084ec4cfe67b7ef7efe2d2f1a33883931@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
1b9ae0c929
commit
c112992433
@ -93,13 +93,44 @@ static u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
|
||||
* This function cleans up the SKB, i.e. it removes all the stuff
|
||||
* only useful for monitoring.
|
||||
*/
|
||||
static void remove_monitor_info(struct sk_buff *skb,
|
||||
unsigned int present_fcs_len,
|
||||
unsigned int rtap_space)
|
||||
static struct sk_buff *ieee80211_clean_skb(struct sk_buff *skb,
|
||||
unsigned int present_fcs_len,
|
||||
unsigned int rtap_space)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
unsigned int hdrlen;
|
||||
__le16 fc;
|
||||
|
||||
if (present_fcs_len)
|
||||
__pskb_trim(skb, skb->len - present_fcs_len);
|
||||
__pskb_pull(skb, rtap_space);
|
||||
|
||||
hdr = (void *)skb->data;
|
||||
fc = hdr->frame_control;
|
||||
|
||||
/*
|
||||
* Remove the HT-Control field (if present) on management
|
||||
* frames after we've sent the frame to monitoring. We
|
||||
* (currently) don't need it, and don't properly parse
|
||||
* frames with it present, due to the assumption of a
|
||||
* fixed management header length.
|
||||
*/
|
||||
if (likely(!ieee80211_is_mgmt(fc) || !ieee80211_has_order(fc)))
|
||||
return skb;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(fc);
|
||||
hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_ORDER);
|
||||
|
||||
if (!pskb_may_pull(skb, hdrlen)) {
|
||||
dev_kfree_skb(skb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memmove(skb->data + IEEE80211_HT_CTL_LEN, skb->data,
|
||||
hdrlen - IEEE80211_HT_CTL_LEN);
|
||||
__pskb_pull(skb, IEEE80211_HT_CTL_LEN);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
|
||||
@ -827,8 +858,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
remove_monitor_info(origskb, present_fcs_len, rtap_space);
|
||||
return origskb;
|
||||
return ieee80211_clean_skb(origskb, present_fcs_len,
|
||||
rtap_space);
|
||||
}
|
||||
|
||||
ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_space);
|
||||
@ -871,8 +902,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
||||
if (!origskb)
|
||||
return NULL;
|
||||
|
||||
remove_monitor_info(origskb, present_fcs_len, rtap_space);
|
||||
return origskb;
|
||||
return ieee80211_clean_skb(origskb, present_fcs_len, rtap_space);
|
||||
}
|
||||
|
||||
static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
|
||||
|
Loading…
Reference in New Issue
Block a user