mac80211: detect and drop incoming packets with invalid CCMP packet numbers to fix...
authorFelix Fietkau <nbd@openwrt.org>
Sun, 1 May 2011 01:51:03 +0000 (01:51 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 1 May 2011 01:51:03 +0000 (01:51 +0000)
SVN-Revision: 26796

package/mac80211/patches/420-mac80211_ignore_invalid_ccmp_rx_pn.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/420-mac80211_ignore_invalid_ccmp_rx_pn.patch b/package/mac80211/patches/420-mac80211_ignore_invalid_ccmp_rx_pn.patch
new file mode 100644 (file)
index 0000000..4d0f861
--- /dev/null
@@ -0,0 +1,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
+@@ -407,6 +407,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)
+@@ -419,6 +426,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);
+@@ -452,6 +460,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 */