ieee80211_crypt_tkip.c revision 0ee9f67c4028500a4348e8bc87ee7ec1139b8259
18fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang/*
28fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
38fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang *
48fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
58fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang *
68fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang * This program is free software; you can redistribute it and/or modify
78fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang * it under the terms of the GNU General Public License version 2 as
88fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang * published by the Free Software Foundation. See README and COPYING for
98fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang * more details.
108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang */
118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang//#include <linux/config.h>
138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/version.h>
148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/module.h>
158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/init.h>
168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/slab.h>
178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/random.h>
188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/skbuff.h>
198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/netdevice.h>
208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/if_ether.h>
218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/if_arp.h>
228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <asm/string.h>
238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include "ieee80211.h"
258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/crypto.h>
27e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	#include <linux/scatterlist.h>
288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#include <linux/crc32.h>
298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry ChuangMODULE_AUTHOR("Jouni Malinen");
318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry ChuangMODULE_DESCRIPTION("Host AP crypt: TKIP");
328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry ChuangMODULE_LICENSE("GPL");
338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstruct ieee80211_tkip_data {
358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#define TKIP_KEY_LEN 32
368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 key[TKIP_KEY_LEN];
378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int key_set;
388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 tx_iv32;
408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 tx_iv16;
418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 tx_ttak[5];
428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int tx_phase1_done;
438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 rx_iv32;
458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 rx_iv16;
468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 rx_ttak[5];
478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int rx_phase1_done;
488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 rx_iv32_new;
498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 rx_iv16_new;
508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 dot11RSNAStatsTKIPReplays;
528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 dot11RSNAStatsTKIPICVErrors;
538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 dot11RSNAStatsTKIPLocalMICFailures;
548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int key_idx;
56f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_blkcipher *rx_tfm_arc4;
588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_hash *rx_tfm_michael;
598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_blkcipher *tx_tfm_arc4;
608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_hash *tx_tfm_michael;
61f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* scratch buffers for virt_to_page() (crypto API) */
638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 rx_hdr[16], tx_hdr[16];
648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang};
658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic void * ieee80211_tkip_init(int key_idx)
678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *priv;
698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (priv == NULL)
728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		goto fail;
738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memset(priv, 0, sizeof(*priv));
748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	priv->key_idx = key_idx;
758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			CRYPTO_ALG_ASYNC);
788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (IS_ERR(priv->tx_tfm_arc4)) {
798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				"crypto API arc4\n");
818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		priv->tx_tfm_arc4 = NULL;
828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		goto fail;
838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			CRYPTO_ALG_ASYNC);
878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (IS_ERR(priv->tx_tfm_michael)) {
888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				"crypto API michael_mic\n");
908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		priv->tx_tfm_michael = NULL;
918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		goto fail;
928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			CRYPTO_ALG_ASYNC);
968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (IS_ERR(priv->rx_tfm_arc4)) {
978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				"crypto API arc4\n");
998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		priv->rx_tfm_arc4 = NULL;
1008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		goto fail;
1018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
1028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
1048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			CRYPTO_ALG_ASYNC);
1058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (IS_ERR(priv->rx_tfm_michael)) {
1068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
1078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				"crypto API michael_mic\n");
1088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		priv->rx_tfm_michael = NULL;
1098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		goto fail;
1108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
111f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
1128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return priv;
1138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangfail:
1158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (priv) {
1168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (priv->tx_tfm_michael)
1178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_hash(priv->tx_tfm_michael);
1188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (priv->tx_tfm_arc4)
1198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_blkcipher(priv->tx_tfm_arc4);
1208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (priv->rx_tfm_michael)
1218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_hash(priv->rx_tfm_michael);
1228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (priv->rx_tfm_arc4)
1238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_blkcipher(priv->rx_tfm_arc4);
1248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		kfree(priv);
1258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
1268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return NULL;
1288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic void ieee80211_tkip_deinit(void *priv)
1328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *_priv = priv;
134f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
1358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (_priv) {
1368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (_priv->tx_tfm_michael)
1378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_hash(_priv->tx_tfm_michael);
1388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (_priv->tx_tfm_arc4)
1398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_blkcipher(_priv->tx_tfm_arc4);
1408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (_priv->rx_tfm_michael)
1418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_hash(_priv->rx_tfm_michael);
1428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (_priv->rx_tfm_arc4)
1438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			crypto_free_blkcipher(_priv->rx_tfm_arc4);
1448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
1458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	kfree(priv);
1468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u16 RotR1(u16 val)
1508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return (val >> 1) | (val << 15);
1528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u8 Lo8(u16 val)
1568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return val & 0xff;
1588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u8 Hi8(u16 val)
1628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return val >> 8;
1648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u16 Lo16(u32 val)
1688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return val & 0xffff;
1708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u16 Hi16(u32 val)
1748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return val >> 16;
1768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u16 Mk16(u8 hi, u8 lo)
1808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return lo | (((u16) hi) << 8);
1828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u16 Mk16_le(u16 *v)
1868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return le16_to_cpu(*v);
1888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
1898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
1918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic const u16 Sbox[256] =
1928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
1938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
1948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
1958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
1968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
1978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
1988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
1998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
2008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
2018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
2028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
2038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
2048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
2058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
2068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
2078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
2088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
2098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
2108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
2118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
2128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
2138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
2148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
2158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
2168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
2178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
2188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
2198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
2208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
2218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
2228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
2238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
2248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
2258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang};
2268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic inline u16 _S_(u16 v)
2298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
2308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 t = Sbox[Hi8(v)];
2318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
2328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
2338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#define PHASE1_LOOP_COUNT 8
2368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
2398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
2408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int i, j;
2418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
2438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	TTAK[0] = Lo16(IV32);
2448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	TTAK[1] = Hi16(IV32);
2458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	TTAK[2] = Mk16(TA[1], TA[0]);
2468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	TTAK[3] = Mk16(TA[3], TA[2]);
2478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	TTAK[4] = Mk16(TA[5], TA[4]);
2488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
2508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		j = 2 * (i & 1);
2518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
2528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
2538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
2548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
2558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
2568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
2578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
2588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
2618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       u16 IV16)
2628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
2638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Make temporary area overlap WEP seed so that the final copy can be
2648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	 * avoided on little endian hosts. */
2658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 *PPK = (u16 *) &WEPSeed[4];
2668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Step 1 - make copy of TTAK and bring in TSC */
2688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[0] = TTAK[0];
2698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[1] = TTAK[1];
2708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[2] = TTAK[2];
2718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[3] = TTAK[3];
2728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[4] = TTAK[4];
2738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[5] = TTAK[4] + IV16;
2748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Step 2 - 96-bit bijective mixing using S-box */
2768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0]));
2778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2]));
2788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4]));
2798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6]));
2808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8]));
2818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10]));
2828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12]));
2848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14]));
2858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[2] += RotR1(PPK[1]);
2868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[3] += RotR1(PPK[2]);
2878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[4] += RotR1(PPK[3]);
2888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	PPK[5] += RotR1(PPK[4]);
2898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
2918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	 * WEPSeed[0..2] is transmitted as WEP IV */
2928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	WEPSeed[0] = Hi8(IV16);
2938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
2948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	WEPSeed[2] = Lo8(IV16);
2958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1);
2968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
2978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#ifdef __BIG_ENDIAN
2988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	{
2998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		int i;
3008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		for (i = 0; i < 6; i++)
3018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
3028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
3038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang#endif
3048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
3058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
3088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
3098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkey = priv;
3108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		int len;
3118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 *pos;
3128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_hdr_4addr *hdr;
3138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
3148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4};
3158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int ret = 0;
3168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 rc4key[16],  *icv;
3178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 crc;
3188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct scatterlist sg;
3198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 ||
3218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	    skb->len < hdr_len)
3228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
3238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr = (struct ieee80211_hdr_4addr *) skb->data;
3258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tcb_desc->bHwSec)
3278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	{
3288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (!tkey->tx_phase1_done) {
3298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
3308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang					tkey->tx_iv32);
3318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkey->tx_phase1_done = 1;
3328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
3338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
3348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
3358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
3368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->tx_phase1_done = 1;
3378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	len = skb->len - hdr_len;
3408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	pos = skb_push(skb, 8);
3418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memmove(pos, pos + 8, hdr_len);
3428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	pos += hdr_len;
3438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (tcb_desc->bHwSec)
3458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	{
3468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		*pos++ = Hi8(tkey->tx_iv16);
3478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		*pos++ = (Hi8(tkey->tx_iv16) | 0x20) & 0x7F;
3488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		*pos++ = Lo8(tkey->tx_iv16);
3498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
3508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
3518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	{
3528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		*pos++ = rc4key[0];
3538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		*pos++ = rc4key[1];
3548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		*pos++ = rc4key[2];
3558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
3568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	*pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */;
3588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	*pos++ = tkey->tx_iv32 & 0xff;
3598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	*pos++ = (tkey->tx_iv32 >> 8) & 0xff;
3608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	*pos++ = (tkey->tx_iv32 >> 16) & 0xff;
3618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	*pos++ = (tkey->tx_iv32 >> 24) & 0xff;
3628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tcb_desc->bHwSec)
3648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	{
3658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv = skb_put(skb, 4);
3668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		crc = ~crc32_le(~0, pos, len);
3678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[0] = crc;
3688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[1] = crc >> 8;
3698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[2] = crc >> 16;
3708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[3] = crc >> 24;
3718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
3728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		sg_init_one(&sg, pos, len+4);
3738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		ret= crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
3748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
3758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->tx_iv16++;
3778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (tkey->tx_iv16 == 0) {
3788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->tx_phase1_done = 0;
3798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->tx_iv32++;
3808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
3818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tcb_desc->bHwSec)
3838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return ret;
3848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
385e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab		return 0;
3868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
3898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
3908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
3918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
3928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkey = priv;
3938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 keyidx, *pos;
3948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 iv32;
3958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u16 iv16;
3968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_hdr_4addr *hdr;
3978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
3988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct blkcipher_desc desc = {.tfm = tkey->rx_tfm_arc4};
3998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 rc4key[16];
4008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 icv[4];
4018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u32 crc;
4028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct scatterlist sg;
4038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int plen;
4048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (skb->len < hdr_len + 8 + 4)
4058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
4068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr = (struct ieee80211_hdr_4addr *) skb->data;
4088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	pos = skb->data + hdr_len;
4098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	keyidx = pos[3];
4108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!(keyidx & (1 << 5))) {
4118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (net_ratelimit()) {
4128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			printk(KERN_DEBUG "TKIP: received packet without ExtIV"
4130ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches			       " flag from %pM\n", hdr->addr2);
4148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
4158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -2;
4168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
4178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	keyidx >>= 6;
4188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (tkey->key_idx != keyidx) {
4198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
4208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
4218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -6;
4228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
4238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tkey->key_set) {
4248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (net_ratelimit()) {
4250ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches			printk(KERN_DEBUG "TKIP: received packet from %pM"
4268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			       " with keyid=%d that does not have a configured"
4270ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches			       " key\n", hdr->addr2, keyidx);
4288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
4298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -3;
4308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
4318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	iv16 = (pos[0] << 8) | pos[2];
4328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
4338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	pos += 8;
4348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tcb_desc->bHwSec)
4368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	{
4378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (iv32 < tkey->rx_iv32 ||
4388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		(iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
4398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			if (net_ratelimit()) {
4400ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches				printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
4418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				" previous TSC %08x%04x received TSC "
4420ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches				"%08x%04x\n", hdr->addr2,
4438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
4448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			}
4458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkey->dot11RSNAStatsTKIPReplays++;
4468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			return -4;
4478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
4488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
4508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
4518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkey->rx_phase1_done = 1;
4528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
4538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
4548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		plen = skb->len - hdr_len - 12;
4568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
4588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		sg_init_one(&sg, pos, plen+4);
459f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
4608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
4618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			if (net_ratelimit()) {
4628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				printk(KERN_DEBUG ": TKIP: failed to decrypt "
4630ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches						"received packet from %pM\n",
4640ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches						hdr->addr2);
4658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			}
4668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			return -7;
4678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
4688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		crc = ~crc32_le(~0, pos, plen);
4708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[0] = crc;
4718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[1] = crc >> 8;
4728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[2] = crc >> 16;
4738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		icv[3] = crc >> 24;
4748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (memcmp(icv, pos + plen, 4) != 0) {
4768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			if (iv32 != tkey->rx_iv32) {
4778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				/* Previously cached Phase1 result was already lost, so
4788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				* it needs to be recalculated for the next packet. */
4798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				tkey->rx_phase1_done = 0;
4808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			}
4818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			if (net_ratelimit()) {
4828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				printk(KERN_DEBUG "TKIP: ICV error detected: STA="
4830ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches				"%pM\n", hdr->addr2);
4848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			}
4858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkey->dot11RSNAStatsTKIPICVErrors++;
4868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			return -5;
4878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
4888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
4908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Update real counters only after Michael MIC verification has
4928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	 * completed */
4938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->rx_iv32_new = iv32;
4948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->rx_iv16_new = iv16;
4958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
4968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Remove IV and ICV */
4978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memmove(skb->data + 8, skb->data, hdr_len);
4988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	skb_pull(skb, 8);
4998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	skb_trim(skb, skb->len - 4);
5008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return keyidx;
5028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
5038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
505e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab		       u8 * data, size_t data_len, u8 * mic)
5068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
507e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	struct hash_desc desc;
508e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	struct scatterlist sg[2];
5098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
510e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	if (tfm_michael == NULL) {
511e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab		printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
512e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab		return -1;
513e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	}
514f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
515e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	sg_init_table(sg, 2);
516e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	sg_set_buf(&sg[0], hdr, 16);
517e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	sg_set_buf(&sg[1], data, data_len);
5188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
519e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	if (crypto_hash_setkey(tfm_michael, key, 8))
520e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab		return -1;
5218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
522e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	desc.tfm = tfm_michael;
523e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	desc.flags = 0;
524e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	return crypto_hash_digest(&desc, sg, data_len + 16, mic);
5258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
5268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic void michael_mic_hdr(struct sk_buff *skb, u8 *hdr)
5288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
5298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_hdr_4addr *hdr11;
5308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr11 = (struct ieee80211_hdr_4addr *) skb->data;
5328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	switch (le16_to_cpu(hdr11->frame_ctl) &
5338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
5348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	case IEEE80211_FCTL_TODS:
5358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
5368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
5378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		break;
5388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	case IEEE80211_FCTL_FROMDS:
5398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
5408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
5418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		break;
5428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
5438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
5448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
5458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		break;
5468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	case 0:
5478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
5488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
5498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		break;
5508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
5518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr[12] = 0; /* priority */
5538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
5558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
5568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv)
5598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
5608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkey = priv;
5618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 *pos;
5628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_hdr_4addr *hdr;
5638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr = (struct ieee80211_hdr_4addr *) skb->data;
5658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
5678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "Invalid packet for Michael MIC add "
5688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       "(tailroom=%d hdr_len=%d skb->len=%d)\n",
5698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       skb_tailroom(skb), hdr_len, skb->len);
5708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
5718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
5728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	michael_mic_hdr(skb, tkey->tx_hdr);
5748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	// { david, 2006.9.1
5768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	// fix the wpa process with wmm enabled.
5778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
5788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
5798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
5808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	// }
5818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	pos = skb_put(skb, 8);
582f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehab
5838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
5848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
5858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
5868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return 0;
5888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
5898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic void ieee80211_michael_mic_failure(struct net_device *dev,
5918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				       struct ieee80211_hdr_4addr *hdr,
5928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				       int keyidx)
5938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
5948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	union iwreq_data wrqu;
5958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct iw_michaelmicfailure ev;
5968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
5978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* TODO: needed parameters: count, keyid, key type, TSC */
5988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memset(&ev, 0, sizeof(ev));
5998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
6008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (hdr->addr1[0] & 0x01)
6018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		ev.flags |= IW_MICFAILURE_GROUP;
6028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
6038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		ev.flags |= IW_MICFAILURE_PAIRWISE;
6048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	ev.src_addr.sa_family = ARPHRD_ETHER;
6058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
6068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memset(&wrqu, 0, sizeof(wrqu));
6078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	wrqu.data.length = sizeof(ev);
6088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev);
6098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
6108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
6128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				     int hdr_len, void *priv)
6138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
6148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkey = priv;
6158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	u8 mic[8];
6168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_hdr_4addr *hdr;
6178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	hdr = (struct ieee80211_hdr_4addr *) skb->data;
6198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tkey->key_set)
6218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
6228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	michael_mic_hdr(skb, tkey->rx_hdr);
6248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	// { david, 2006.9.1
6258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	// fix the wpa process with wmm enabled.
6268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if(IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) {
6278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07;
6288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
6298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	// }
6308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
6328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
633e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab		return -1;
6348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
6358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		struct ieee80211_hdr_4addr *hdr;
6368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		hdr = (struct ieee80211_hdr_4addr *) skb->data;
6378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		printk(KERN_DEBUG "%s: Michael MIC verification failed for "
6380ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches		       "MSDU from %pM keyidx=%d\n",
6390ee9f67c4028500a4348e8bc87ee7ec1139b8259Joe Perches		       skb->dev ? skb->dev->name : "N/A", hdr->addr2,
6408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		       keyidx);
6418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (skb->dev)
6428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
6438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->dot11RSNAStatsTKIPLocalMICFailures++;
6448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
6458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
6468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	/* Update TSC counters for RX now that the packet verification has
6488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	 * completed. */
6498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->rx_iv32 = tkey->rx_iv32_new;
6508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->rx_iv16 = tkey->rx_iv16_new;
6518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	skb_trim(skb, skb->len - 8);
6538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return 0;
6558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
6568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv)
6598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
6608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkey = priv;
6618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	int keyidx;
6628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_hash *tfm = tkey->tx_tfm_michael;
6638fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
6648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
6658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
6668fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	keyidx = tkey->key_idx;
6688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memset(tkey, 0, sizeof(*tkey));
6698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->key_idx = keyidx;
6708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->tx_tfm_michael = tfm;
6718fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->tx_tfm_arc4 = tfm2;
6728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->rx_tfm_michael = tfm3;
6738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	tkey->rx_tfm_arc4 = tfm4;
6748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (len == TKIP_KEY_LEN) {
6768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		memcpy(tkey->key, key, TKIP_KEY_LEN);
6778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->key_set = 1;
6788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
6798fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (seq) {
6808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
6818fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang				(seq[3] << 8) | seq[2];
6828fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			tkey->rx_iv16 = (seq[1] << 8) | seq[0];
6838fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		}
6848fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	} else if (len == 0)
6858fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		tkey->key_set = 0;
6868fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	else
6878fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
6888fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6898fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return 0;
6908fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
6918fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6928fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6938fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv)
6948fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
6958fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkey = priv;
6968fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
6978fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (len < TKIP_KEY_LEN)
6988fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return -1;
6998fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7008fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (!tkey->key_set)
7018fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		return 0;
7028fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	memcpy(key, tkey->key, TKIP_KEY_LEN);
7038fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7048fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	if (seq) {
7058fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		/* Return the sequence number of the last transmitted frame. */
7068fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		u16 iv16 = tkey->tx_iv16;
7078fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		u32 iv32 = tkey->tx_iv32;
7088fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		if (iv16 == 0)
7098fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang			iv32--;
7108fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		iv16--;
7118fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		seq[0] = tkey->tx_iv16;
7128fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		seq[1] = tkey->tx_iv16 >> 8;
7138fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		seq[2] = tkey->tx_iv32;
7148fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		seq[3] = tkey->tx_iv32 >> 8;
7158fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		seq[4] = tkey->tx_iv32 >> 16;
7168fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		seq[5] = tkey->tx_iv32 >> 24;
7178fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	}
7188fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7198fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return TKIP_KEY_LEN;
7208fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
7218fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7228fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7238fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic char * ieee80211_tkip_print_stats(char *p, void *priv)
7248fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
7258fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	struct ieee80211_tkip_data *tkip = priv;
7268fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
7278fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     "tx_pn=%02x%02x%02x%02x%02x%02x "
7288fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     "rx_pn=%02x%02x%02x%02x%02x%02x "
7298fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     "replays=%d icv_errors=%d local_mic_failures=%d\n",
7308fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->key_idx, tkip->key_set,
7318fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->tx_iv32 >> 24) & 0xff,
7328fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->tx_iv32 >> 16) & 0xff,
7338fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->tx_iv32 >> 8) & 0xff,
7348fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->tx_iv32 & 0xff,
7358fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->tx_iv16 >> 8) & 0xff,
7368fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->tx_iv16 & 0xff,
7378fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->rx_iv32 >> 24) & 0xff,
7388fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->rx_iv32 >> 16) & 0xff,
7398fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->rx_iv32 >> 8) & 0xff,
7408fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->rx_iv32 & 0xff,
7418fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     (tkip->rx_iv16 >> 8) & 0xff,
7428fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->rx_iv16 & 0xff,
7438fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->dot11RSNAStatsTKIPReplays,
7448fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->dot11RSNAStatsTKIPICVErrors,
7458fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang		     tkip->dot11RSNAStatsTKIPLocalMICFailures);
7468fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return p;
7478fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
7488fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7498fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7508fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangstatic struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
7518fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.name			= "TKIP",
7528fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.init			= ieee80211_tkip_init,
7538fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.deinit			= ieee80211_tkip_deinit,
7548fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.encrypt_mpdu		= ieee80211_tkip_encrypt,
7558fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.decrypt_mpdu		= ieee80211_tkip_decrypt,
7568fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.encrypt_msdu		= ieee80211_michael_mic_add,
7578fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.decrypt_msdu		= ieee80211_michael_mic_verify,
7588fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.set_key		= ieee80211_tkip_set_key,
7598fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.get_key		= ieee80211_tkip_get_key,
7608fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.print_stats		= ieee80211_tkip_print_stats,
7618fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.extra_prefix_len	= 4 + 4, /* IV + ExtIV */
7628fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	.extra_postfix_len	= 8 + 4, /* MIC + ICV */
763e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	.owner			= THIS_MODULE,
7648fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang};
7658fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
766f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehabint __init ieee80211_crypto_tkip_init(void)
7678fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
7688fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
7698fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
7708fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
771f61fb9356d20977258bb59a8d9f1857d2c58ac98Mauro Carvalho Chehabvoid __exit ieee80211_crypto_tkip_exit(void)
7728fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
7738fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang	ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
7748fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
7758fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang
7768fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuangvoid ieee80211_tkip_null(void)
7778fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang{
7788fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang//    printk("============>%s()\n", __FUNCTION__);
779e406322b4b963e622f41d76193d8ca9e5435adb8Mauro Carvalho Chehab	return;
7808fc8598e61f6f384f3eaf1d9b09500c12af47b37Jerry Chuang}
781