aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/wpa.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-07-06 15:59:39 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-07-08 11:11:19 -0400
commitaba83a0b301c32dbb91c017f33307611e1a1d384 (patch)
tree9f8478ddf2160c9b4c50666e037e6239ea52e274 /net/mac80211/wpa.c
parent523b02ea23b175dd3e46e3daf1bc9354376640a3 (diff)
mac80211: fix CCMP races
Since we can process multiple packets at the same time for different ACs, but the PN is allocated from a single counter, we need to use an atomic value there. Use atomic64_t to make this cheaper on 64-bit platforms, other platforms will support this through software emulation, see lib/atomic64.c. We also need to use an on-stack scratch buf so that multiple packets won't corrupt each others scratch buffers. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/wpa.c')
-rw-r--r--net/mac80211/wpa.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 4ded2ae48a5..7691e4edc74 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -15,6 +15,7 @@
15#include <linux/gfp.h> 15#include <linux/gfp.h>
16#include <asm/unaligned.h> 16#include <asm/unaligned.h>
17#include <net/mac80211.h> 17#include <net/mac80211.h>
18#include <crypto/aes.h>
18 19
19#include "ieee80211_i.h" 20#include "ieee80211_i.h"
20#include "michael.h" 21#include "michael.h"
@@ -290,6 +291,8 @@ static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
290 unsigned int hdrlen; 291 unsigned int hdrlen;
291 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 292 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
292 293
294 memset(scratch, 0, 6 * AES_BLOCK_LEN);
295
293 b_0 = scratch + 3 * AES_BLOCK_LEN; 296 b_0 = scratch + 3 * AES_BLOCK_LEN;
294 aad = scratch + 4 * AES_BLOCK_LEN; 297 aad = scratch + 4 * AES_BLOCK_LEN;
295 298
@@ -380,8 +383,10 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
380 struct ieee80211_key *key = tx->key; 383 struct ieee80211_key *key = tx->key;
381 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 384 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
382 int hdrlen, len, tail; 385 int hdrlen, len, tail;
383 u8 *pos, *pn; 386 u8 *pos;
384 int i; 387 u8 pn[6];
388 u64 pn64;
389 u8 scratch[6 * AES_BLOCK_LEN];
385 390
386 if (info->control.hw_key && 391 if (info->control.hw_key &&
387 !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { 392 !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
@@ -409,14 +414,14 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
409 hdr = (struct ieee80211_hdr *) pos; 414 hdr = (struct ieee80211_hdr *) pos;
410 pos += hdrlen; 415 pos += hdrlen;
411 416
412 /* PN = PN + 1 */ 417 pn64 = atomic64_inc_return(&key->u.ccmp.tx_pn);
413 pn = key->u.ccmp.tx_pn;
414 418
415 for (i = CCMP_PN_LEN - 1; i >= 0; i--) { 419 pn[5] = pn64;
416 pn[i]++; 420 pn[4] = pn64 >> 8;
417 if (pn[i]) 421 pn[3] = pn64 >> 16;
418 break; 422 pn[2] = pn64 >> 24;
419 } 423 pn[1] = pn64 >> 32;
424 pn[0] = pn64 >> 40;
420 425
421 ccmp_pn2hdr(pos, pn, key->conf.keyidx); 426 ccmp_pn2hdr(pos, pn, key->conf.keyidx);
422 427
@@ -425,8 +430,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
425 return 0; 430 return 0;
426 431
427 pos += CCMP_HDR_LEN; 432 pos += CCMP_HDR_LEN;
428 ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); 433 ccmp_special_blocks(skb, pn, scratch, 0);
429 ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len, 434 ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, pos, len,
430 pos, skb_put(skb, CCMP_MIC_LEN)); 435 pos, skb_put(skb, CCMP_MIC_LEN));
431 436
432 return 0; 437 return 0;
@@ -482,11 +487,12 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
482 } 487 }
483 488
484 if (!(status->flag & RX_FLAG_DECRYPTED)) { 489 if (!(status->flag & RX_FLAG_DECRYPTED)) {
490 u8 scratch[6 * AES_BLOCK_LEN];
485 /* hardware didn't decrypt/verify MIC */ 491 /* hardware didn't decrypt/verify MIC */
486 ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1); 492 ccmp_special_blocks(skb, pn, scratch, 1);
487 493
488 if (ieee80211_aes_ccm_decrypt( 494 if (ieee80211_aes_ccm_decrypt(
489 key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf, 495 key->u.ccmp.tfm, scratch,
490 skb->data + hdrlen + CCMP_HDR_LEN, data_len, 496 skb->data + hdrlen + CCMP_HDR_LEN, data_len,
491 skb->data + skb->len - CCMP_MIC_LEN, 497 skb->data + skb->len - CCMP_MIC_LEN,
492 skb->data + hdrlen + CCMP_HDR_LEN)) 498 skb->data + hdrlen + CCMP_HDR_LEN))