[MAC80211]: embed key conf in key, fix driver interface

This patch embeds the struct ieee80211_key_conf into struct ieee80211_key
and thus avoids allocations and having data present twice.

This required some more changes:
 1) The removal of the IEEE80211_KEY_DEFAULT_TX_KEY key flag.
    This flag isn't used by drivers nor should it be since
    we have a set_key_idx() callback. Maybe that callback needs
    to be extended to include the key conf, but only a driver that
    requires it will tell.
 2) The removal of the IEEE80211_KEY_DEFAULT_WEP_ONLY key flag.
    This flag is global, so it shouldn't be passed in the key
    conf structure. Pass it to the function instead.

Also, this patch removes the AID parameter to the set_key() callback
because it is currently unused and the hardware currently cannot know
about the AID anyway. I suspect this was used with some hardware that
actually selected the AID itself, but that functionality was removed.

Additionally, I've removed the ALG_NULL key algorithm since we have
ALG_NONE.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Michael Wu <flamingice@sourmilk.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 077f907..246938c 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -14,17 +14,17 @@
 #include "debugfs.h"
 #include "debugfs_key.h"
 
-#define KEY_READ(name, buflen, format_string)				\
+#define KEY_READ(name, prop, buflen, format_string)			\
 static ssize_t key_##name##_read(struct file *file,			\
 				 char __user *userbuf,			\
 				 size_t count, loff_t *ppos)		\
 {									\
 	char buf[buflen];						\
 	struct ieee80211_key *key = file->private_data;			\
-	int res = scnprintf(buf, buflen, format_string, key->name);	\
+	int res = scnprintf(buf, buflen, format_string, key->prop);	\
 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
 }
-#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n")
+#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n")
 
 #define KEY_OPS(name)							\
 static const struct file_operations key_ ##name## _ops = {		\
@@ -36,10 +36,25 @@
 		 KEY_READ_##format(name)				\
 		 KEY_OPS(name)
 
-KEY_FILE(keylen, D);
-KEY_FILE(force_sw_encrypt, D);
-KEY_FILE(keyidx, D);
-KEY_FILE(hw_key_idx, D);
+#define KEY_CONF_READ(name, buflen, format_string)			\
+	KEY_READ(conf_##name, conf.name, buflen, format_string)
+#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n")
+#define KEY_CONF_READ_X(name) KEY_CONF_READ(name, 20, "0x%x\n")
+
+#define KEY_CONF_OPS(name)						\
+static const struct file_operations key_ ##name## _ops = {		\
+	.read = key_conf_##name##_read,					\
+	.open = mac80211_open_file_generic,				\
+}
+
+#define KEY_CONF_FILE(name, format)					\
+		 KEY_CONF_READ_##format(name)				\
+		 KEY_CONF_OPS(name)
+
+KEY_CONF_FILE(keylen, D);
+KEY_CONF_FILE(keyidx, D);
+KEY_CONF_FILE(hw_key_idx, D);
+KEY_CONF_FILE(flags, X);
 KEY_FILE(tx_rx_count, D);
 
 static ssize_t key_algorithm_read(struct file *file,
@@ -49,7 +64,7 @@
 	char *alg;
 	struct ieee80211_key *key = file->private_data;
 
-	switch (key->alg) {
+	switch (key->conf.alg) {
 	case ALG_WEP:
 		alg = "WEP\n";
 		break;
@@ -74,7 +89,7 @@
 	int len;
 	struct ieee80211_key *key = file->private_data;
 
-	switch (key->alg) {
+	switch (key->conf.alg) {
 	case ALG_WEP:
 		len = scnprintf(buf, sizeof(buf), "\n");
 		break;
@@ -103,7 +118,7 @@
 	int i, len;
 	const u8 *rpn;
 
-	switch (key->alg) {
+	switch (key->conf.alg) {
 	case ALG_WEP:
 		len = scnprintf(buf, sizeof(buf), "\n");
 		break;
@@ -139,7 +154,7 @@
 	char buf[20];
 	int len;
 
-	if (key->alg != ALG_CCMP)
+	if (key->conf.alg != ALG_CCMP)
 		return 0;
 	len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
 	return simple_read_from_buffer(userbuf, count, ppos, buf, len);
@@ -150,12 +165,12 @@
 			    size_t count, loff_t *ppos)
 {
 	struct ieee80211_key *key = file->private_data;
-	int i, res, bufsize = 2*key->keylen+2;
+	int i, res, bufsize = 2 * key->conf.keylen + 2;
 	char *buf = kmalloc(bufsize, GFP_KERNEL);
 	char *p = buf;
 
-	for (i = 0; i < key->keylen; i++)
-		p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]);
+	for (i = 0; i < key->conf.keylen; i++)
+		p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]);
 	p += scnprintf(p, bufsize+buf-p, "\n");
 	res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 	kfree(buf);
@@ -185,7 +200,7 @@
 		return;
 
 	DEBUGFS_ADD(keylen);
-	DEBUGFS_ADD(force_sw_encrypt);
+	DEBUGFS_ADD(flags);
 	DEBUGFS_ADD(keyidx);
 	DEBUGFS_ADD(hw_key_idx);
 	DEBUGFS_ADD(tx_rx_count);
@@ -205,7 +220,7 @@
 		return;
 
 	DEBUGFS_DEL(keylen);
-	DEBUGFS_DEL(force_sw_encrypt);
+	DEBUGFS_DEL(flags);
 	DEBUGFS_DEL(keyidx);
 	DEBUGFS_DEL(hw_key_idx);
 	DEBUGFS_DEL(tx_rx_count);
@@ -227,7 +242,7 @@
 	if (!sdata->debugfsdir)
 		return;
 
-	sprintf(buf, "../keys/%d", sdata->default_key->keyidx);
+	sprintf(buf, "../keys/%d", sdata->default_key->conf.keyidx);
 	sdata->debugfs.default_key =
 		debugfs_create_symlink("default_key", sdata->debugfsdir, buf);
 }
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 50d7af3..5d5034f 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -890,7 +890,7 @@
 	if (!key)
 		goto no_key;
 
-	switch (key->alg) {
+	switch (key->conf.alg) {
 	case ALG_WEP:
 		iv_len = WEP_IV_LEN;
 		mic_len = WEP_ICV_LEN;
@@ -907,7 +907,8 @@
 		goto no_key;
 	}
 
-	if (skb->len >= mic_len && key->force_sw_encrypt)
+	if (skb->len >= mic_len &&
+	    (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT))
 		skb_trim(skb, skb->len - mic_len);
 	if (skb->len >= iv_len && skb->len > hdrlen) {
 		memmove(skb->data + iv_len, skb->data, hdrlen);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ef633a04..cc87e9d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -816,9 +816,6 @@
 int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* key handling */
-struct ieee80211_key_conf *
-ieee80211_key_data2conf(struct ieee80211_local *local,
-			const struct ieee80211_key *data);
 struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
 					  int idx, size_t key_len, gfp_t flags);
 void ieee80211_key_free(struct ieee80211_key *key);
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 6100917..3e59afa 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -227,7 +227,8 @@
 		memset(addr, 0xff, ETH_ALEN);
 		if (local->ops->set_key)
 			local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
-					    local->keys[i], 0);
+					    local->keys[i],
+					    local->default_wep_only);
 #endif
 		ieee80211_key_free(sdata->keys[i]);
 		sdata->keys[i] = NULL;
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 9964f05..380670c 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -31,29 +31,20 @@
 					struct sta_info *sta, u8 addr[ETH_ALEN],
 					struct ieee80211_key *key)
 {
-	struct ieee80211_key_conf *keyconf = NULL;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
 	/* default to sw encryption; this will be cleared by low-level
 	 * driver if the hw supports requested encryption */
 	if (key)
-		key->force_sw_encrypt = 1;
+		key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
 
-	if (key && local->ops->set_key &&
-	    (keyconf = ieee80211_key_data2conf(local, key))) {
+	if (key && local->ops->set_key) {
 		if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
-				       keyconf, sta ? sta->aid : 0)) {
-			key->force_sw_encrypt = 1;
-			key->hw_key_idx = HW_KEY_IDX_INVALID;
-		} else {
-			key->force_sw_encrypt =
-				!!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
-			key->hw_key_idx =
-				keyconf->hw_key_idx;
-
+					&key->conf, local->default_wep_only)) {
+			key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
+			key->conf.hw_key_idx = HW_KEY_IDX_INVALID;
 		}
 	}
