mac80211: Properly handle SKB with radiotap only

The monitor interface Rx handling of SKBs that contain only
radiotap information was buggy as it tried to access the
SKB assuming it contains a frame.

To fix this, check the RX_FLAG_NO_PSDU flag in the Rx status
(indicting that the SKB contains only radiotap information),
and do not perform data path specific processing when the flag
is set.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Ilan Peer 2018-12-15 11:03:17 +02:00 committed by Johannes Berg
parent 925b5978cd
commit 8020919a9b

View File

@ -753,6 +753,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
struct ieee80211_sub_if_data *monitor_sdata = struct ieee80211_sub_if_data *monitor_sdata =
rcu_dereference(local->monitor_sdata); rcu_dereference(local->monitor_sdata);
bool only_monitor = false; bool only_monitor = false;
unsigned int min_head_len;
if (status->flag & RX_FLAG_RADIOTAP_HE) if (status->flag & RX_FLAG_RADIOTAP_HE)
rtap_space += sizeof(struct ieee80211_radiotap_he); rtap_space += sizeof(struct ieee80211_radiotap_he);
@ -766,6 +767,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
rtap_space += sizeof(*rtap) + rtap->len + rtap->pad; rtap_space += sizeof(*rtap) + rtap->len + rtap->pad;
} }
min_head_len = rtap_space;
/* /*
* First, we may need to make a copy of the skb because * First, we may need to make a copy of the skb because
* (1) we need to modify it for radiotap (if not present), and * (1) we need to modify it for radiotap (if not present), and
@ -775,18 +778,23 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
* the SKB because it has a bad FCS/PLCP checksum. * the SKB because it has a bad FCS/PLCP checksum.
*/ */
if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) { if (!(status->flag & RX_FLAG_NO_PSDU)) {
if (unlikely(origskb->len <= FCS_LEN)) { if (ieee80211_hw_check(&local->hw, RX_INCLUDES_FCS)) {
/* driver bug */ if (unlikely(origskb->len <= FCS_LEN + rtap_space)) {
WARN_ON(1); /* driver bug */
dev_kfree_skb(origskb); WARN_ON(1);
return NULL; dev_kfree_skb(origskb);
return NULL;
}
present_fcs_len = FCS_LEN;
} }
present_fcs_len = FCS_LEN;
/* also consider the hdr->frame_control */
min_head_len += 2;
} }
/* ensure hdr->frame_control and vendor radiotap data are in skb head */ /* ensure that the expected data elements are in skb head */
if (!pskb_may_pull(origskb, 2 + rtap_space)) { if (!pskb_may_pull(origskb, min_head_len)) {
dev_kfree_skb(origskb); dev_kfree_skb(origskb);
return NULL; return NULL;
} }