Commit c1129924 authored by Johannes Berg's avatar Johannes Berg
Browse files

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: default avatarHaggai Abramovsky <haggai.abramovsky@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Link: https://lore.kernel.org/r/20200526143346.cf5ce70521c5.I333251a084ec4cfe67b7ef7efe2d2f1a33883931@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 1b9ae0c9
Loading
Loading
Loading
Loading
+37 −7
Original line number Diff line number Diff line
@@ -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,
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)