1 From: Wen Gong <wgong@codeaurora.org>
2 Date: Tue, 11 May 2021 20:02:52 +0200
3 Subject: [PATCH] ath10k: add CCMP PN replay protection for fragmented
6 PN replay check for not fragmented frames is finished in the firmware,
7 but this was not done for fragmented frames when ath10k is used with
8 QCA6174/QCA6377 PCIe. mac80211 has the function
9 ieee80211_rx_h_defragment() for PN replay check for fragmented frames,
10 but this does not get checked with QCA6174 due to the
11 ieee80211_has_protected() condition not matching the cleared Protected
14 Validate the PN of received fragmented frames within ath10k when CCMP is
15 used and drop the fragment if the PN is not correct (incremented by
16 exactly one from the previous fragment). This applies only for
19 Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1
21 Cc: stable@vger.kernel.org
22 Signed-off-by: Wen Gong <wgong@codeaurora.org>
23 Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
24 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
27 --- a/drivers/net/wireless/ath/ath10k/htt.h
28 +++ b/drivers/net/wireless/ath/ath10k/htt.h
29 @@ -846,6 +846,7 @@ enum htt_security_types {
31 #define ATH10K_HTT_TXRX_PEER_SECURITY_MAX 2
32 #define ATH10K_TXRX_NUM_EXT_TIDS 19
33 +#define ATH10K_TXRX_NON_QOS_TID 16
35 enum htt_security_flags {
36 #define HTT_SECURITY_TYPE_MASK 0x7F
37 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c
38 +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
39 @@ -1746,16 +1746,87 @@ static void ath10k_htt_rx_h_csum_offload
40 msdu->ip_summed = ath10k_htt_rx_get_csum_state(msdu);
43 +static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb,
45 + enum htt_rx_mpdu_encrypt_type enctype)
47 + struct ieee80211_hdr *hdr;
51 + hdr = (struct ieee80211_hdr *)(skb->data + offset);
52 + ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control);
54 + if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) {
56 + pn |= (u64)ehdr[1] << 8;
57 + pn |= (u64)ehdr[4] << 16;
58 + pn |= (u64)ehdr[5] << 24;
59 + pn |= (u64)ehdr[6] << 32;
60 + pn |= (u64)ehdr[7] << 40;
65 +static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
66 + struct sk_buff *skb,
69 + enum htt_rx_mpdu_encrypt_type enctype)
71 + struct ath10k_peer *peer;
72 + union htt_rx_pn_t *last_pn, new_pn = {0};
73 + struct ieee80211_hdr *hdr;
75 + u8 tid, frag_number;
78 + peer = ath10k_peer_find_by_id(ar, peer_id);
80 + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n");
84 + hdr = (struct ieee80211_hdr *)(skb->data + offset);
85 + if (ieee80211_is_data_qos(hdr->frame_control))
86 + tid = ieee80211_get_tid(hdr);
88 + tid = ATH10K_TXRX_NON_QOS_TID;
90 + last_pn = &peer->frag_tids_last_pn[tid];
91 + new_pn.pn48 = ath10k_htt_rx_h_get_pn(ar, skb, offset, enctype);
92 + more_frags = ieee80211_has_morefrags(hdr->frame_control);
93 + frag_number = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
94 + seq = (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
96 + if (frag_number == 0) {
97 + last_pn->pn48 = new_pn.pn48;
98 + peer->frag_tids_seq[tid] = seq;
100 + if (seq != peer->frag_tids_seq[tid])
103 + if (new_pn.pn48 != last_pn->pn48 + 1)
106 + last_pn->pn48 = new_pn.pn48;
112 static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
113 struct sk_buff_head *amsdu,
114 struct ieee80211_rx_status *status,
115 bool fill_crypt_header,
117 - enum ath10k_pkt_rx_err *err)
118 + enum ath10k_pkt_rx_err *err,
122 struct sk_buff *first;
123 struct sk_buff *last;
124 - struct sk_buff *msdu;
125 + struct sk_buff *msdu, *temp;
126 struct htt_rx_desc *rxd;
127 struct ieee80211_hdr *hdr;
128 enum htt_rx_mpdu_encrypt_type enctype;
129 @@ -1768,6 +1839,7 @@ static void ath10k_htt_rx_h_mpdu(struct
133 + bool frag_pn_check = true;
135 if (skb_queue_empty(amsdu))
137 @@ -1866,6 +1938,24 @@ static void ath10k_htt_rx_h_mpdu(struct
140 skb_queue_walk(amsdu, msdu) {
141 + if (frag && !fill_crypt_header && is_decrypted &&
142 + enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2)
143 + frag_pn_check = ath10k_htt_rx_h_frag_pn_check(ar,
149 + if (!frag_pn_check) {
150 + /* Discard the fragment with invalid PN */
152 + __skb_unlink(msdu, amsdu);
153 + dev_kfree_skb_any(msdu);
155 + frag_pn_check = true;
159 ath10k_htt_rx_h_csum_offload(msdu);
160 ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
162 @@ -2071,7 +2161,8 @@ static int ath10k_htt_rx_handle_amsdu(st
163 ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt);
165 ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
166 - ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err);
167 + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err, 0,
169 msdus_to_queue = skb_queue_len(&amsdu);
170 ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
172 @@ -3027,7 +3118,7 @@ static int ath10k_htt_rx_in_ord_ind(stru
173 ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
174 ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
175 ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
177 + NULL, peer_id, frag);
178 ath10k_htt_rx_h_enqueue(ar, &amsdu, status);