From 65b6a2775102cd81e57158ef4b1cb89641f76cfd Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 21 Aug 2006 11:32:31 +0800 Subject: [PATCH] ieee80211: Fix header->qos_ctl endian issue Signed-off-by: Jackie Wu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_crypt_tkip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/ieee80211/ieee80211_crypt_tkip.c') diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 34dba0b..a61b09e 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -528,7 +528,7 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) if (stype & IEEE80211_STYPE_QOS_DATA) { const struct ieee80211_hdr_3addrqos *qoshdr = (struct ieee80211_hdr_3addrqos *)skb->data; - hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID; + hdr[12] = qoshdr->qos_ctl & cpu_to_le16(IEEE80211_QCTL_TID); } else hdr[12] = 0; /* priority */ -- cgit v1.1 From b4328d87ec5711543b818fea2e1cf64f09d326f1 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 21 Aug 2006 11:33:09 +0800 Subject: [PATCH] ieee80211: TKIP and CCMP replay check rework Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_crypt_tkip.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'net/ieee80211/ieee80211_crypt_tkip.c') diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index a61b09e..02abf29 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -360,6 +360,19 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return 0; } +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, + u32 iv32_o, u16 iv16_o) +{ + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct ieee80211_tkip_data *tkey = priv; @@ -414,8 +427,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); pos += 8; - if (iv32 < tkey->rx_iv32 || - (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { + if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT " previous TSC %08x%04x received TSC " -- cgit v1.1 From 5a656949719bf8598ad1e93a56eb11e70a4c3208 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 21 Aug 2006 11:33:56 +0800 Subject: [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 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- net/ieee80211/ieee80211_crypt_tkip.c | 90 ++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 30 deletions(-) (limited to 'net/ieee80211/ieee80211_crypt_tkip.c') diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 02abf29..f2df2f5 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -52,8 +52,10 @@ struct ieee80211_tkip_data { int key_idx; - struct crypto_tfm *tfm_arc4; - struct crypto_tfm *tfm_michael; + struct crypto_tfm *tx_tfm_arc4; + struct crypto_tfm *tx_tfm_michael; + struct crypto_tfm *rx_tfm_arc4; + struct crypto_tfm *rx_tfm_michael; /* scratch buffers for virt_to_page() (crypto API) */ u8 rx_hdr[16], tx_hdr[16]; @@ -85,15 +87,29 @@ static void *ieee80211_tkip_init(int key_idx) priv->key_idx = key_idx; - priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0); - if (priv->tfm_arc4 == NULL) { + priv->tx_tfm_arc4 = crypto_alloc_tfm("arc4", 0); + if (priv->tx_tfm_arc4 == NULL) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API arc4\n"); goto fail; } - priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0); - if (priv->tfm_michael == NULL) { + priv->tx_tfm_michael = crypto_alloc_tfm("michael_mic", 0); + if (priv->tx_tfm_michael == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API michael_mic\n"); + goto fail; + } + + priv->rx_tfm_arc4 = crypto_alloc_tfm("arc4", 0); + if (priv->rx_tfm_arc4 == NULL) { + printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + "crypto API arc4\n"); + goto fail; + } + + priv->rx_tfm_michael = crypto_alloc_tfm("michael_mic", 0); + if (priv->rx_tfm_michael == NULL) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API michael_mic\n"); goto fail; @@ -103,10 +119,14 @@ static void *ieee80211_tkip_init(int key_idx) fail: if (priv) { - if (priv->tfm_michael) - crypto_free_tfm(priv->tfm_michael); - if (priv->tfm_arc4) - crypto_free_tfm(priv->tfm_arc4); + if (priv->tx_tfm_michael) + crypto_free_tfm(priv->tx_tfm_michael); + if (priv->tx_tfm_arc4) + crypto_free_tfm(priv->tx_tfm_arc4); + if (priv->rx_tfm_michael) + crypto_free_tfm(priv->rx_tfm_michael); + if (priv->rx_tfm_arc4) + crypto_free_tfm(priv->rx_tfm_arc4); kfree(priv); } @@ -116,10 +136,16 @@ static void *ieee80211_tkip_init(int key_idx) static void ieee80211_tkip_deinit(void *priv) { struct ieee80211_tkip_data *_priv = priv; - if (_priv && _priv->tfm_michael) - crypto_free_tfm(_priv->tfm_michael); - if (_priv && _priv->tfm_arc4) - crypto_free_tfm(_priv->tfm_arc4); + if (_priv) { + if (_priv->tx_tfm_michael) + crypto_free_tfm(_priv->tx_tfm_michael); + if (_priv->tx_tfm_arc4) + crypto_free_tfm(_priv->tx_tfm_arc4); + if (_priv->rx_tfm_michael) + crypto_free_tfm(_priv->rx_tfm_michael); + if (_priv->rx_tfm_arc4) + crypto_free_tfm(_priv->rx_tfm_arc4); + } kfree(priv); } @@ -351,11 +377,11 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) icv[2] = crc >> 16; icv[3] = crc >> 24; - crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); + crypto_cipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = len + 4; - crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); + crypto_cipher_encrypt(tkey->tx_tfm_arc4, &sg, &sg, len + 4); return 0; } @@ -446,11 +472,11 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) plen = skb->len - hdr_len - 12; - crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); + crypto_cipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = plen + 4; - crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4); + crypto_cipher_decrypt(tkey->rx_tfm_arc4, &sg, &sg, plen + 4); crc = ~crc32_le(~0, pos, plen); icv[0] = crc; @@ -484,12 +510,12 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return keyidx; } -static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, +static int michael_mic(struct crypto_tfm *tfm_michael, u8 * key, u8 * hdr, u8 * data, size_t data_len, u8 * mic) { struct scatterlist sg[2]; - if (tkey->tfm_michael == NULL) { + if (tfm_michael == NULL) { printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); return -1; } @@ -501,10 +527,10 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, sg[1].offset = offset_in_page(data); sg[1].length = data_len; - crypto_digest_init(tkey->tfm_michael); - crypto_digest_setkey(tkey->tfm_michael, key, 8); - crypto_digest_update(tkey->tfm_michael, sg, 2); - crypto_digest_final(tkey->tfm_michael, mic); + crypto_digest_init(tfm_michael); + crypto_digest_setkey(tfm_michael, key, 8); + crypto_digest_update(tfm_michael, sg, 2); + crypto_digest_final(tfm_michael, mic); return 0; } @@ -562,7 +588,7 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, michael_mic_hdr(skb, tkey->tx_hdr); pos = skb_put(skb, 8); - if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr, + if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) return -1; @@ -600,7 +626,7 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, return -1; michael_mic_hdr(skb, tkey->rx_hdr); - if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr, + if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) return -1; 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) { struct ieee80211_tkip_data *tkey = priv; int keyidx; - struct crypto_tfm *tfm = tkey->tfm_michael; - struct crypto_tfm *tfm2 = tkey->tfm_arc4; + struct crypto_tfm *tfm = tkey->tx_tfm_michael; + struct crypto_tfm *tfm2 = tkey->tx_tfm_arc4; + struct crypto_tfm *tfm3 = tkey->rx_tfm_michael; + struct crypto_tfm *tfm4 = tkey->rx_tfm_arc4; keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); tkey->key_idx = keyidx; - tkey->tfm_michael = tfm; - tkey->tfm_arc4 = tfm2; + tkey->tx_tfm_michael = tfm; + tkey->tx_tfm_arc4 = tfm2; + tkey->rx_tfm_michael = tfm3; + tkey->rx_tfm_arc4 = tfm4; if (len == TKIP_KEY_LEN) { memcpy(tkey->key, key, TKIP_KEY_LEN); tkey->key_set = 1; -- cgit v1.1 From 183798799216fad36c7219fe8d4d6dee6b8fa755 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Fri, 22 Sep 2006 21:19:05 -0400 Subject: net/ieee80211: fix more crypto-related build breakage Signed-off-by: Jeff Garzik --- net/ieee80211/ieee80211_crypt_tkip.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'net/ieee80211/ieee80211_crypt_tkip.c') diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 259572d..4200ec5 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -93,7 +93,7 @@ static void *ieee80211_tkip_init(int key_idx) if (IS_ERR(priv->tx_tfm_arc4)) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API arc4\n"); - priv->tfm_arc4 = NULL; + priv->tx_tfm_arc4 = NULL; goto fail; } @@ -102,6 +102,7 @@ static void *ieee80211_tkip_init(int key_idx) if (IS_ERR(priv->tx_tfm_michael)) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API michael_mic\n"); + priv->tx_tfm_michael = NULL; goto fail; } @@ -110,6 +111,7 @@ static void *ieee80211_tkip_init(int key_idx) if (IS_ERR(priv->rx_tfm_arc4)) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API arc4\n"); + priv->rx_tfm_arc4 = NULL; goto fail; } @@ -118,7 +120,7 @@ static void *ieee80211_tkip_init(int key_idx) if (IS_ERR(priv->rx_tfm_michael)) { printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " "crypto API michael_mic\n"); - priv->tfm_michael = NULL; + priv->rx_tfm_michael = NULL; goto fail; } @@ -392,6 +394,19 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); } +/* + * deal with seq counter wrapping correctly. + * refer to timer_after() for jiffies wrapping handling + */ +static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, + u32 iv32_o, u16 iv16_o) +{ + if ((s32)iv32_n - (s32)iv32_o < 0 || + (iv32_n == iv32_o && iv16_n <= iv16_o)) + return 1; + return 0; +} + static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct ieee80211_tkip_data *tkey = priv; -- cgit v1.1