aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee80211/ieee80211_crypt_tkip.c
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2006-08-20 23:33:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-08-29 17:06:30 -0400
commit5a656949719bf8598ad1e93a56eb11e70a4c3208 (patch)
treeea0df5c37e264903b9e82e4ec7ade946e6d39be2 /net/ieee80211/ieee80211_crypt_tkip.c
parentb4328d87ec5711543b818fea2e1cf64f09d326f1 (diff)
[PATCH] ieee80211: Fix TKIP and WEP decryption error on SMP machines
The IEEE80211 TKIP and WEP Tx and Rx paths use the same crypto_tfm to encrypt and decrypt data. During the encrypt and decrypt process, both of them will set a new key to crypto_tfm. If they happen on the same time, it will corrupt the crypto_tfm. Thus users will receive an ICV error or Michael MIC error. This only likely to happen on SMP box with heavy traffic both on Tx and Rx. The patch use two sets of crypto_tfms to avoid this problem. Signed-off-by: Hong Liu <hong.liu@intel.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/ieee80211/ieee80211_crypt_tkip.c')
-rw-r--r--net/ieee80211/ieee80211_crypt_tkip.c90
1 files changed, 60 insertions, 30 deletions
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index 02abf2985b84..f2df2f5b3e4c 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -52,8 +52,10 @@ struct ieee80211_tkip_data {
52 52
53 int key_idx; 53 int key_idx;
54 54
55 struct crypto_tfm *tfm_arc4; 55 struct crypto_tfm *tx_tfm_arc4;
56 struct crypto_tfm *tfm_michael; 56 struct crypto_tfm *tx_tfm_michael;
57 struct crypto_tfm *rx_tfm_arc4;
58 struct crypto_tfm *rx_tfm_michael;
57 59
58 /* scratch buffers for virt_to_page() (crypto API) */ 60 /* scratch buffers for virt_to_page() (crypto API) */
59 u8 rx_hdr[16], tx_hdr[16]; 61 u8 rx_hdr[16], tx_hdr[16];
@@ -85,15 +87,29 @@ static void *ieee80211_tkip_init(int key_idx)
85 87
86 priv->key_idx = key_idx; 88 priv->key_idx = key_idx;
87 89
88 priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); 90 priv->tx_tfm_arc4 = crypto_alloc_tfm("arc4", 0);
89 if (priv->tfm_arc4 == NULL) { 91 if (priv->tx_tfm_arc4 == NULL) {
90 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " 92 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
91 "crypto API arc4\n"); 93 "crypto API arc4\n");
92 goto fail; 94 goto fail;
93 } 95 }
94 96
95 priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); 97 priv->tx_tfm_michael = crypto_alloc_tfm("michael_mic", 0);
96 if (priv->tfm_michael == NULL) { 98 if (priv->tx_tfm_michael == NULL) {
99 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
100 "crypto API michael_mic\n");
101 goto fail;
102 }
103
104 priv->rx_tfm_arc4 = crypto_alloc_tfm("arc4", 0);
105 if (priv->rx_tfm_arc4 == NULL) {
106 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
107 "crypto API arc4\n");
108 goto fail;
109 }
110
111 priv->rx_tfm_michael = crypto_alloc_tfm("michael_mic", 0);
112 if (priv->rx_tfm_michael == NULL) {
97 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " 113 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
98 "crypto API michael_mic\n"); 114 "crypto API michael_mic\n");
99 goto fail; 115 goto fail;
@@ -103,10 +119,14 @@ static void *ieee80211_tkip_init(int key_idx)
103 119
104 fail: 120 fail:
105 if (priv) { 121 if (priv) {
106 if (priv->tfm_michael) 122 if (priv->tx_tfm_michael)
107 crypto_free_tfm(priv->tfm_michael); 123 crypto_free_tfm(priv->tx_tfm_michael);
108 if (priv->tfm_arc4) 124 if (priv->tx_tfm_arc4)
109 crypto_free_tfm(priv->tfm_arc4); 125 crypto_free_tfm(priv->tx_tfm_arc4);
126 if (priv->rx_tfm_michael)
127 crypto_free_tfm(priv->rx_tfm_michael);
128 if (priv->rx_tfm_arc4)
129 crypto_free_tfm(priv->rx_tfm_arc4);
110 kfree(priv); 130 kfree(priv);
111 } 131 }
112 132
@@ -116,10 +136,16 @@ static void *ieee80211_tkip_init(int key_idx)
116static void ieee80211_tkip_deinit(void *priv) 136static void ieee80211_tkip_deinit(void *priv)
117{ 137{
118 struct ieee80211_tkip_data *_priv = priv; 138 struct ieee80211_tkip_data *_priv = priv;
119 if (_priv && _priv->tfm_michael) 139 if (_priv) {
120 crypto_free_tfm(_priv->tfm_michael); 140 if (_priv->tx_tfm_michael)
121 if (_priv && _priv->tfm_arc4) 141 crypto_free_tfm(_priv->tx_tfm_michael);
122 crypto_free_tfm(_priv->tfm_arc4); 142 if (_priv->tx_tfm_arc4)
143 crypto_free_tfm(_priv->tx_tfm_arc4);
144 if (_priv->rx_tfm_michael)
145 crypto_free_tfm(_priv->rx_tfm_michael);
146 if (_priv->rx_tfm_arc4)
147 crypto_free_tfm(_priv->rx_tfm_arc4);
148 }
123 kfree(priv); 149 kfree(priv);
124} 150}
125 151
@@ -351,11 +377,11 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
351 icv[2] = crc >> 16; 377 icv[2] = crc >> 16;
352 icv[3] = crc >> 24; 378 icv[3] = crc >> 24;
353 379
354 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); 380 crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
355 sg.page = virt_to_page(pos); 381 sg.page = virt_to_page(pos);
356 sg.offset = offset_in_page(pos); 382 sg.offset = offset_in_page(pos);
357 sg.length = len + 4; 383 sg.length = len + 4;
358 crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); 384 crypto_cipher_encrypt(tkey->tx_tfm_arc4, &sg, &sg, len + 4);
359 385
360 return 0; 386 return 0;
361} 387}
@@ -446,11 +472,11 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
446 472
447 plen = skb->len - hdr_len - 12; 473 plen = skb->len - hdr_len - 12;
448 474
449 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); 475 crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
450 sg.page = virt_to_page(pos); 476 sg.page = virt_to_page(pos);
451 sg.offset = offset_in_page(pos); 477 sg.offset = offset_in_page(pos);
452 sg.length = plen + 4; 478 sg.length = plen + 4;
453 crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); 479 crypto_cipher_decrypt(tkey->rx_tfm_arc4, &sg, &sg, plen + 4);
454 480
455 crc = ~crc32_le(~0, pos, plen); 481 crc = ~crc32_le(~0, pos, plen);
456 icv[0] = crc; 482 icv[0] = crc;
@@ -484,12 +510,12 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
484 return keyidx; 510 return keyidx;
485} 511}
486 512
487static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, 513static int michael_mic(struct crypto_tfm *tfm_michael, u8 * key, u8 * hdr,
488 u8 * data, size_t data_len, u8 * mic) 514 u8 * data, size_t data_len, u8 * mic)
489{ 515{
490 struct scatterlist sg[2]; 516 struct scatterlist sg[2];
491 517
492 if (tkey->tfm_michael == NULL) { 518 if (tfm_michael == NULL) {
493 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); 519 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
494 return -1; 520 return -1;
495 } 521 }
@@ -501,10 +527,10 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
501 sg[1].offset = offset_in_page(data); 527 sg[1].offset = offset_in_page(data);
502 sg[1].length = data_len; 528 sg[1].length = data_len;
503 529
504 crypto_digest_init(tkey->tfm_michael); 530 crypto_digest_init(tfm_michael);
505 crypto_digest_setkey(tkey->tfm_michael, key, 8); 531 crypto_digest_setkey(tfm_michael, key, 8);
506 crypto_digest_update(tkey->tfm_michael, sg, 2); 532 crypto_digest_update(tfm_michael, sg, 2);
507 crypto_digest_final(tkey->tfm_michael, mic); 533 crypto_digest_final(tfm_michael, mic);
508 534
509 return 0; 535 return 0;
510} 536}
@@ -562,7 +588,7 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
562 588
563 michael_mic_hdr(skb, tkey->tx_hdr); 589 michael_mic_hdr(skb, tkey->tx_hdr);
564 pos = skb_put(skb, 8); 590 pos = skb_put(skb, 8);
565 if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, 591 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
566 skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) 592 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
567 return -1; 593 return -1;
568 594
@@ -600,7 +626,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
600 return -1; 626 return -1;
601 627
602 michael_mic_hdr(skb, tkey->rx_hdr); 628 michael_mic_hdr(skb, tkey->rx_hdr);
603 if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, 629 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
604 skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) 630 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
605 return -1; 631 return -1;
606 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { 632 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
@@ -630,14 +656,18 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
630{ 656{
631 struct ieee80211_tkip_data *tkey = priv; 657 struct ieee80211_tkip_data *tkey = priv;
632 int keyidx; 658 int keyidx;
633 struct crypto_tfm *tfm = tkey->tfm_michael; 659 struct crypto_tfm *tfm = tkey->tx_tfm_michael;
634 struct crypto_tfm *tfm2 = tkey->tfm_arc4; 660 struct crypto_tfm *tfm2 = tkey->tx_tfm_arc4;
661 struct crypto_tfm *tfm3 = tkey->rx_tfm_michael;
662 struct crypto_tfm *tfm4 = tkey->rx_tfm_arc4;
635 663
636 keyidx = tkey->key_idx; 664 keyidx = tkey->key_idx;
637 memset(tkey, 0, sizeof(*tkey)); 665 memset(tkey, 0, sizeof(*tkey));
638 tkey->key_idx = keyidx; 666 tkey->key_idx = keyidx;
639 tkey->tfm_michael = tfm; 667 tkey->tx_tfm_michael = tfm;
640 tkey->tfm_arc4 = tfm2; 668 tkey->tx_tfm_arc4 = tfm2;
669 tkey->rx_tfm_michael = tfm3;
670 tkey->rx_tfm_arc4 = tfm4;
641 if (len == TKIP_KEY_LEN) { 671 if (len == TKIP_KEY_LEN) {
642 memcpy(tkey->key, key, TKIP_KEY_LEN); 672 memcpy(tkey->key, key, TKIP_KEY_LEN);
643 tkey->key_set = 1; 673 tkey->key_set = 1;