-	kfree(keyconf);
 }
 
 
@@ -66,7 +57,6 @@
 	struct sta_info *sta;
 	struct ieee80211_key *key, *old_key;
 	int try_hwaccel = 1;
-	struct ieee80211_key_conf *keyconf;
 	struct ieee80211_sub_if_data *sdata;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -154,18 +144,16 @@
 	}
 
 	if (alg == ALG_NONE) {
-		keyconf = NULL;
 		if (try_hwaccel && key &&
-		    key->hw_key_idx != HW_KEY_IDX_INVALID &&
+		    key->conf.hw_key_idx != HW_KEY_IDX_INVALID &&
 		    local->ops->set_key &&
-		    (keyconf = ieee80211_key_data2conf(local, key)) != NULL &&
 		    local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-				       sta_addr, keyconf, sta ? sta->aid : 0)) {
+					sta_addr, &key->conf,
+					local->default_wep_only)) {
 			printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
 			       " failed\n", dev->name);
 			ret = -EINVAL;
 		}
-		kfree(keyconf);
 
 		if (set_tx_key || sdata->default_key == key) {
 			ieee80211_debugfs_key_remove_default(sdata);
@@ -189,22 +177,20 @@
 
 		/* default to sw encryption; low-level driver sets these if the
 		 * requested encryption is supported */
-		key->hw_key_idx = HW_KEY_IDX_INVALID;
-		key->force_sw_encrypt = 1;
+		key->conf.hw_key_idx = HW_KEY_IDX_INVALID;
+		key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
 
-		key->alg = alg;
-		key->keyidx = idx;
-		key->keylen = key_len;
-		memcpy(key->key, _key, key_len);
-		if (set_tx_key)
-			key->default_tx_key = 1;
+		key->conf.alg = alg;
+		key->conf.keyidx = idx;
+		key->conf.keylen = key_len;
+		memcpy(key->conf.key, _key, key_len);
 
 		if (alg == ALG_CCMP) {
 			/* Initialize AES key state here as an optimization
 			 * so that it does not need to be initialized for every
 			 * packet. */
 			key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
-				key->key);
+				key->conf.key);
 			if (!key->u.ccmp.tfm) {
 				ret = -ENOMEM;
 				goto err_free;
@@ -941,43 +927,38 @@
 static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
 					 struct ieee80211_key *key)
 {
-	struct ieee80211_key_conf *keyconf;
 	u8 addr[ETH_ALEN];
 
-	if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt ||
+	if (!key || key->conf.alg != ALG_WEP ||
+	    !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) ||
 	    (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
 		return;
 
 	memset(addr, 0xff, ETH_ALEN);
-	keyconf = ieee80211_key_data2conf(local, key);
-	if (keyconf && local->ops->set_key &&
+
+	if (local->ops->set_key)
 	    local->ops->set_key(local_to_hw(local),
-			       SET_KEY, addr, keyconf, 0) == 0) {
-		key->force_sw_encrypt =
-			!!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
-		key->hw_key_idx = keyconf->hw_key_idx;
-	}
-	kfree(keyconf);
+				SET_KEY, addr, &key->conf,
+				local->default_wep_only);
 }
 
 
 static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local,
 					  struct ieee80211_key *key)
 {
-	struct ieee80211_key_conf *keyconf;
 	u8 addr[ETH_ALEN];
 
-	if (!key || key->alg != ALG_WEP || key->force_sw_encrypt ||
+	if (!key || key->conf.alg != ALG_WEP ||
+	    (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) ||
 	    (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
 		return;
 
 	memset(addr, 0xff, ETH_ALEN);
-	keyconf = ieee80211_key_data2conf(local, key);
-	if (keyconf && local->ops->set_key)
+	if (local->ops->set_key)
 		local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-				   addr, keyconf, 0);
-	kfree(keyconf);
-	key->force_sw_encrypt = 1;
+				    addr, &key->conf,
+				    local->default_wep_only);
+	key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
 }
 
 
@@ -1341,9 +1322,9 @@
 		return 0;
 	}
 
