Merge remote-tracking branch 'scsi-queue/drivers-for-3.19' into for-linus
[cascardo/linux.git] / drivers / net / wireless / iwlwifi / mvm / rx.c
index 57052e6..94b6e72 100644 (file)
@@ -98,16 +98,25 @@ int iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
                                            struct sk_buff *skb,
                                            struct ieee80211_hdr *hdr, u16 len,
-                                           u32 ampdu_status,
+                                           u32 ampdu_status, u8 crypt_len,
                                            struct iwl_rx_cmd_buffer *rxb)
 {
        unsigned int hdrlen, fraglen;
 
        /* If frame is small enough to fit in skb->head, pull it completely.
-        * If not, only pull ieee80211_hdr so that splice() or TCP coalesce
-        * are more efficient.
+        * If not, only pull ieee80211_hdr (including crypto if present, and
+        * an additional 8 bytes for SNAP/ethertype, see below) so that
+        * splice() or TCP coalesce are more efficient.
+        *
+        * Since, in addition, ieee80211_data_to_8023() always pull in at
+        * least 8 bytes (possibly more for mesh) we can do the same here
+        * to save the cost of doing it later. That still doesn't pull in
+        * the actual IP header since the typical case has a SNAP header.
+        * If the latter changes (there are efforts in the standards group
+        * to do so) we should revisit this and ieee80211_data_to_8023().
         */
-       hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr);
+       hdrlen = (len <= skb_tailroom(skb)) ? len :
+                                             sizeof(*hdr) + crypt_len + 8;
 
        memcpy(skb_put(skb, hdrlen), hdr, hdrlen);
        fraglen = len - hdrlen;
@@ -174,7 +183,8 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
 static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
                                        struct ieee80211_hdr *hdr,
                                        struct ieee80211_rx_status *stats,
-                                       u32 rx_pkt_status)
+                                       u32 rx_pkt_status,
+                                       u8 *crypt_len)
 {
        if (!ieee80211_has_protected(hdr->frame_control) ||
            (rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
@@ -194,12 +204,14 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
 
                stats->flag |= RX_FLAG_DECRYPTED;
                IWL_DEBUG_WEP(mvm, "hw decrypted CCMP successfully\n");
+               *crypt_len = IEEE80211_CCMP_HDR_LEN;
                return 0;
 
        case RX_MPDU_RES_STATUS_SEC_TKIP_ENC:
                /* Don't drop the frame and decrypt it in SW */
                if (!(rx_pkt_status & RX_MPDU_RES_STATUS_TTAK_OK))
                        return 0;
+               *crypt_len = IEEE80211_TKIP_IV_LEN;
                /* fall through if TTAK OK */
 
        case RX_MPDU_RES_STATUS_SEC_WEP_ENC:
@@ -207,6 +219,9 @@ static u32 iwl_mvm_set_mac80211_rx_flag(struct iwl_mvm *mvm,
                        return -1;
 
                stats->flag |= RX_FLAG_DECRYPTED;
+               if ((rx_pkt_status & RX_MPDU_RES_STATUS_SEC_ENC_MSK) ==
+                               RX_MPDU_RES_STATUS_SEC_WEP_ENC)
+                       *crypt_len = IEEE80211_WEP_IV_LEN;
                return 0;
 
        case RX_MPDU_RES_STATUS_SEC_EXT_ENC:
@@ -241,6 +256,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        u32 ampdu_status;
        u32 rate_n_flags;
        u32 rx_pkt_status;
+       u8 crypt_len = 0;
 
        phy_info = &mvm->last_phy_info;
        rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
@@ -263,7 +279,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        /*
         * drop the packet if it has failed being decrypted by HW
         */
-       if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status)) {
+       if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status,
+                                        &crypt_len)) {
                IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",
                               rx_pkt_status);
                kfree_skb(skb);
@@ -393,7 +410,8 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
        iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags,
                                   rx_status->flag & RX_FLAG_AMPDU_DETAILS);
 #endif
-       iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status, rxb);
+       iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status,
+                                       crypt_len, rxb);
        return 0;
 }