0ce49b22ab48fc2235533cfe2bad5c1225483cf8
[openwrt/staging/thess.git] /
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
4 frames for PCIe
5
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
12 bit case.
13
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
17 QCA6174/QCA6377 PCIe.
18
19 Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00110-QCARMSWP-1
20
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>
25 ---
26
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 {
30
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
34
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);
41 }
42
43 +static u64 ath10k_htt_rx_h_get_pn(struct ath10k *ar, struct sk_buff *skb,
44 + u16 offset,
45 + enum htt_rx_mpdu_encrypt_type enctype)
46 +{
47 + struct ieee80211_hdr *hdr;
48 + u64 pn = 0;
49 + u8 *ehdr;
50 +
51 + hdr = (struct ieee80211_hdr *)(skb->data + offset);
52 + ehdr = skb->data + offset + ieee80211_hdrlen(hdr->frame_control);
53 +
54 + if (enctype == HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2) {
55 + pn = ehdr[0];
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;
61 + }
62 + return pn;
63 +}
64 +
65 +static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar,
66 + struct sk_buff *skb,
67 + u16 peer_id,
68 + u16 offset,
69 + enum htt_rx_mpdu_encrypt_type enctype)
70 +{
71 + struct ath10k_peer *peer;
72 + union htt_rx_pn_t *last_pn, new_pn = {0};
73 + struct ieee80211_hdr *hdr;
74 + bool more_frags;
75 + u8 tid, frag_number;
76 + u32 seq;
77 +
78 + peer = ath10k_peer_find_by_id(ar, peer_id);
79 + if (!peer) {
80 + ath10k_dbg(ar, ATH10K_DBG_HTT, "invalid peer for frag pn check\n");
81 + return false;
82 + }
83 +
84 + hdr = (struct ieee80211_hdr *)(skb->data + offset);
85 + if (ieee80211_is_data_qos(hdr->frame_control))
86 + tid = ieee80211_get_tid(hdr);
87 + else
88 + tid = ATH10K_TXRX_NON_QOS_TID;
89 +
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;
95 +
96 + if (frag_number == 0) {
97 + last_pn->pn48 = new_pn.pn48;
98 + peer->frag_tids_seq[tid] = seq;
99 + } else {
100 + if (seq != peer->frag_tids_seq[tid])
101 + return false;
102 +
103 + if (new_pn.pn48 != last_pn->pn48 + 1)
104 + return false;
105 +
106 + last_pn->pn48 = new_pn.pn48;
107 + }
108 +
109 + return true;
110 +}
111 +
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,
116 u8 *rx_hdr,
117 - enum ath10k_pkt_rx_err *err)
118 + enum ath10k_pkt_rx_err *err,
119 + u16 peer_id,
120 + bool frag)
121 {
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
130 bool is_decrypted;
131 bool is_mgmt;
132 u32 attention;
133 + bool frag_pn_check = true;
134
135 if (skb_queue_empty(amsdu))
136 return;
137 @@ -1866,6 +1938,24 @@ static void ath10k_htt_rx_h_mpdu(struct
138 }
139
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,
144 + msdu,
145 + peer_id,
146 + 0,
147 + enctype);
148 +
149 + if (!frag_pn_check) {
150 + /* Discard the fragment with invalid PN */
151 + temp = msdu->prev;
152 + __skb_unlink(msdu, amsdu);
153 + dev_kfree_skb_any(msdu);
154 + msdu = temp;
155 + frag_pn_check = true;
156 + continue;
157 + }
158 +
159 ath10k_htt_rx_h_csum_offload(msdu);
160 ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
161 is_decrypted);
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);
164
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,
168 + false);
169 msdus_to_queue = skb_queue_len(&amsdu);
170 ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
171
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,
176 - NULL);
177 + NULL, peer_id, frag);
178 ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
179 break;
180 case -EAGAIN: