--- /dev/null
+From 7eccb738fce57cbe53ed903ccf43f9ab257b15b3 Mon Sep 17 00:00:00 2001
+From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
+Date: Fri, 27 Oct 2017 18:35:31 +0300
+Subject: ath10k: rebuild crypto header in rx data frames
+
+From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
+
+commit 7eccb738fce57cbe53ed903ccf43f9ab257b15b3 upstream.
+
+Rx data frames notified through HTT_T2H_MSG_TYPE_RX_IND and
+HTT_T2H_MSG_TYPE_RX_FRAG_IND expect PN/TSC check to be done
+on host (mac80211) rather than firmware. Rebuild cipher header
+in every received data frames (that are notified through those
+HTT interfaces) from the rx_hdr_status tlv available in the
+rx descriptor of the first msdu. Skip setting RX_FLAG_IV_STRIPPED
+flag for the packets which requires mac80211 PN/TSC check support
+and set appropriate RX_FLAG for stripped crypto tail. Hw QCA988X,
+QCA9887, QCA99X0, QCA9984, QCA9888 and QCA4019 currently need the
+rebuilding of cipher header to perform PN/TSC check for replay
+attack.
+
+Please note that removing crypto tail for CCMP-256, GCMP and GCMP-256 ciphers
+in raw mode needs to be fixed. Since Rx with these ciphers in raw
+mode does not work in the current form even without this patch and
+removing crypto tail for these chipers needs clean up, raw mode related
+issues in CCMP-256, GCMP and GCMP-256 can be addressed in follow up
+patches.
+
+Tested-by: Manikanta Pubbisetty <mpubbise@qti.qualcomm.com>
+Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/ath/ath10k/htt_rx.c | 105 +++++++++++++++++++++++++-----
+ drivers/net/wireless/ath/ath10k/rx_desc.h | 3
+ 2 files changed, 92 insertions(+), 16 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
+@@ -548,6 +548,11 @@ static int ath10k_htt_rx_crypto_param_le
+ return IEEE80211_TKIP_IV_LEN;
+ case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2:
+ return IEEE80211_CCMP_HDR_LEN;
++ case HTT_RX_MPDU_ENCRYPT_AES_CCM256_WPA2:
++ return IEEE80211_CCMP_256_HDR_LEN;
++ case HTT_RX_MPDU_ENCRYPT_AES_GCMP_WPA2:
++ case HTT_RX_MPDU_ENCRYPT_AES_GCMP256_WPA2:
++ return IEEE80211_GCMP_HDR_LEN;
+ case HTT_RX_MPDU_ENCRYPT_WEP128:
+ case HTT_RX_MPDU_ENCRYPT_WAPI:
+ break;
+@@ -573,6 +578,11 @@ static int ath10k_htt_rx_crypto_tail_len
+ return IEEE80211_TKIP_ICV_LEN;
+ case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2:
+ return IEEE80211_CCMP_MIC_LEN;
++ case HTT_RX_MPDU_ENCRYPT_AES_CCM256_WPA2:
++ return IEEE80211_CCMP_256_MIC_LEN;
++ case HTT_RX_MPDU_ENCRYPT_AES_GCMP_WPA2:
++ case HTT_RX_MPDU_ENCRYPT_AES_GCMP256_WPA2:
++ return IEEE80211_GCMP_MIC_LEN;
+ case HTT_RX_MPDU_ENCRYPT_WEP128:
+ case HTT_RX_MPDU_ENCRYPT_WAPI:
+ break;
+@@ -1024,9 +1034,21 @@ static void ath10k_htt_rx_h_undecap_raw(
+ hdr = (void *)msdu->data;
+
+ /* Tail */
+- if (status->flag & RX_FLAG_IV_STRIPPED)
++ if (status->flag & RX_FLAG_IV_STRIPPED) {
+ skb_trim(msdu, msdu->len -
+ ath10k_htt_rx_crypto_tail_len(ar, enctype));
++ } else {
++ /* MIC */
++ if ((status->flag & RX_FLAG_MIC_STRIPPED) &&
++ enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
++ skb_trim(msdu, msdu->len - 8);
++
++ /* ICV */
++ if (status->flag & RX_FLAG_ICV_STRIPPED &&
++ enctype != HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
++ skb_trim(msdu, msdu->len -
++ ath10k_htt_rx_crypto_tail_len(ar, enctype));
++ }
+
+ /* MMIC */
+ if ((status->flag & RX_FLAG_MMIC_STRIPPED) &&
+@@ -1048,7 +1070,8 @@ static void ath10k_htt_rx_h_undecap_raw(
+ static void ath10k_htt_rx_h_undecap_nwifi(struct ath10k *ar,
+ struct sk_buff *msdu,
+ struct ieee80211_rx_status *status,
+- const u8 first_hdr[64])
++ const u8 first_hdr[64],
++ enum htt_rx_mpdu_encrypt_type enctype)
+ {
+ struct ieee80211_hdr *hdr;
+ struct htt_rx_desc *rxd;
+@@ -1056,6 +1079,7 @@ static void ath10k_htt_rx_h_undecap_nwif
+ u8 da[ETH_ALEN];
+ u8 sa[ETH_ALEN];
+ int l3_pad_bytes;
++ int bytes_aligned = ar->hw_params.decap_align_bytes;
+
+ /* Delivered decapped frame:
+ * [nwifi 802.11 header] <-- replaced with 802.11 hdr
+@@ -1084,6 +1108,14 @@ static void ath10k_htt_rx_h_undecap_nwif
+ /* push original 802.11 header */
+ hdr = (struct ieee80211_hdr *)first_hdr;
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
++
++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
++ memcpy(skb_push(msdu,
++ ath10k_htt_rx_crypto_param_len(ar, enctype)),
++ (void *)hdr + round_up(hdr_len, bytes_aligned),
++ ath10k_htt_rx_crypto_param_len(ar, enctype));
++ }
++
+ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+
+ /* original 802.11 header has a different DA and in
+@@ -1144,6 +1176,7 @@ static void ath10k_htt_rx_h_undecap_eth(
+ u8 sa[ETH_ALEN];
+ int l3_pad_bytes;
+ struct htt_rx_desc *rxd;
++ int bytes_aligned = ar->hw_params.decap_align_bytes;
+
+ /* Delivered decapped frame:
+ * [eth header] <-- replaced with 802.11 hdr & rfc1042/llc
+@@ -1172,6 +1205,14 @@ static void ath10k_htt_rx_h_undecap_eth(
+ /* push original 802.11 header */
+ hdr = (struct ieee80211_hdr *)first_hdr;
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
++
++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
++ memcpy(skb_push(msdu,
++ ath10k_htt_rx_crypto_param_len(ar, enctype)),
++ (void *)hdr + round_up(hdr_len, bytes_aligned),
++ ath10k_htt_rx_crypto_param_len(ar, enctype));
++ }
++
+ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+
+ /* original 802.11 header has a different DA and in
+@@ -1185,12 +1226,14 @@ static void ath10k_htt_rx_h_undecap_eth(
+ static void ath10k_htt_rx_h_undecap_snap(struct ath10k *ar,
+ struct sk_buff *msdu,
+ struct ieee80211_rx_status *status,
+- const u8 first_hdr[64])
++ const u8 first_hdr[64],
++ enum htt_rx_mpdu_encrypt_type enctype)
+ {
+ struct ieee80211_hdr *hdr;
+ size_t hdr_len;
+ int l3_pad_bytes;
+ struct htt_rx_desc *rxd;
++ int bytes_aligned = ar->hw_params.decap_align_bytes;
+
+ /* Delivered decapped frame:
+ * [amsdu header] <-- replaced with 802.11 hdr
+@@ -1206,6 +1249,14 @@ static void ath10k_htt_rx_h_undecap_snap
+
+ hdr = (struct ieee80211_hdr *)first_hdr;
+ hdr_len = ieee80211_hdrlen(hdr->frame_control);
++
++ if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
++ memcpy(skb_push(msdu,
++ ath10k_htt_rx_crypto_param_len(ar, enctype)),
++ (void *)hdr + round_up(hdr_len, bytes_aligned),
++ ath10k_htt_rx_crypto_param_len(ar, enctype));
++ }
++
+ memcpy(skb_push(msdu, hdr_len), hdr, hdr_len);
+ }
+
+@@ -1240,13 +1291,15 @@ static void ath10k_htt_rx_h_undecap(stru
+ is_decrypted);
+ break;
+ case RX_MSDU_DECAP_NATIVE_WIFI:
+- ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr);
++ ath10k_htt_rx_h_undecap_nwifi(ar, msdu, status, first_hdr,
++ enctype);
+ break;
+ case RX_MSDU_DECAP_ETHERNET2_DIX:
+ ath10k_htt_rx_h_undecap_eth(ar, msdu, status, first_hdr, enctype);
+ break;
+ case RX_MSDU_DECAP_8023_SNAP_LLC:
+- ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr);
++ ath10k_htt_rx_h_undecap_snap(ar, msdu, status, first_hdr,
++ enctype);
+ break;
+ }
+ }
+@@ -1289,7 +1342,8 @@ static void ath10k_htt_rx_h_csum_offload
+
+ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
+ struct sk_buff_head *amsdu,
+- struct ieee80211_rx_status *status)
++ struct ieee80211_rx_status *status,
++ bool fill_crypt_header)
+ {
+ struct sk_buff *first;
+ struct sk_buff *last;
+@@ -1299,7 +1353,6 @@ static void ath10k_htt_rx_h_mpdu(struct
+ enum htt_rx_mpdu_encrypt_type enctype;
+ u8 first_hdr[64];
+ u8 *qos;
+- size_t hdr_len;
+ bool has_fcs_err;
+ bool has_crypto_err;
+ bool has_tkip_err;
+@@ -1324,15 +1377,17 @@ static void ath10k_htt_rx_h_mpdu(struct
+ * decapped header. It'll be used for undecapping of each MSDU.
+ */
+ hdr = (void *)rxd->rx_hdr_status;
+- hdr_len = ieee80211_hdrlen(hdr->frame_control);
+- memcpy(first_hdr, hdr, hdr_len);
++ memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
+
+ /* Each A-MSDU subframe will use the original header as the base and be
+ * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
+ */
+ hdr = (void *)first_hdr;
+- qos = ieee80211_get_qos_ctl(hdr);
+- qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
++
++ if (ieee80211_is_data_qos(hdr->frame_control)) {
++ qos = ieee80211_get_qos_ctl(hdr);
++ qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
++ }
+
+ /* Some attention flags are valid only in the last MSDU. */
+ last = skb_peek_tail(amsdu);
+@@ -1379,9 +1434,14 @@ static void ath10k_htt_rx_h_mpdu(struct
+ status->flag |= RX_FLAG_DECRYPTED;
+
+ if (likely(!is_mgmt))
+- status->flag |= RX_FLAG_IV_STRIPPED |
+- RX_FLAG_MMIC_STRIPPED;
+-}
++ status->flag |= RX_FLAG_MMIC_STRIPPED;
++
++ if (fill_crypt_header)
++ status->flag |= RX_FLAG_MIC_STRIPPED |
++ RX_FLAG_ICV_STRIPPED;
++ else
++ status->flag |= RX_FLAG_IV_STRIPPED;
++ }
+
+ skb_queue_walk(amsdu, msdu) {
+ ath10k_htt_rx_h_csum_offload(msdu);
+@@ -1397,6 +1457,9 @@ static void ath10k_htt_rx_h_mpdu(struct
+ if (is_mgmt)
+ continue;
+
++ if (fill_crypt_header)
++ continue;
++
+ hdr = (void *)msdu->data;
+ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ }
+@@ -1407,6 +1470,9 @@ static void ath10k_htt_rx_h_deliver(stru
+ struct ieee80211_rx_status *status)
+ {
+ struct sk_buff *msdu;
++ struct sk_buff *first_subframe;
++
++ first_subframe = skb_peek(amsdu);
+
+ while ((msdu = __skb_dequeue(amsdu))) {
+ /* Setup per-MSDU flags */
+@@ -1415,6 +1481,13 @@ static void ath10k_htt_rx_h_deliver(stru
+ else
+ status->flag |= RX_FLAG_AMSDU_MORE;
+
++ if (msdu == first_subframe) {
++ first_subframe = NULL;
++ status->flag &= ~RX_FLAG_ALLOW_SAME_PN;
++ } else {
++ status->flag |= RX_FLAG_ALLOW_SAME_PN;
++ }
++
+ ath10k_process_rx(ar, status, msdu);
+ }
+ }
+@@ -1557,7 +1630,7 @@ static int ath10k_htt_rx_handle_amsdu(st
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
+ ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0);
+ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
+- ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status);
++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
+ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status);
+
+ return num_msdus;
+@@ -1892,7 +1965,7 @@ static int ath10k_htt_rx_in_ord_ind(stru
+ num_msdus += skb_queue_len(&amsdu);
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
+ ath10k_htt_rx_h_filter(ar, &amsdu, status);
+- ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
++ ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
+ ath10k_htt_rx_h_deliver(ar, &amsdu, status);
+ break;
+ case -EAGAIN:
+--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
++++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
+@@ -239,6 +239,9 @@ enum htt_rx_mpdu_encrypt_type {
+ HTT_RX_MPDU_ENCRYPT_WAPI = 5,
+ HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2 = 6,
+ HTT_RX_MPDU_ENCRYPT_NONE = 7,
++ HTT_RX_MPDU_ENCRYPT_AES_CCM256_WPA2 = 8,
++ HTT_RX_MPDU_ENCRYPT_AES_GCMP_WPA2 = 9,
++ HTT_RX_MPDU_ENCRYPT_AES_GCMP256_WPA2 = 10,
+ };
+
+ #define RX_MPDU_START_INFO0_PEER_IDX_MASK 0x000007ff
--- /dev/null
+From fbc7c07ec23c040179384a1f16b62b6030eb6bdd Mon Sep 17 00:00:00 2001
+From: Suren Baghdasaryan <surenb@google.com>
+Date: Wed, 6 Dec 2017 09:27:30 -0800
+Subject: dm bufio: fix shrinker scans when (nr_to_scan < retain_target)
+
+From: Suren Baghdasaryan <surenb@google.com>
+
+commit fbc7c07ec23c040179384a1f16b62b6030eb6bdd upstream.
+
+When system is under memory pressure it is observed that dm bufio
+shrinker often reclaims only one buffer per scan. This change fixes
+the following two issues in dm bufio shrinker that cause this behavior:
+
+1. ((nr_to_scan - freed) <= retain_target) condition is used to
+terminate slab scan process. This assumes that nr_to_scan is equal
+to the LRU size, which might not be correct because do_shrink_slab()
+in vmscan.c calculates nr_to_scan using multiple inputs.
+As a result when nr_to_scan is less than retain_target (64) the scan
+will terminate after the first iteration, effectively reclaiming one
+buffer per scan and making scans very inefficient. This hurts vmscan
+performance especially because mutex is acquired/released every time
+dm_bufio_shrink_scan() is called.
+New implementation uses ((LRU size - freed) <= retain_target)
+condition for scan termination. LRU size can be safely determined
+inside __scan() because this function is called after dm_bufio_lock().
+
+2. do_shrink_slab() uses value returned by dm_bufio_shrink_count() to
+determine number of freeable objects in the slab. However dm_bufio
+always retains retain_target buffers in its LRU and will terminate
+a scan when this mark is reached. Therefore returning the entire LRU size
+from dm_bufio_shrink_count() is misleading because that does not
+represent the number of freeable objects that slab will reclaim during
+a scan. Returning (LRU size - retain_target) better represents the
+number of freeable objects in the slab. This way do_shrink_slab()
+returns 0 when (LRU size < retain_target) and vmscan will not try to
+scan this shrinker avoiding scans that will not reclaim any memory.
+
+Test: tested using Android device running
+<AOSP>/system/extras/alloc-stress that generates memory pressure
+and causes intensive shrinker scans
+
+Signed-off-by: Suren Baghdasaryan <surenb@google.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ drivers/md/dm-bufio.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/md/dm-bufio.c
++++ b/drivers/md/dm-bufio.c
+@@ -1554,7 +1554,8 @@ static unsigned long __scan(struct dm_bu
+ int l;
+ struct dm_buffer *b, *tmp;
+ unsigned long freed = 0;
+- unsigned long count = nr_to_scan;
++ unsigned long count = c->n_buffers[LIST_CLEAN] +
++ c->n_buffers[LIST_DIRTY];
+ unsigned long retain_target = get_retain_buffers(c);
+
+ for (l = 0; l < LIST_SIZE; l++) {
+@@ -1591,6 +1592,7 @@ dm_bufio_shrink_count(struct shrinker *s
+ {
+ struct dm_bufio_client *c;
+ unsigned long count;
++ unsigned long retain_target;
+
+ c = container_of(shrink, struct dm_bufio_client, shrinker);
+ if (sc->gfp_mask & __GFP_FS)
+@@ -1599,8 +1601,9 @@ dm_bufio_shrink_count(struct shrinker *s
+ return 0;
+
+ count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
++ retain_target = get_retain_buffers(c);
+ dm_bufio_unlock(c);
+- return count;
++ return (count < retain_target) ? 0 : (count - retain_target);
+ }
+
+ /*
--- /dev/null
+From cef0acd4d7d4811d2d19cd0195031bf0dfe41249 Mon Sep 17 00:00:00 2001
+From: David Spinadel <david.spinadel@intel.com>
+Date: Mon, 21 Nov 2016 16:58:40 +0200
+Subject: mac80211: Add RX flag to indicate ICV stripped
+
+From: David Spinadel <david.spinadel@intel.com>
+
+commit cef0acd4d7d4811d2d19cd0195031bf0dfe41249 upstream.
+
+Add a flag that indicates that the WEP ICV was stripped from an
+RX packet, allowing the device to not transfer that if it's
+already checked.
+
+Signed-off-by: David Spinadel <david.spinadel@intel.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Cc: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/net/mac80211.h | 5 ++++-
+ net/mac80211/wep.c | 3 ++-
+ net/mac80211/wpa.c | 3 ++-
+ 3 files changed, 8 insertions(+), 3 deletions(-)
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1007,7 +1007,7 @@ ieee80211_tx_info_clear_status(struct ie
+ * @RX_FLAG_DECRYPTED: This frame was decrypted in hardware.
+ * @RX_FLAG_MMIC_STRIPPED: the Michael MIC is stripped off this frame,
+ * verification has been done by the hardware.
+- * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame.
++ * @RX_FLAG_IV_STRIPPED: The IV and ICV are stripped from this frame.
+ * If this flag is set, the stack cannot do any replay detection
+ * hence the driver or hardware will have to do that.
+ * @RX_FLAG_PN_VALIDATED: Currently only valid for CCMP/GCMP frames, this
+@@ -1078,6 +1078,8 @@ ieee80211_tx_info_clear_status(struct ie
+ * @RX_FLAG_ALLOW_SAME_PN: Allow the same PN as same packet before.
+ * This is used for AMSDU subframes which can have the same PN as
+ * the first subframe.
++ * @RX_FLAG_ICV_STRIPPED: The ICV is stripped from this frame. CRC checking must
++ * be done in the hardware.
+ */
+ enum mac80211_rx_flags {
+ RX_FLAG_MMIC_ERROR = BIT(0),
+@@ -1113,6 +1115,7 @@ enum mac80211_rx_flags {
+ RX_FLAG_RADIOTAP_VENDOR_DATA = BIT(31),
+ RX_FLAG_MIC_STRIPPED = BIT_ULL(32),
+ RX_FLAG_ALLOW_SAME_PN = BIT_ULL(33),
++ RX_FLAG_ICV_STRIPPED = BIT_ULL(34),
+ };
+
+ #define RX_FLAG_STBC_SHIFT 26
+--- a/net/mac80211/wep.c
++++ b/net/mac80211/wep.c
+@@ -293,7 +293,8 @@ ieee80211_crypto_wep_decrypt(struct ieee
+ return RX_DROP_UNUSABLE;
+ ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
+ /* remove ICV */
+- if (pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
++ if (!(status->flag & RX_FLAG_ICV_STRIPPED) &&
++ pskb_trim(rx->skb, rx->skb->len - IEEE80211_WEP_ICV_LEN))
+ return RX_DROP_UNUSABLE;
+ }
+
+--- a/net/mac80211/wpa.c
++++ b/net/mac80211/wpa.c
+@@ -295,7 +295,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
+ return RX_DROP_UNUSABLE;
+
+ /* Trim ICV */
+- skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
++ if (!(status->flag & RX_FLAG_ICV_STRIPPED))
++ skb_trim(skb, skb->len - IEEE80211_TKIP_ICV_LEN);
+
+ /* Remove IV */
+ memmove(skb->data + IEEE80211_TKIP_IV_LEN, skb->data, hdrlen);