-	memcpy(key, sdata->keys[idx]->key,
-	       min((int)erq->length, sdata->keys[idx]->keylen));
-	erq->length = sdata->keys[idx]->keylen;
+	memcpy(key, sdata->keys[idx]->conf.key,
+	       min((int)erq->length, sdata->keys[idx]->conf.keylen));
+	erq->length = sdata->keys[idx]->conf.keylen;
 	erq->flags |= IW_ENCODE_ENABLED;
 
 	return 0;
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h
index c333849..1b5e539 100644
--- a/net/mac80211/ieee80211_key.h
+++ b/net/mac80211/ieee80211_key.h
@@ -44,8 +44,6 @@
 struct ieee80211_key {
 	struct kref kref;
 
-	int hw_key_idx; /* filled and used by low-level driver */
-	ieee80211_key_alg alg;
 	union {
 		struct {
 			/* last used TSC */
@@ -73,22 +71,16 @@
 			u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
 		} ccmp;
 	} u;
-	int tx_rx_count; /* number of times this key has been used */
-	int keylen;
 
-	/* if the low level driver can provide hardware acceleration it should
-	 * clear this flag */
-	unsigned int force_sw_encrypt:1;
-	unsigned int default_tx_key:1; /* This key is the new default TX key
-					* (used only for broadcast keys). */
-	s8 keyidx; /* WEP key index */
+	/* number of times this key has been used */
+	int tx_rx_count;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct {
 		struct dentry *stalink;
 		struct dentry *dir;
 		struct dentry *keylen;
-		struct dentry *force_sw_encrypt;
+		struct dentry *flags;
 		struct dentry *keyidx;
 		struct dentry *hw_key_idx;
 		struct dentry *tx_rx_count;
@@ -100,7 +92,11 @@
 	} debugfs;
 #endif
 
-	u8 key[0];
+	/*
+	 * key config, must be last because it contains key
+	 * material as variable length member
+	 */
+	struct ieee80211_key_conf conf;
 };
 
 #endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index fe94ebfc..a244327 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -904,7 +904,7 @@
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (!sdata || !sdata->default_key ||
-	    sdata->default_key->alg != ALG_WEP)
+	    sdata->default_key->conf.alg != ALG_WEP)
 		return 0;
 	return 1;
 }
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index b67558c..92d994f 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -13,32 +13,6 @@
 #include "debugfs_key.h"
 #include "aes_ccm.h"
 
-struct ieee80211_key_conf *
-ieee80211_key_data2conf(struct ieee80211_local *local,
-			const struct ieee80211_key *data)
-{
-	struct ieee80211_key_conf *conf;
-
-	conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC);
-	if (!conf)
-		return NULL;
-
-	conf->hw_key_idx = data->hw_key_idx;
-	conf->alg = data->alg;
-	conf->keylen = data->keylen;
-	conf->flags = 0;
-	if (data->force_sw_encrypt)
-		conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
-	conf->keyidx = data->keyidx;
-	if (data->default_tx_key)
-		conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY;
-	if (local->default_wep_only)
-		conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY;
-	memcpy(conf->key, data->key, data->keylen);
-
-	return conf;
-}
-
 struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
 					  int idx, size_t key_len, gfp_t flags)
 {
@@ -56,7 +30,7 @@
 	struct ieee80211_key *key;
 
 	key = container_of(kref, struct ieee80211_key, kref);
-	if (key->alg == ALG_CCMP)
+	if (key->conf.alg == ALG_CCMP)
 		ieee80211_aes_key_free(key->u.ccmp.tfm);
 	ieee80211_debugfs_key_remove(key);
 	kfree(key);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index b52e330..976b646 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -374,7 +374,7 @@
 		 * pairwise or station-to-station keys, but for WEP we allow
 		 * using a key index as well.
 		 */
-		if (rx->key && rx->key->alg != ALG_WEP &&
+		if (rx->key && rx->key->conf.alg != ALG_WEP &&
 		    !is_multicast_ether_addr(hdr->addr1))
 			rx->key = NULL;
 	}
@@ -522,18 +522,15 @@
 {
 	if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
 	    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-	    !rx->key || rx->key->alg != ALG_WEP ||
+	    !rx->key || rx->key->conf.alg != ALG_WEP ||
 	    !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
 		return TXRX_CONTINUE;
 
 	/* Check for weak IVs, if hwaccel did not remove IV from the frame */
 	if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) ||
-	    rx->key->force_sw_encrypt) {
-		u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key);
-		if (iv) {
+	    (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT))
+		if (ieee80211_wep_is_weak_iv(rx->skb, rx->key))
 			rx->sta->wep_weak_iv_count++;
-		}
-	}
 
 	return TXRX_CONTINUE;
 }
@@ -541,7 +538,7 @@
 static ieee80211_txrx_result
 ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx)
 {
-	if ((rx->key && rx->key->alg != ALG_WEP) ||
+	if ((rx->key && rx->key->conf.alg != ALG_WEP) ||
 	    !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
 	    ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
 	     ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
@@ -556,7 +553,7 @@
 	}
 
 	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) ||
-	    rx->key->force_sw_encrypt) {
+	    (rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
 		if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
@@ -680,7 +677,7 @@
 		/* This is the first fragment of a new frame. */
 		entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
 						 rx->u.rx.queue, &(rx->skb));
-		if (rx->key && rx->key->alg == ALG_CCMP &&
+		if (rx->key && rx->key->conf.alg == ALG_CCMP &&
 		    (rx->fc & IEEE80211_FCTL_PROTECTED)) {
 			/* Store CCMP PN so that we can verify that the next
 			 * fragment has a sequential PN value. */
@@ -707,7 +704,7 @@
 	if (entry->ccmp) {
 		int i;
 		u8 pn[CCMP_PN_LEN], *rpn;
-		if (!rx->key || rx->key->alg != ALG_CCMP)
+		if (!rx->key || rx->key->conf.alg != ALG_CCMP)
 			return TXRX_DROP;
 		memcpy(pn, entry->last_pn, CCMP_PN_LEN);
 		for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
@@ -900,7 +897,8 @@
 	 * uploaded to the hardware.
 	 */
 	if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) &&
-	    (!rx->key || !rx->key->force_sw_encrypt))
+	    (!rx->key ||
+	     !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)))
 		return TXRX_CONTINUE;
 
 	/* Drop unencrypted frames if key is set. */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 34245b8..7e10c69 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -228,23 +228,20 @@
 
 	if (sta->key) {
 		if (local->ops->set_key) {
-			struct ieee80211_key_conf *key;
-			key = ieee80211_key_data2conf(local, sta->key);
-			if (key) {
-				local->ops->set_key(local_to_hw(local),
-						   DISABLE_KEY,
-						   sta->addr, key, sta->aid);
-				kfree(key);
-			}
+			local->ops->set_key(local_to_hw(local),
+					   DISABLE_KEY, sta->addr,
+					   &sta->key->conf,
+					   local->default_wep_only);
 		}
 	} else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) {
 		struct ieee80211_key_conf conf;
 		memset(&conf, 0, sizeof(conf));
 		conf.hw_key_idx = sta->key_idx_compression;
-		conf.alg = ALG_NULL;
+		conf.alg = ALG_NONE;
 		conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
 		local->ops->set_key(local_to_hw(local), DISABLE_KEY,
-				   sta->addr, &conf, sta->aid);
+				    sta->addr, &conf,
+				    local->default_wep_only);
 		sta->key_idx_compression = HW_KEY_IDX_INVALID;
 	}
 
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 4162172..b9c1d54 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -182,7 +182,7 @@
 	*pos++ = iv0;
 	*pos++ = iv1;
 	*pos++ = iv2;
-	*pos++ = (key->keyidx << 6) | (1 << 5) /* Ext IV */;
+	*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
 	*pos++ = key->u.tkip.iv32 & 0xff;
 	*pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
 	*pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
@@ -194,7 +194,7 @@
 void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
 				  u16 *phase1key)
 {
-	tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+	tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
 			   key->u.tkip.iv32, phase1key);
 }
 
@@ -204,12 +204,13 @@
 	/* Calculate per-packet key */
 	if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
 		/* IV16 wrapped around - perform TKIP phase 1 */
-		tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+		tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
 				   key->u.tkip.iv32, key->u.tkip.p1k);
 		key->u.tkip.tx_initialized = 1;
 	}
 
-	tkip_mixing_phase2(key->u.tkip.p1k, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+	tkip_mixing_phase2(key->u.tkip.p1k,
+			   &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
 			   key->u.tkip.iv16, rc4key);
 }
 
@@ -266,7 +267,7 @@
 	if (!(keyid & (1 << 5)))
 		return TKIP_DECRYPT_NO_EXT_IV;
 
-	if ((keyid >> 6) != key->keyidx)
+	if ((keyid >> 6) != key->conf.keyidx)
 		return TKIP_DECRYPT_INVALID_KEYIDX;
 
 	if (key->u.tkip.rx_initialized[queue] &&
@@ -293,7 +294,7 @@
 	    key->u.tkip.iv32_rx[queue] != iv32) {
 		key->u.tkip.rx_initialized[queue] = 1;
 		/* IV16 wrapped around - perform TKIP phase 1 */
-		tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+		tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
 				   iv32, key->u.tkip.p1k_rx[queue]);
 #ifdef CONFIG_TKIP_DEBUG
 		{
@@ -302,7 +303,8 @@
 			       " TK=", MAC_ARG(ta));
 			for (i = 0; i < 16; i++)
 				printk("%02x ",
-				       key->key[ALG_TKIP_TEMP_ENCR_KEY + i]);
+				       key->conf.key[
+						ALG_TKIP_TEMP_ENCR_KEY + i]);
 			printk("\n");
 			printk(KERN_DEBUG "TKIP decrypt: P1K=");
 			for (i = 0; i < 5; i++)
@@ -313,7 +315,7 @@
 	}
 
 	tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
