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