summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/420-mac80211_ignore_invalid_ccmp_rx_pn.patch
blob: 0222f54b6b865b4cc2f1705e1a943ed05deaab0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -90,6 +90,7 @@ struct ieee80211_key {
 			 * Management frames.
 			 */
 			u8 rx_pn[NUM_RX_DATA_QUEUES + 1][6];
+			u8 rx_invalid_pn[NUM_RX_DATA_QUEUES + 1];
 			struct crypto_cipher *tfm;
 			u32 replays; /* dot11RSNAStatsCCMPReplays */
 #ifndef AES_BLOCK_LEN
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -457,6 +457,13 @@ ieee80211_crypto_ccmp_encrypt(struct iee
 	return TX_CONTINUE;
 }
 
+static inline u64 pn_to_u64(u8 *data)
+{
+	u64 pn = get_unaligned_be32(data + 2);
+	pn |= ((u64) get_unaligned_be16(data)) << 32;
+	return pn;
+}
+
 
 ieee80211_rx_result
 ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
@@ -469,6 +476,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee
 	u8 pn[CCMP_PN_LEN];
 	int data_len;
 	int queue;
+	u64 diff;
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -503,6 +511,11 @@ ieee80211_crypto_ccmp_decrypt(struct iee
 			return RX_DROP_UNUSABLE;
 	}
 
+	diff = pn_to_u64(pn) - pn_to_u64(key->u.ccmp.rx_pn[queue]);
+	if (diff > 1000 && key->u.ccmp.rx_invalid_pn[queue]++ < 10)
+		return RX_DROP_UNUSABLE;
+
+	key->u.ccmp.rx_invalid_pn[queue] = 0;
 	memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
 
 	/* Remove CCMP header and MIC */