-			   &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+			   &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
 			   iv16, rc4key);
 #ifdef CONFIG_TKIP_DEBUG
 	{
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ddb104a..684f928 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -539,11 +539,11 @@
 
 static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
 {
-	if (tx->key->force_sw_encrypt) {
+	if (tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) {
 		if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
 			return -1;
 	} else {
-		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
 		if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
 			if (ieee80211_wep_add_iv(tx->local, skb, tx->key) ==
 			    NULL)
@@ -561,7 +561,7 @@
 
 	fc = le16_to_cpu(hdr->frame_control);
 
-	if (!tx->key || tx->key->alg != ALG_WEP ||
+	if (!tx->key || tx->key->conf.alg != ALG_WEP ||
 	    ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
 	     ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
 	      (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 1ad3d75..0b19e89 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -67,7 +67,7 @@
 			  struct ieee80211_key *key, u8 *iv)
 {
 	local->wep_iv++;
-	if (ieee80211_wep_weak_iv(local->wep_iv, key->keylen))
+	if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen))
 		local->wep_iv += 0x0100;
 
 	if (!iv)
@@ -76,7 +76,7 @@
 	*iv++ = (local->wep_iv >> 16) & 0xff;
 	*iv++ = (local->wep_iv >> 8) & 0xff;
 	*iv++ = local->wep_iv & 0xff;
-	*iv++ = key->keyidx << 6;
+	*iv++ = key->conf.keyidx << 6;
 }
 
 
@@ -159,10 +159,10 @@
 	u8 *rc4key, *iv;
 	size_t len;
 
-	if (!key || key->alg != ALG_WEP)
+	if (!key || key->conf.alg != ALG_WEP)
 		return -1;
 
-	klen = 3 + key->keylen;
+	klen = 3 + key->conf.keylen;
 	rc4key = kmalloc(klen, GFP_ATOMIC);
 	if (!rc4key)
 		return -1;
@@ -179,7 +179,7 @@
 	memcpy(rc4key, iv, 3);
 
 	/* Copy rest of the WEP key (the secret part) */
-	memcpy(rc4key + 3, key->key, key->keylen);
+	memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
 
 	/* Add room for ICV */
 	skb_put(skb, WEP_ICV_LEN);
@@ -251,10 +251,10 @@
 
 	keyidx = skb->data[hdrlen + 3] >> 6;
 
-	if (!key || keyidx != key->keyidx || key->alg != ALG_WEP)
+	if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP)
 		return -1;
 
-	klen = 3 + key->keylen;
+	klen = 3 + key->conf.keylen;
 
 	rc4key = kmalloc(klen, GFP_ATOMIC);
 	if (!rc4key)
@@ -264,7 +264,7 @@
 	memcpy(rc4key, skb->data + hdrlen, 3);
 
 	/* Copy rest of the WEP key (the secret part) */
-	memcpy(rc4key + 3, key->key, key->keylen);
+	memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
 
 	if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
 				       skb->data + hdrlen + WEP_IV_LEN,
@@ -321,7 +321,7 @@
 	ivpos = skb->data + hdrlen;
 	iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
 
-	if (ieee80211_wep_weak_iv(iv, key->keylen))
+	if (ieee80211_wep_weak_iv(iv, key->conf.keylen))
 		return ivpos;
 
 	return NULL;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 1142b42..4a2a9aa 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -82,14 +82,14 @@
 
 	fc = tx->fc;
 
-	if (!tx->key || tx->key->alg != ALG_TKIP || skb->len < 24 ||
+	if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
 	    !WLAN_FC_DATA_PRESENT(fc))
 		return TXRX_CONTINUE;
 
 	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
 		return TXRX_DROP;
 
-	if (!tx->key->force_sw_encrypt &&
+	if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) &&
 	    !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
 	    !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) &&
 	    !wpa_test) {
@@ -114,8 +114,8 @@
 #else
 	authenticator = 1;
 #endif
-	key = &tx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
-			    ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
+	key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
+				 ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
 	mic = skb_put(skb, MICHAEL_MIC_LEN);
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 
@@ -141,12 +141,12 @@
 	if (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC)
 		return TXRX_CONTINUE;
 
-	if (!rx->key || rx->key->alg != ALG_TKIP ||
+	if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
 	    !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
 		return TXRX_CONTINUE;
 
 	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-	    !rx->key->force_sw_encrypt) {
+	    !(rx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
 		if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
 			if (skb->len < MICHAEL_MIC_LEN)
 				return TXRX_DROP;
@@ -169,8 +169,8 @@
 #else
 	authenticator = 1;
 #endif
-	key = &rx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
-			    ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
+	key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
+				 ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
 		if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
@@ -179,7 +179,7 @@
 		printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
 		       MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
 
-		mac80211_ev_michael_mic_failure(rx->dev, rx->key->keyidx,
+		mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
 						(void *) skb->data);
 		return TXRX_DROP;
 	}
@@ -205,7 +205,11 @@
 	hdrlen = ieee80211_get_hdrlen(fc);
 	len = skb->len - hdrlen;
 
-	tailneed = !tx->key->force_sw_encrypt ? 0 : TKIP_ICV_LEN;
+	if (tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)
+		tailneed = TKIP_ICV_LEN;
+	else
+		tailneed = 0;
+
 	if ((skb_headroom(skb) < TKIP_IV_LEN ||
 	     skb_tailroom(skb) < tailneed)) {
 		I802_DEBUG_INC(tx->local->tx_expand_skb_head);
@@ -223,7 +227,7 @@
 	if (key->u.tkip.iv16 == 0)
 		key->u.tkip.iv32++;
 
-	if (!tx->key->force_sw_encrypt) {
+	if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
 		u32 flags = tx->local->hw.flags;
 		hdr = (struct ieee80211_hdr *)skb->data;
 
@@ -250,7 +254,7 @@
 					    ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
 		}
 
-		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
 		return 0;
 	}
 
@@ -275,18 +279,18 @@
 
 	fc = le16_to_cpu(hdr->frame_control);
 
-	if (!key || key->alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc))
+	if (!key || key->conf.alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc))
 		return TXRX_CONTINUE;
 
 	tx->u.tx.control->icv_len = TKIP_ICV_LEN;
 	tx->u.tx.control->iv_len = TKIP_IV_LEN;
 	ieee80211_tx_set_iswep(tx);
 
-	if (!tx->key->force_sw_encrypt &&
+	if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) &&
 	    !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
 	    !wpa_test) {
 		/* hwaccel - with no need for preallocated room for IV/ICV */
-		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
 		return TXRX_CONTINUE;
 	}
 
