blob: f6793541f2aaa60480939a492468ca4f1ecc3858 (
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
@@ -86,6 +86,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 */
/* scratch buffers for virt_to_page() (crypto API) */
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -441,6 +441,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)
@@ -453,6 +460,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);
@@ -486,6 +494,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 */
|