summaryrefslogtreecommitdiff
path: root/package/mac80211
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2011-05-01 01:45:26 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2011-05-01 01:45:26 +0000
commitd75d999a720d07495811415ca129727f69c94843 (patch)
tree92bc5385ca6f5673d00a97153fec2efc2c8e729e /package/mac80211
parent44370d22ed7d75d197e54f1c53df617231224bd8 (diff)
mac80211: detect and drop incoming packets with invalid CCMP packet numbers to fix connection hangs on some devices
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@26795 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/mac80211')
-rw-r--r--package/mac80211/patches/420-mac80211_ignore_invalid_ccmp_rx_pn.patch46
1 files changed, 46 insertions, 0 deletions
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
index 0000000000..4d0f861344
--- /dev/null
+++ b/package/mac80211/patches/420-mac80211_ignore_invalid_ccmp_rx_pn.patch
@@ -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 */