@@ -318,7 +322,7 @@
 	fc = le16_to_cpu(hdr->frame_control);
 	hdrlen = ieee80211_get_hdrlen(fc);
 
-	if (!rx->key || rx->key->alg != ALG_TKIP ||
+	if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
 	    !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
 	    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
 		return TXRX_CONTINUE;
@@ -327,7 +331,7 @@
 		return TXRX_DROP;
 
 	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-	    !rx->key->force_sw_encrypt) {
+	    !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
 		if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
 			/* Hardware takes care of all processing, including
 			 * replay protection, so no need to continue here. */
@@ -471,7 +475,10 @@
 	hdrlen = ieee80211_get_hdrlen(fc);
 	len = skb->len - hdrlen;
 
-	tailneed = !key->force_sw_encrypt ? 0 : CCMP_MIC_LEN;
+	if (key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)
+		tailneed = CCMP_MIC_LEN;
+	else
+		tailneed = 0;
 
 	if ((skb_headroom(skb) < CCMP_HDR_LEN ||
 	     skb_tailroom(skb) < tailneed)) {
@@ -495,11 +502,11 @@
 			break;
 	}
 
-	ccmp_pn2hdr(pos, pn, key->keyidx);
+	ccmp_pn2hdr(pos, pn, key->conf.keyidx);
 
-	if (!key->force_sw_encrypt) {
+	if (!(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
 		/* hwaccel - with preallocated room for CCMP header */
-		tx->u.tx.control->key_idx = key->hw_key_idx;
+		tx->u.tx.control->key_idx = key->conf.hw_key_idx;
 		return 0;
 	}
 
@@ -523,18 +530,18 @@
 
 	fc = le16_to_cpu(hdr->frame_control);
 
-	if (!key || key->alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc))
+	if (!key || key->conf.alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc))
 		return TXRX_CONTINUE;
 
 	tx->u.tx.control->icv_len = CCMP_MIC_LEN;
 	tx->u.tx.control->iv_len = CCMP_HDR_LEN;
 	ieee80211_tx_set_iswep(tx);
 
-	if (!tx->key->force_sw_encrypt &&
+	if (!(tx->key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) &&
 	    !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
 		/* hwaccel - with no need for preallocated room for CCMP "
 		 * header or MIC fields */
-		tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
 		return TXRX_CONTINUE;
 	}
 
@@ -569,7 +576,7 @@
 	fc = le16_to_cpu(hdr->frame_control);
 	hdrlen = ieee80211_get_hdrlen(fc);
 
-	if (!key || key->alg != ALG_CCMP ||
+	if (!key || key->conf.alg != ALG_CCMP ||
 	    !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
 	    (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
 		return TXRX_CONTINUE;
@@ -579,7 +586,7 @@
 		return TXRX_DROP;
 
 	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-	    !key->force_sw_encrypt &&
+	    !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT) &&
 	    !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV))
 		return TXRX_CONTINUE;
 
@@ -600,7 +607,7 @@
 	}
 
 	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-	    !key->force_sw_encrypt) {
+	    !(key->conf.flags & IEEE80211_KEY_FORCE_SW_ENCRYPT)) {
 		/* hwaccel has already decrypted frame and verified MIC */
 	} else {
 		u8 *scratch, *b_0, *aad;