[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>
This commit is contained in:
@@ -32,7 +32,8 @@ struct prism2_wep_data {
|
||||
u8 key[WEP_KEY_LEN + 1];
|
||||
u8 key_len;
|
||||
u8 key_idx;
|
||||
struct crypto_tfm *tfm;
|
||||
struct crypto_tfm *tx_tfm;
|
||||
struct crypto_tfm *rx_tfm;
|
||||
};
|
||||
|
||||
static void *prism2_wep_init(int keyidx)
|
||||
@@ -44,13 +45,19 @@ static void *prism2_wep_init(int keyidx)
|
||||
goto fail;
|
||||
priv->key_idx = keyidx;
|
||||
|
||||
priv->tfm = crypto_alloc_tfm("arc4", 0);
|
||||
if (priv->tfm == NULL) {
|
||||
priv->tx_tfm = crypto_alloc_tfm("arc4", 0);
|
||||
if (priv->tx_tfm == NULL) {
|
||||
printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
|
||||
"crypto API arc4\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
priv->rx_tfm = crypto_alloc_tfm("arc4", 0);
|
||||
if (priv->rx_tfm == NULL) {
|
||||
printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate "
|
||||
"crypto API arc4\n");
|
||||
goto fail;
|
||||
}
|
||||
/* start WEP IV from a random value */
|
||||
get_random_bytes(&priv->iv, 4);
|
||||
|
||||
@@ -58,8 +65,10 @@ static void *prism2_wep_init(int keyidx)
|
||||
|
||||
fail:
|
||||
if (priv) {
|
||||
if (priv->tfm)
|
||||
crypto_free_tfm(priv->tfm);
|
||||
if (priv->tx_tfm)
|
||||
crypto_free_tfm(priv->tx_tfm);
|
||||
if (priv->rx_tfm)
|
||||
crypto_free_tfm(priv->rx_tfm);
|
||||
kfree(priv);
|
||||
}
|
||||
return NULL;
|
||||
@@ -68,8 +77,12 @@ static void *prism2_wep_init(int keyidx)
|
||||
static void prism2_wep_deinit(void *priv)
|
||||
{
|
||||
struct prism2_wep_data *_priv = priv;
|
||||
if (_priv && _priv->tfm)
|
||||
crypto_free_tfm(_priv->tfm);
|
||||
if (_priv) {
|
||||
if (_priv->tx_tfm)
|
||||
crypto_free_tfm(_priv->tx_tfm);
|
||||
if (_priv->rx_tfm)
|
||||
crypto_free_tfm(_priv->rx_tfm);
|
||||
}
|
||||
kfree(priv);
|
||||
}
|
||||
|
||||
@@ -151,11 +164,11 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
||||
icv[2] = crc >> 16;
|
||||
icv[3] = crc >> 24;
|
||||
|
||||
crypto_cipher_setkey(wep->tfm, key, klen);
|
||||
crypto_cipher_setkey(wep->tx_tfm, key, klen);
|
||||
sg.page = virt_to_page(pos);
|
||||
sg.offset = offset_in_page(pos);
|
||||
sg.length = len + 4;
|
||||
crypto_cipher_encrypt(wep->tfm, &sg, &sg, len + 4);
|
||||
crypto_cipher_encrypt(wep->tx_tfm, &sg, &sg, len + 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -194,11 +207,11 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
|
||||
/* Apply RC4 to data and compute CRC32 over decrypted data */
|
||||
plen = skb->len - hdr_len - 8;
|
||||
|
||||
crypto_cipher_setkey(wep->tfm, key, klen);
|
||||
crypto_cipher_setkey(wep->rx_tfm, key, klen);
|
||||
sg.page = virt_to_page(pos);
|
||||
sg.offset = offset_in_page(pos);
|
||||
sg.length = plen + 4;
|
||||
crypto_cipher_decrypt(wep->tfm, &sg, &sg, plen + 4);
|
||||
crypto_cipher_decrypt(wep->rx_tfm, &sg, &sg, plen + 4);
|
||||
|
||||
crc = ~crc32_le(~0, pos, plen);
|
||||
icv[0] = crc;
|
||||
|
Reference in New Issue
Block a user