iwlwifi: mvm: don't hide HE radiotap data in SKB
authorJohannes Berg <johannes.berg@intel.com>
Mon, 10 Dec 2018 09:36:29 +0000 (10:36 +0100)
committerLuca Coelho <luciano.coelho@intel.com>
Mon, 4 Feb 2019 10:28:07 +0000 (12:28 +0200)
Hiding the HE radiotap data for further processing of the SKB just
caused another bug when adding the L-SIG data. Simply stop doing
this and adjust the skb->data pointer accordingly when we need to
get the 802.11 header.

While at it, also verify and fix the data alignment, we need to add
2 bytes padding with the vendor data to ensure the whole length of
all radiotap headers is a multiple of 4.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Fixes: 6721039d5b8a ("iwlwifi: mvm: add L-SIG length to radiotap")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c

index d2728fe6a0411d47645ccd1b6310fc7df2e25707..957d99932e8b27dffc172bcf0767b8d684d825a6 100644 (file)
 #include "mvm.h"
 #include "fw-api.h"
 
+static void *iwl_mvm_skb_get_hdr(struct sk_buff *skb)
+{
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+       u8 *data = skb->data;
+
+       /* Alignment concerns */
+       BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he) % 4);
+       BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_he_mu) % 4);
+       BUILD_BUG_ON(sizeof(struct ieee80211_radiotap_lsig) % 4);
+       BUILD_BUG_ON(sizeof(struct ieee80211_vendor_radiotap) % 4);
+
+       if (rx_status->flag & RX_FLAG_RADIOTAP_HE)
+               data += sizeof(struct ieee80211_radiotap_he);
+       if (rx_status->flag & RX_FLAG_RADIOTAP_HE_MU)
+               data += sizeof(struct ieee80211_radiotap_he_mu);
+       if (rx_status->flag & RX_FLAG_RADIOTAP_LSIG)
+               data += sizeof(struct ieee80211_radiotap_lsig);
+       if (rx_status->flag & RX_FLAG_RADIOTAP_VENDOR_DATA) {
+               struct ieee80211_vendor_radiotap *radiotap = (void *)data;
+
+               data += sizeof(*radiotap) + radiotap->len + radiotap->pad;
+       }
+
+       return data;
+}
+
 static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
                                   int queue, struct ieee80211_sta *sta)
 {
        struct iwl_mvm_sta *mvmsta;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb);
        struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
        struct iwl_mvm_key_pn *ptk_pn;
        int res;
@@ -197,12 +223,15 @@ static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
 {
        struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_vendor_radiotap *radiotap;
-       int size = sizeof(*radiotap) + sizeof(__le16);
+       const int size = sizeof(*radiotap) + sizeof(__le16);
 
        if (!mvm->cur_aid)
                return;
 
-       radiotap = skb_put(skb, size);
+       /* ensure alignment */
+       BUILD_BUG_ON((size + 2) % 4);
+
+       radiotap = skb_put(skb, size + 2);
        radiotap->align = 1;
        /* Intel OUI */
        radiotap->oui[0] = 0xf6;
@@ -212,10 +241,12 @@ static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
        radiotap->subns = 1;
        radiotap->present = 0x1;
        radiotap->len = size - sizeof(*radiotap);
-       radiotap->pad = 0;
+       radiotap->pad = 2;
 
        /* fill the data now */
        memcpy(radiotap->data, &mvm->cur_aid, sizeof(mvm->cur_aid));
+       /* and clear the padding */
+       memset(radiotap->data + sizeof(__le16), 0, radiotap->pad);
 
        rx_status->flag |= RX_FLAG_RADIOTAP_VENDOR_DATA;
 }
@@ -663,7 +694,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
                            struct sk_buff *skb,
                            struct iwl_rx_mpdu_desc *desc)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb);
        struct iwl_mvm_sta *mvm_sta;
        struct iwl_mvm_baid_data *baid_data;
        struct iwl_mvm_reorder_buffer *buffer;
@@ -1174,22 +1205,16 @@ static void iwl_mvm_rx_he(struct iwl_mvm *mvm, struct sk_buff *skb,
                .flags2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN |
                                      IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
        };
-       unsigned int radiotap_len = 0;
 
        he = skb_put_data(skb, &known, sizeof(known));
-       radiotap_len += sizeof(known);
        rx_status->flag |= RX_FLAG_RADIOTAP_HE;
 
        if (phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU ||
            phy_data->info_type == IWL_RX_PHY_INFO_TYPE_HE_MU_EXT) {
                he_mu = skb_put_data(skb, &mu_known, sizeof(mu_known));
-               radiotap_len += sizeof(mu_known);
                rx_status->flag |= RX_FLAG_RADIOTAP_HE_MU;
        }
 
-       /* temporarily hide the radiotap data */
-       __skb_pull(skb, radiotap_len);
-
        /* report the AMPDU-EOF bit on single frames */
        if (!queue && !(phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
                rx_status->flag |= RX_FLAG_AMPDU_DETAILS;