Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH] Assign next hop address to pending mesh frames once the path is resolved.
From: Johannes Berg @ 2009-07-08 10:40 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, devel
In-Reply-To: <1247032403-8312-1-git-send-email-javier@cozybit.com>

[-- Attachment #1: Type: text/plain, Size: 1321 bytes --]

On Tue, 2009-07-07 at 22:53 -0700, Javier Cardona wrote:
> Regression.  Frames transmitted when a mesh path was wating to be resolved were
> being transmitted with an invalid Receiver Address.

> -	rcu_assign_pointer(mpath->next_hop, sta);
> +	struct sk_buff *skb, *skb_first = NULL;
> +	struct ieee80211_hdr *hdr;
> +
> +	rcu_read_lock();
> +	mpath->next_hop = sta;
> +
> +	while ((skb = skb_dequeue(&mpath->frame_queue)) != skb_first) {
> +		if (!skb_first)
> +			skb_first = skb;
> +		hdr = (struct ieee80211_hdr *) skb->data;
> +		memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
> +		skb_queue_tail(&mpath->frame_queue, skb);
> +	}
> +	if (skb_first)
> +		skb_queue_tail(&mpath->frame_queue, skb_first);
> +
> +	rcu_read_unlock();

Since skb queues have a locks, why use rcu too?

Also I think you should probably use a different pattern -- this looks
prone to breakage, maybe something like

	sk_buff_head tmpq;
	unsigned long flags;

	__skb_queue_head_init(&tmpq);

	spin_lock_irqsave(&frame_queue->lock);

	while (skb = __skb_dequeue(&frame_queue)) {
		hdr = (struct ieee80211_hdr *) skb->data;
		memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
		__skb_queue_tail(&tmpq, skb);
	}

	skb_queue_splice(&tmpq, frame_queue);
	spin_unlock_irqrestore(&frame_queue->lock);

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* [PATCH] nl80211: introduce new key attributes
From: Johannes Berg @ 2009-07-08 11:11 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

We will soon want to nest key attributes into
some new attribute for configuring static WEP
keys at connect() and ibss_join() time, so we
need nested attributes for that. However, key
attributes right now are 'global'. This patch
thus introduces new nested attributes for the
key settings and functions for parsing them.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 include/linux/nl80211.h |   35 ++++++++
 net/wireless/nl80211.c  |  203 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 191 insertions(+), 47 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2009-07-07 14:04:46.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2009-07-07 14:05:19.000000000 +0200
@@ -574,6 +574,9 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_PID: Process ID of a network namespace.
  *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ *	%NL80211_KEY_* sub-attributes
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -701,6 +704,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_PID,
 
+	NL80211_ATTR_KEY,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1329,4 +1334,34 @@ enum nl80211_wpa_versions {
 	NL80211_WPA_VERSION_2 = 1 << 1,
 };
 
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *	keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *	CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+	__NL80211_KEY_INVALID,
+	NL80211_KEY_DATA,
+	NL80211_KEY_IDX,
+	NL80211_KEY_CIPHER,
+	NL80211_KEY_SEQ,
+	NL80211_KEY_DEFAULT,
+	NL80211_KEY_DEFAULT_MGMT,
+
+	/* keep last */
+	__NL80211_KEY_AFTER_LAST,
+	NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
--- wireless-testing.orig/net/wireless/nl80211.c	2009-07-07 14:04:46.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-07-07 14:05:19.000000000 +0200
@@ -77,6 +77,7 @@ static struct nla_policy nl80211_policy[
 	[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
 	[NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
 
+	[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
 	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
 				    .len = WLAN_MAX_KEY_LEN },
 	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
@@ -139,6 +140,18 @@ static struct nla_policy nl80211_policy[
 	[NL80211_ATTR_PID] = { .type = NLA_U32 },
 };
 
+/* policy for the attributes */
+static struct nla_policy
+nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
+	[NL80211_KEY_DATA] = { .type = NLA_BINARY,
+				    .len = WLAN_MAX_KEY_LEN },
+	[NL80211_KEY_IDX] = { .type = NLA_U8 },
+	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
+	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+	[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
+	[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
+};
+
 /* IE validation */
 static bool is_valid_ie_attr(const struct nlattr *attr)
 {
@@ -203,6 +216,100 @@ static int nl80211_msg_put_channel(struc
 
 /* netlink command implementations */
 
+struct key_parse {
+	struct key_params p;
+	int idx;
+	bool def, defmgmt;
+};
+
+static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
+{
+	struct nlattr *tb[NL80211_KEY_MAX + 1];
+	int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
+				   nl80211_key_policy);
+	if (err)
+		return err;
+
+	k->def = !!tb[NL80211_KEY_DEFAULT];
+	k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
+
+	if (tb[NL80211_KEY_IDX])
+		k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
+
+	if (tb[NL80211_KEY_DATA]) {
+		k->p.key = nla_data(tb[NL80211_KEY_DATA]);
+		k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
+	}
+
+	if (tb[NL80211_KEY_SEQ]) {
+		k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
+		k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
+	}
+
+	if (tb[NL80211_KEY_CIPHER])
+		k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
+
+	return 0;
+}
+
+static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
+{
+	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+		k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+		k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+	}
+
+	if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
+		k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
+		k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
+	}
+
+	if (info->attrs[NL80211_ATTR_KEY_IDX])
+		k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+	if (info->attrs[NL80211_ATTR_KEY_CIPHER])
+		k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+	k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
+	k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
+
+	return 0;
+}
+
+static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
+{
+	int err;
+
+	memset(k, 0, sizeof(*k));
+	k->idx = -1;
+
+	if (info->attrs[NL80211_ATTR_KEY])
+		err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
+	else
+		err = nl80211_parse_key_old(info, k);
+
+	if (err)
+		return err;
+
+	if (k->def && k->defmgmt)
+		return -EINVAL;
+
+	if (k->idx != -1) {
+		if (k->defmgmt) {
+			if (k->idx < 4 || k->idx > 5)
+				return -EINVAL;
+		} else if (k->def) {
+			if (k->idx < 0 || k->idx > 3)
+				return -EINVAL;
+		} else {
+			if (k->idx < 0 || k->idx > 5)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
@@ -955,10 +1062,12 @@ static int nl80211_del_interface(struct 
 struct get_key_cookie {
 	struct sk_buff *msg;
 	int error;
+	int idx;
 };
 
 static void get_key_callback(void *c, struct key_params *params)
 {
+	struct nlattr *key;
 	struct get_key_cookie *cookie = c;
 
 	if (params->key)
@@ -973,6 +1082,26 @@ static void get_key_callback(void *c, st
 		NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
 			    params->cipher);
 
+	key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
+	if (!key)
+		goto nla_put_failure;
+
+	if (params->key)
+		NLA_PUT(cookie->msg, NL80211_KEY_DATA,
+			params->key_len, params->key);
+
+	if (params->seq)
+		NLA_PUT(cookie->msg, NL80211_KEY_SEQ,
+			params->seq_len, params->seq);
+
+	if (params->cipher)
+		NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER,
+			    params->cipher);
+
+	NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx);
+
+	nla_nest_end(cookie->msg, key);
+
 	return;
  nla_put_failure:
 	cookie->error = 1;
@@ -1026,6 +1155,7 @@ static int nl80211_get_key(struct sk_buf
 	}
 
 	cookie.msg = msg;
+	cookie.idx = key_idx;
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
@@ -1060,26 +1190,21 @@ static int nl80211_get_key(struct sk_buf
 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
+	struct key_parse key;
 	int err;
 	struct net_device *dev;
-	u8 key_idx;
 	int (*func)(struct wiphy *wiphy, struct net_device *netdev,
 		    u8 key_index);
 
-	if (!info->attrs[NL80211_ATTR_KEY_IDX])
-		return -EINVAL;
-
-	key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
 
-	if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
-		if (key_idx < 4 || key_idx > 5)
-			return -EINVAL;
-	} else if (key_idx > 3)
+	if (key.idx < 0)
 		return -EINVAL;
 
-	/* currently only support setting default key */
-	if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
-	    !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
+	/* only support setting default key */
+	if (!key.def && !key.defmgmt)
 		return -EINVAL;
 
 	rtnl_lock();
@@ -1088,7 +1213,7 @@ static int nl80211_set_key(struct sk_buf
 	if (err)
 		goto unlock_rtnl;
 
-	if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
+	if (key.def)
 		func = rdev->ops->set_default_key;
 	else
 		func = rdev->ops->set_default_mgmt_key;
@@ -1098,13 +1223,13 @@ static int nl80211_set_key(struct sk_buf
 		goto out;
 	}
 
-	err = func(&rdev->wiphy, dev, key_idx);
+	err = func(&rdev->wiphy, dev, key.idx);
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
 		if (func == rdev->ops->set_default_key)
-			dev->ieee80211_ptr->wext.default_key = key_idx;
+			dev->ieee80211_ptr->wext.default_key = key.idx;
 		else
-			dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
+			dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
 	}
 #endif
 
@@ -1123,34 +1248,20 @@ static int nl80211_new_key(struct sk_buf
 	struct cfg80211_registered_device *rdev;
 	int err, i;
 	struct net_device *dev;
-	struct key_params params;
-	u8 key_idx = 0;
+	struct key_parse key;
 	u8 *mac_addr = NULL;
 
-	memset(&params, 0, sizeof(params));
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
 
-	if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+	if (!key.p.key)
 		return -EINVAL;
 
-	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
-		params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
-		params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
-	}
-
-	if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
-		params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
-		params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
-	}
-
-	if (info->attrs[NL80211_ATTR_KEY_IDX])
-		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
-	params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-	if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
+	if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
 		return -EINVAL;
 
 	rtnl_lock();
@@ -1160,7 +1271,7 @@ static int nl80211_new_key(struct sk_buf
 		goto unlock_rtnl;
 
 	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-		if (params.cipher == rdev->wiphy.cipher_suites[i])
+		if (key.p.cipher == rdev->wiphy.cipher_suites[i])
 			break;
 	if (i == rdev->wiphy.n_cipher_suites) {
 		err = -EINVAL;
@@ -1172,7 +1283,7 @@ static int nl80211_new_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, &params);
+	err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1188,14 +1299,12 @@ static int nl80211_del_key(struct sk_buf
 	struct cfg80211_registered_device *rdev;
 	int err;
 	struct net_device *dev;
-	u8 key_idx = 0;
 	u8 *mac_addr = NULL;
+	struct key_parse key;
 
-	if (info->attrs[NL80211_ATTR_KEY_IDX])
-		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
-	if (key_idx > 5)
-		return -EINVAL;
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
 
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -1211,13 +1320,13 @@ static int nl80211_del_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr);
+	err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
-		if (key_idx == dev->ieee80211_ptr->wext.default_key)
+		if (key.idx == dev->ieee80211_ptr->wext.default_key)
 			dev->ieee80211_ptr->wext.default_key = -1;
-		else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
+		else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
 			dev->ieee80211_ptr->wext.default_mgmt_key = -1;
 	}
 #endif



^ permalink raw reply

* [PATCH] cfg80211: rework key operation
From: Johannes Berg @ 2009-07-08 11:13 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.

In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.

Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
Samuel, if you would like the keys passed directly to the connect() call
then feel free submit a patch changing that.

 include/linux/nl80211.h    |    4 +
 include/net/cfg80211.h     |   18 ++++
 net/mac80211/ibss.c        |    9 +-
 net/mac80211/ieee80211_i.h |    8 +-
 net/mac80211/mlme.c        |   11 ++
 net/mac80211/util.c        |   16 ++--
 net/mac80211/wep.c         |    6 -
 net/mac80211/wep.h         |    3 
 net/wireless/core.c        |   11 +-
 net/wireless/core.h        |   32 ++++++--
 net/wireless/ibss.c        |   79 +++++++++++++++++---
 net/wireless/mlme.c        |   16 +++-
 net/wireless/nl80211.c     |  170 +++++++++++++++++++++++++++++++++++++++------
 net/wireless/sme.c         |   97 ++++++++++++++++++-------
 net/wireless/util.c        |   41 ++++++++++
 net/wireless/wext-compat.c |  167 +++++++++++++++++++++++++++-----------------
 net/wireless/wext-sme.c    |   30 ++++++-
 17 files changed, 555 insertions(+), 163 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2009-07-08 00:45:16.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2009-07-08 00:45:16.000000000 +0200
@@ -576,6 +576,9 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_KEY: key information in a nested attribute with
  *	%NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ *	and join_ibss(), key information is in a nested attribute each
+ *	with %NL80211_KEY_* sub-attributes
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -705,6 +708,7 @@ enum nl80211_attrs {
 	NL80211_ATTR_PID,
 
 	NL80211_ATTR_KEY,
+	NL80211_ATTR_KEYS,
 
 	/* add attributes here, update the policy in nl80211.c */
 
--- wireless-testing.orig/net/wireless/nl80211.c	2009-07-08 00:45:16.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-07-08 00:45:16.000000000 +0200
@@ -143,8 +143,7 @@ static struct nla_policy nl80211_policy[
 /* policy for the attributes */
 static struct nla_policy
 nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
-	[NL80211_KEY_DATA] = { .type = NLA_BINARY,
-				    .len = WLAN_MAX_KEY_LEN },
+	[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
 	[NL80211_KEY_IDX] = { .type = NLA_U8 },
 	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
 	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
@@ -310,6 +309,83 @@ static int nl80211_parse_key(struct genl
 	return 0;
 }
 
+static struct cfg80211_cached_keys *
+nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
+		       struct nlattr *keys)
+{
+	struct key_parse parse;
+	struct nlattr *key;
+	struct cfg80211_cached_keys *result;
+	int rem, err, def = 0;
+
+	result = kzalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return ERR_PTR(-ENOMEM);
+
+	result->def = -1;
+	result->defmgmt = -1;
+
+	nla_for_each_nested(key, keys, rem) {
+		memset(&parse, 0, sizeof(parse));
+		parse.idx = -1;
+
+		err = nl80211_parse_key_new(key, &parse);
+		if (err)
+			goto error;
+		err = -EINVAL;
+		if (!parse.p.key)
+			goto error;
+		if (parse.idx < 0 || parse.idx > 4)
+			goto error;
+		if (parse.def) {
+			if (def)
+				goto error;
+			def = 1;
+			result->def = parse.idx;
+		} else if (parse.defmgmt)
+			goto error;
+		err = cfg80211_validate_key_settings(rdev, &parse.p,
+						     parse.idx, NULL);
+		if (err)
+			goto error;
+		result->params[parse.idx].cipher = parse.p.cipher;
+		result->params[parse.idx].key_len = parse.p.key_len;
+		result->params[parse.idx].key = result->data[parse.idx];
+		memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
+	}
+
+	return result;
+ error:
+	kfree(result);
+	return ERR_PTR(err);
+}
+
+static int nl80211_key_allowed(struct wireless_dev *wdev)
+{
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (!netif_running(wdev->netdev))
+		return -ENETDOWN;
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		if (!wdev->current_bss)
+			return -ENOLINK;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (wdev->sme_state != CFG80211_SME_CONNECTED)
+			return -ENOLINK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
@@ -1223,7 +1299,11 @@ static int nl80211_set_key(struct sk_buf
 		goto out;
 	}
 
-	err = func(&rdev->wiphy, dev, key.idx);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = func(&rdev->wiphy, dev, key.idx);
+
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
 		if (func == rdev->ops->set_default_key)
@@ -1232,6 +1312,7 @@ static int nl80211_set_key(struct sk_buf
 			dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
 	}
 #endif
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1246,7 +1327,7 @@ static int nl80211_set_key(struct sk_buf
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
-	int err, i;
+	int err;
 	struct net_device *dev;
 	struct key_parse key;
 	u8 *mac_addr = NULL;
@@ -1261,29 +1342,28 @@ static int nl80211_new_key(struct sk_buf
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-	if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
-		return -EINVAL;
-
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
 	if (err)
 		goto unlock_rtnl;
 
-	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-		if (key.p.cipher == rdev->wiphy.cipher_suites[i])
-			break;
-	if (i == rdev->wiphy.n_cipher_suites) {
-		err = -EINVAL;
+	if (!rdev->ops->add_key) {
+		err = -EOPNOTSUPP;
 		goto out;
 	}
 
-	if (!rdev->ops->add_key) {
-		err = -EOPNOTSUPP;
+	if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
+		err = -EINVAL;
 		goto out;
 	}
 
-	err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+					 mac_addr, &key.p);
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1320,7 +1400,10 @@ static int nl80211_del_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
@@ -1330,6 +1413,7 @@ static int nl80211_del_key(struct sk_buf
 			dev->ieee80211_ptr->wext.default_mgmt_key = -1;
 	}
 #endif
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -3174,6 +3258,7 @@ static int nl80211_authenticate(struct s
 	const u8 *bssid, *ssid, *ie = NULL;
 	int err, ssid_len, ie_len = 0;
 	enum nl80211_auth_type auth_type;
+	struct key_parse key;
 
 	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
 		return -EINVAL;
@@ -3190,6 +3275,25 @@ static int nl80211_authenticate(struct s
 	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
 		return -EINVAL;
 
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
+
+	if (key.idx >= 0) {
+		if (!key.p.key || !key.p.key_len)
+			return -EINVAL;
+		if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
+		     key.p.key_len != WLAN_KEY_LEN_WEP40) &&
+		    (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
+		     key.p.key_len != WLAN_KEY_LEN_WEP104))
+			return -EINVAL;
+		if (key.idx > 4)
+			return -EINVAL;
+	} else {
+		key.p.key_len = 0;
+		key.p.key = NULL;
+	}
+
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
@@ -3234,7 +3338,8 @@ static int nl80211_authenticate(struct s
 	}
 
 	err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-				 ssid, ssid_len, ie, ie_len);
+				 ssid, ssid_len, ie, ie_len,
+				 key.p.key, key.p.key_len, key.idx);
 
 out:
 	cfg80211_unlock_rdev(rdev);
@@ -3521,6 +3626,7 @@ static int nl80211_join_ibss(struct sk_b
 	struct net_device *dev;
 	struct cfg80211_ibss_params ibss;
 	struct wiphy *wiphy;
+	struct cfg80211_cached_keys *connkeys = NULL;
 	int err;
 
 	memset(&ibss, 0, sizeof(ibss));
@@ -3585,13 +3691,26 @@ static int nl80211_join_ibss(struct sk_b
 	}
 
 	ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+	ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+	if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+		connkeys = nl80211_parse_connkeys(rdev,
+					info->attrs[NL80211_ATTR_KEYS]);
+		if (IS_ERR(connkeys)) {
+			err = PTR_ERR(connkeys);
+			connkeys = NULL;
+			goto out;
+		}
+	}
 
-	err = cfg80211_join_ibss(rdev, dev, &ibss);
+	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
 
 out:
 	cfg80211_unlock_rdev(rdev);
 	dev_put(dev);
 unlock_rtnl:
+	if (err)
+		kfree(connkeys);
 	rtnl_unlock();
 	return err;
 }
@@ -3761,6 +3880,7 @@ static int nl80211_connect(struct sk_buf
 	struct net_device *dev;
 	struct cfg80211_connect_params connect;
 	struct wiphy *wiphy;
+	struct cfg80211_cached_keys *connkeys = NULL;
 	int err;
 
 	memset(&connect, 0, sizeof(connect));
@@ -3825,12 +3945,24 @@ static int nl80211_connect(struct sk_buf
 		}
 	}
 
-	err = cfg80211_connect(rdev, dev, &connect);
+	if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+		connkeys = nl80211_parse_connkeys(rdev,
+					info->attrs[NL80211_ATTR_KEYS]);
+		if (IS_ERR(connkeys)) {
+			err = PTR_ERR(connkeys);
+			connkeys = NULL;
+			goto out;
+		}
+	}
+
+	err = cfg80211_connect(rdev, dev, &connect, connkeys);
 
 out:
 	cfg80211_unlock_rdev(rdev);
 	dev_put(dev);
 unlock_rtnl:
+	if (err)
+		kfree(connkeys);
 	rtnl_unlock();
 	return err;
 }
--- wireless-testing.orig/net/wireless/wext-compat.c	2009-07-07 23:39:11.000000000 +0200
+++ wireless-testing/net/wireless/wext-compat.c	2009-07-08 00:45:17.000000000 +0200
@@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_de
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 
-static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
-				   struct net_device *dev, const u8 *addr,
-				   bool remove, bool tx_key, int idx,
-				   struct key_params *params)
-{
-	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int err;
+static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+				     struct net_device *dev, const u8 *addr,
+				     bool remove, bool tx_key, int idx,
+				     struct key_params *params)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err, i;
+
+	if (!wdev->wext.keys) {
+		wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
+					      GFP_KERNEL);
+		if (!wdev->wext.keys)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			wdev->wext.keys->params[i].key =
+				wdev->wext.keys->data[i];
+	}
+
+	if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
+	    wdev->iftype != NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
 
 	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		if (!wdev->current_bss)
+			return -ENOLINK;
+
 		if (!rdev->ops->set_default_mgmt_key)
 			return -EOPNOTSUPP;
 
@@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struc
 		return -EINVAL;
 
 	if (remove) {
-		err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+		err = 0;
+		if (wdev->current_bss)
+			err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
 		if (!err) {
+			if (!addr) {
+				wdev->wext.keys->params[idx].key_len = 0;
+				wdev->wext.keys->params[idx].cipher = 0;
+			}
 			if (idx == wdev->wext.default_key)
 				wdev->wext.default_key = -1;
 			else if (idx == wdev->wext.default_mgmt_key)
@@ -486,36 +509,64 @@ static int cfg80211_set_encryption(struc
 			return 0;
 
 		return err;
-	} else {
-		if (addr)
-			tx_key = false;
+	}
 
-		if (cfg80211_validate_key_settings(params, idx, addr))
-			return -EINVAL;
+	if (addr)
+		tx_key = false;
+
+	if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+		return -EINVAL;
 
+	err = 0;
+	if (wdev->current_bss)
 		err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
-		if (err)
-			return err;
+	if (err)
+		return err;
 
-		if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+	if (!addr) {
+		wdev->wext.keys->params[idx] = *params;
+		memcpy(wdev->wext.keys->data[idx],
+			params->key, params->key_len);
+		wdev->wext.keys->params[idx].key =
+			wdev->wext.keys->data[idx];
+	}
+
+	if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
+	    (tx_key || (!addr && wdev->wext.default_key == -1))) {
+		if (wdev->current_bss)
 			err = rdev->ops->set_default_key(&rdev->wiphy,
 							 dev, idx);
-			if (!err)
-				wdev->wext.default_key = idx;
-			return err;
-		}
+		if (!err)
+			wdev->wext.default_key = idx;
+		return err;
+	}
 
-		if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
-		    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+	    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+	    	if (wdev->current_bss)
 			err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
 							      dev, idx);
-			if (!err)
-				wdev->wext.default_mgmt_key = idx;
-			return err;
-		}
-
-		return 0;
+		if (!err)
+			wdev->wext.default_mgmt_key = idx;
+		return err;
 	}
+
+	return 0;
+}
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+				   struct net_device *dev, const u8 *addr,
+				   bool remove, bool tx_key, int idx,
+				   struct key_params *params)
+{
+	int err;
+
+	wdev_lock(dev->ieee80211_ptr);
+	err = __cfg80211_set_encryption(rdev, dev, addr, remove,
+					tx_key, idx, params);
+	wdev_unlock(dev->ieee80211_ptr);
+
+	return err;
 }
 
 int cfg80211_wext_siwencode(struct net_device *dev,
@@ -528,6 +579,10 @@ int cfg80211_wext_siwencode(struct net_d
 	bool remove = false;
 	struct key_params params;
 
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
+		return -EOPNOTSUPP;
+
 	/* no use -- only MFP (set_default_mgmt_key) is optional */
 	if (!rdev->ops->del_key ||
 	    !rdev->ops->add_key ||
@@ -548,9 +603,14 @@ int cfg80211_wext_siwencode(struct net_d
 		remove = true;
 	else if (erq->length == 0) {
 		/* No key data - just set the default TX key index */
-		err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+		err = 0;
+		wdev_lock(wdev);
+		if (wdev->current_bss)
+			err = rdev->ops->set_default_key(&rdev->wiphy,
+							 dev, idx);
 		if (!err)
 			wdev->wext.default_key = idx;
+		wdev_unlock(wdev);
 		return err;
 	}
 
@@ -583,6 +643,10 @@ int cfg80211_wext_siwencodeext(struct ne
 	struct key_params params;
 	u32 cipher;
 
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
+		return -EOPNOTSUPP;
+
 	/* no use -- only MFP (set_default_mgmt_key) is optional */
 	if (!rdev->ops->del_key ||
 	    !rdev->ops->add_key ||
@@ -656,37 +720,15 @@ int cfg80211_wext_siwencodeext(struct ne
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
 
-struct giwencode_cookie {
-	size_t buflen;
-	char *keybuf;
-};
-
-static void giwencode_get_key_cb(void *cookie, struct key_params *params)
-{
-	struct giwencode_cookie *data = cookie;
-
-	if (!params->key) {
-		data->buflen = 0;
-		return;
-	}
-
-	data->buflen = min_t(size_t, data->buflen, params->key_len);
-	memcpy(data->keybuf, params->key, data->buflen);
-}
-
 int cfg80211_wext_giwencode(struct net_device *dev,
 			    struct iw_request_info *info,
 			    struct iw_point *erq, char *keybuf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-	int idx, err;
-	struct giwencode_cookie data = {
-		.keybuf = keybuf,
-		.buflen = erq->length,
-	};
+	int idx;
 
-	if (!rdev->ops->get_key)
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 
 	idx = erq->flags & IW_ENCODE_INDEX;
@@ -701,21 +743,18 @@ int cfg80211_wext_giwencode(struct net_d
 
 	erq->flags = idx + 1;
 
-	err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
-				 giwencode_get_key_cb);
-	if (!err) {
-		erq->length = data.buflen;
-		erq->flags |= IW_ENCODE_ENABLED;
-		return 0;
-	}
-
-	if (err == -ENOENT) {
+	if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
 		erq->flags |= IW_ENCODE_DISABLED;
 		erq->length = 0;
 		return 0;
 	}
 
-	return err;
+	erq->length = min_t(size_t, erq->length,
+			    wdev->wext.keys->params[idx].key_len);
+	memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
+	erq->flags |= IW_ENCODE_ENABLED;
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
 
--- wireless-testing.orig/include/net/cfg80211.h	2009-07-07 23:39:04.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2009-07-08 00:45:17.000000000 +0200
@@ -647,12 +647,17 @@ struct cfg80211_crypto_settings {
  * @auth_type: Authentication type (algorithm)
  * @ie: Extra IEs to add to Authentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_auth_request {
 	struct cfg80211_bss *bss;
 	const u8 *ie;
 	size_t ie_len;
 	enum nl80211_auth_type auth_type;
+	const u8 *key;
+	u8 key_len, key_idx;
 };
 
 /**
@@ -727,6 +732,8 @@ struct cfg80211_disassoc_request {
  * @ie: information element(s) to include in the beacon
  * @ie_len: length of that
  * @beacon_interval: beacon interval to use
+ * @privacy: this is a protected network, keys will be configured
+ *	after joining
  */
 struct cfg80211_ibss_params {
 	u8 *ssid;
@@ -736,6 +743,7 @@ struct cfg80211_ibss_params {
 	u8 ssid_len, ie_len;
 	u16 beacon_interval;
 	bool channel_fixed;
+	bool privacy;
 };
 
 /**
@@ -755,6 +763,9 @@ struct cfg80211_ibss_params {
  * @assoc_ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
  * @crypto: crypto settings
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_connect_params {
 	struct ieee80211_channel *channel;
@@ -766,6 +777,8 @@ struct cfg80211_connect_params {
 	size_t ie_len;
 	bool privacy;
 	struct cfg80211_crypto_settings crypto;
+	const u8 *key;
+	u8 key_len, key_idx;
 };
 
 /**
@@ -1255,9 +1268,10 @@ extern void wiphy_unregister(struct wiph
  */
 extern void wiphy_free(struct wiphy *wiphy);
 
-/* internal struct */
+/* internal structs */
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
+struct cfg80211_cached_keys;
 
 #define MAX_AUTH_BSSES		4
 
@@ -1299,6 +1313,7 @@ struct wireless_dev {
 		CFG80211_SME_CONNECTED,
 	} sme_state;
 	struct cfg80211_conn *conn;
+	struct cfg80211_cached_keys *connect_keys;
 
 	struct list_head event_list;
 	spinlock_t event_lock;
@@ -1312,6 +1327,7 @@ struct wireless_dev {
 	struct {
 		struct cfg80211_ibss_params ibss;
 		struct cfg80211_connect_params connect;
+		struct cfg80211_cached_keys *keys;
 		u8 *ie;
 		size_t ie_len;
 		u8 bssid[ETH_ALEN];
--- wireless-testing.orig/net/wireless/core.h	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/wireless/core.h	2009-07-08 00:45:17.000000000 +0200
@@ -241,6 +241,12 @@ struct cfg80211_event {
 	};
 };
 
+struct cfg80211_cached_keys {
+	struct key_params params[6];
+	u8 data[6][WLAN_MAX_KEY_LEN];
+	int def, defmgmt;
+};
+
 
 /* free object */
 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -259,14 +265,18 @@ void cfg80211_bss_age(struct cfg80211_re
 /* IBSS */
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 struct cfg80211_ibss_params *params);
+			 struct cfg80211_ibss_params *params,
+			 struct cfg80211_cached_keys *connkeys);
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_ibss_params *params);
+		       struct cfg80211_ibss_params *params,
+		       struct cfg80211_cached_keys *connkeys);
 void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, bool nowext);
 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev);
 
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -275,12 +285,14 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 enum nl80211_auth_type auth_type,
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
-			 const u8 *ie, int ie_len);
+			 const u8 *ie, int ie_len,
+			 const u8 *key, int key_len, int key_idx);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
-		       const u8 *ie, int ie_len);
+		       const u8 *ie, int ie_len,
+		       const u8 *key, int key_len, int key_idx);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev,
 			  struct ieee80211_channel *chan,
@@ -313,10 +325,12 @@ void __cfg80211_connect_result(struct ne
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_connect_params *connect);
+		       struct cfg80211_connect_params *connect,
+		       struct cfg80211_cached_keys *connkeys);
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
 		     struct net_device *dev,
-		     struct cfg80211_connect_params *connect);
+		     struct cfg80211_connect_params *connect,
+		     struct cfg80211_cached_keys *connkeys);
 int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev, u16 reason,
 			  bool wextev);
@@ -326,11 +340,14 @@ int cfg80211_disconnect(struct cfg80211_
 void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
 		       const u8 *req_ie, size_t req_ie_len,
 		       const u8 *resp_ie, size_t resp_ie_len);
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev);
 
 void cfg80211_conn_work(struct work_struct *work);
 
 /* internal helpers */
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+				   struct key_params *params, int key_idx,
 				   const u8 *mac_addr);
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 			     size_t ie_len, u16 reason, bool from_ap);
@@ -338,5 +355,6 @@ void cfg80211_sme_scan_done(struct net_d
 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
 void cfg80211_sme_disassoc(struct net_device *dev, int idx);
 void __cfg80211_scan_done(struct work_struct *wk);
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
 
 #endif /* __NET_WIRELESS_CORE_H */
--- wireless-testing.orig/net/wireless/core.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/wireless/core.c	2009-07-08 00:45:17.000000000 +0200
@@ -707,14 +707,10 @@ static int cfg80211_netdev_notifier_call
 		wdev_lock(wdev);
 		switch (wdev->iftype) {
 		case NL80211_IFTYPE_ADHOC:
-			if (wdev->wext.ibss.ssid_len)
-				__cfg80211_join_ibss(rdev, dev,
-						     &wdev->wext.ibss);
+			cfg80211_ibss_wext_join(rdev, wdev);
 			break;
 		case NL80211_IFTYPE_STATION:
-			if (wdev->wext.connect.ssid_len)
-				__cfg80211_connect(rdev, dev,
-						   &wdev->wext.connect);
+			cfg80211_mgd_wext_connect(rdev, wdev);
 			break;
 		default:
 			break;
@@ -731,6 +727,9 @@ static int cfg80211_netdev_notifier_call
 		}
 		mutex_unlock(&rdev->devlist_mtx);
 		mutex_destroy(&wdev->mtx);
+#ifdef CONFIG_WIRELESS_EXT
+		kfree(wdev->wext.keys);
+#endif
 		break;
 	case NETDEV_PRE_UP:
 		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
--- wireless-testing.orig/net/wireless/sme.c	2009-07-07 23:39:05.000000000 +0200
+++ wireless-testing/net/wireless/sme.c	2009-07-08 00:45:17.000000000 +0200
@@ -126,7 +126,9 @@ static int cfg80211_conn_do_work(struct 
 					    params->channel, params->auth_type,
 					    params->bssid,
 					    params->ssid, params->ssid_len,
-					    NULL, 0);
+					    NULL, 0,
+					    params->key, params->key_len,
+					    params->key_idx);
 	case CFG80211_CONN_ASSOCIATE_NEXT:
 		BUG_ON(!rdev->ops->assoc);
 		wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -280,8 +282,12 @@ void cfg80211_sme_rx_auth(struct net_dev
 		/* select automatically between only open, shared, leap */
 		switch (wdev->conn->params.auth_type) {
 		case NL80211_AUTHTYPE_OPEN_SYSTEM:
-			wdev->conn->params.auth_type =
-				NL80211_AUTHTYPE_SHARED_KEY;
+			if (wdev->connect_keys)
+				wdev->conn->params.auth_type =
+					NL80211_AUTHTYPE_SHARED_KEY;
+			else
+				wdev->conn->params.auth_type =
+					NL80211_AUTHTYPE_NETWORK_EAP;
 			break;
 		case NL80211_AUTHTYPE_SHARED_KEY:
 			wdev->conn->params.auth_type =
@@ -354,10 +360,8 @@ void __cfg80211_connect_result(struct ne
 #endif
 
 	if (status == WLAN_STATUS_SUCCESS &&
-	    wdev->sme_state == CFG80211_SME_IDLE) {
-		wdev->sme_state = CFG80211_SME_CONNECTED;
-		return;
-	}
+	    wdev->sme_state == CFG80211_SME_IDLE)
+		goto success;
 
 	if (wdev->sme_state != CFG80211_SME_CONNECTING)
 		return;
@@ -371,24 +375,29 @@ void __cfg80211_connect_result(struct ne
 	if (wdev->conn)
 		wdev->conn->state = CFG80211_CONN_IDLE;
 
-	if (status == WLAN_STATUS_SUCCESS) {
-		bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-				       wdev->ssid, wdev->ssid_len,
-				       WLAN_CAPABILITY_ESS,
-				       WLAN_CAPABILITY_ESS);
-
-		if (WARN_ON(!bss))
-			return;
-
-		cfg80211_hold_bss(bss_from_pub(bss));
-		wdev->current_bss = bss_from_pub(bss);
-
-		wdev->sme_state = CFG80211_SME_CONNECTED;
-	} else {
+	if (status != WLAN_STATUS_SUCCESS) {
 		wdev->sme_state = CFG80211_SME_IDLE;
 		kfree(wdev->conn);
 		wdev->conn = NULL;
+		kfree(wdev->connect_keys);
+		wdev->connect_keys = NULL;
+		return;
 	}
+
+	bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+			       wdev->ssid, wdev->ssid_len,
+			       WLAN_CAPABILITY_ESS,
+			       WLAN_CAPABILITY_ESS);
+
+	if (WARN_ON(!bss))
+		return;
+
+	cfg80211_hold_bss(bss_from_pub(bss));
+	wdev->current_bss = bss_from_pub(bss);
+
+ success:
+	wdev->sme_state = CFG80211_SME_CONNECTED;
+	cfg80211_upload_connect_keys(wdev);
 }
 
 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -517,6 +526,8 @@ void __cfg80211_disconnected(struct net_
 			     size_t ie_len, u16 reason, bool from_ap)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	int i;
 #ifdef CONFIG_WIRELESS_EXT
 	union iwreq_data wrqu;
 #endif
@@ -544,8 +555,15 @@ void __cfg80211_disconnected(struct net_
 		wdev->conn = NULL;
 	}
 
-	nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
-				  reason, ie, ie_len, from_ap);
+	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
+
+	/*
+	 * Delete all the keys ... pairwise keys can't really
+	 * exist any more anyway, but default keys might.
+	 */
+	if (rdev->ops->del_key)
+		for (i = 0; i < 6; i++)
+			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 
 #ifdef CONFIG_WIRELESS_EXT
 	memset(&wrqu, 0, sizeof(wrqu));
@@ -581,7 +599,8 @@ EXPORT_SYMBOL(cfg80211_disconnected);
 
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_connect_params *connect)
+		       struct cfg80211_connect_params *connect,
+		       struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
@@ -591,6 +610,24 @@ int __cfg80211_connect(struct cfg80211_r
 	if (wdev->sme_state != CFG80211_SME_IDLE)
 		return -EALREADY;
 
+	if (WARN_ON(wdev->connect_keys)) {
+		kfree(wdev->connect_keys);
+		wdev->connect_keys = NULL;
+	}
+
+	if (connkeys && connkeys->def >= 0) {
+		int idx;
+
+		idx = connkeys->def;
+		/* If given a WEP key we may need it for shared key auth */
+		if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
+		    connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
+			connect->key_idx = idx;
+			connect->key = connkeys->params[idx].key;
+			connect->key_len = connkeys->params[idx].key_len;
+		}
+	}
+
 	if (!rdev->ops->connect) {
 		if (!rdev->ops->auth || !rdev->ops->assoc)
 			return -EOPNOTSUPP;
@@ -641,6 +678,7 @@ int __cfg80211_connect(struct cfg80211_r
 			cfg80211_get_conn_bss(wdev);
 
 		wdev->sme_state = CFG80211_SME_CONNECTING;
+		wdev->connect_keys = connkeys;
 
 		/* we're good if we have both BSSID and channel */
 		if (wdev->conn->params.bssid && wdev->conn->params.channel) {
@@ -663,13 +701,16 @@ int __cfg80211_connect(struct cfg80211_r
 			kfree(wdev->conn);
 			wdev->conn = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
+			wdev->connect_keys = NULL;
 		}
 
 		return err;
 	} else {
 		wdev->sme_state = CFG80211_SME_CONNECTING;
+		wdev->connect_keys = connkeys;
 		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
 		if (err) {
+			wdev->connect_keys = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
 			return err;
 		}
@@ -683,12 +724,13 @@ int __cfg80211_connect(struct cfg80211_r
 
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
 		     struct net_device *dev,
-		     struct cfg80211_connect_params *connect)
+		     struct cfg80211_connect_params *connect,
+		     struct cfg80211_cached_keys *connkeys)
 {
 	int err;
 
 	wdev_lock(dev->ieee80211_ptr);
-	err = __cfg80211_connect(rdev, dev, connect);
+	err = __cfg80211_connect(rdev, dev, connect, connkeys);
 	wdev_unlock(dev->ieee80211_ptr);
 
 	return err;
@@ -705,6 +747,9 @@ int __cfg80211_disconnect(struct cfg8021
 	if (wdev->sme_state == CFG80211_SME_IDLE)
 		return -EINVAL;
 
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+
 	if (!rdev->ops->disconnect) {
 		if (!rdev->ops->deauth)
 			return -EOPNOTSUPP;
--- wireless-testing.orig/net/wireless/wext-sme.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/wireless/wext-sme.c	2009-07-08 00:45:17.000000000 +0200
@@ -10,10 +10,11 @@
 #include <net/cfg80211.h>
 #include "nl80211.h"
 
-static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
-				     struct wireless_dev *wdev)
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev)
 {
-	int err;
+	struct cfg80211_cached_keys *ck = NULL;
+	int err, i;
 
 	ASSERT_RDEV_LOCK(rdev);
 	ASSERT_WDEV_LOCK(wdev);
@@ -25,10 +26,25 @@ static int cfg80211_mgd_wext_connect(str
 	wdev->wext.connect.ie_len = wdev->wext.ie_len;
 	wdev->wext.connect.privacy = wdev->wext.default_key != -1;
 
-	err = 0;
-	if (wdev->wext.connect.ssid_len != 0)
-		err = __cfg80211_connect(rdev, wdev->netdev,
-					 &wdev->wext.connect);
+	if (wdev->wext.keys) {
+		wdev->wext.keys->def = wdev->wext.default_key;
+		wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+	}
+
+	if (!wdev->wext.connect.ssid_len)
+		return 0;
+
+	if (wdev->wext.keys) {
+		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+		if (!ck)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			ck->params[i].key = ck->data[i];
+	}
+	err = __cfg80211_connect(rdev, wdev->netdev,
+				 &wdev->wext.connect, ck);
+	if (err)
+		kfree(ck);
 
 	return err;
 }
--- wireless-testing.orig/net/wireless/mlme.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/wireless/mlme.c	2009-07-08 00:45:17.000000000 +0200
@@ -328,7 +328,8 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 enum nl80211_auth_type auth_type,
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
-			 const u8 *ie, int ie_len)
+			 const u8 *ie, int ie_len,
+			 const u8 *key, int key_len, int key_idx)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_auth_request req;
@@ -337,6 +338,10 @@ int __cfg80211_mlme_auth(struct cfg80211
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+		if (!key || !key_len || key_idx < 0 || key_idx > 4)
+			return -EINVAL;
+
 	if (wdev->current_bss &&
 	    memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
 		return -EALREADY;
@@ -359,6 +364,9 @@ int __cfg80211_mlme_auth(struct cfg80211
 	req.auth_type = auth_type;
 	req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
 				   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+	req.key = key;
+	req.key_len = key_len;
+	req.key_idx = key_idx;
 	if (!req.bss)
 		return -ENOENT;
 
@@ -396,13 +404,15 @@ int cfg80211_mlme_auth(struct cfg80211_r
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
-		       const u8 *ie, int ie_len)
+		       const u8 *ie, int ie_len,
+		       const u8 *key, int key_len, int key_idx)
 {
 	int err;
 
 	wdev_lock(dev->ieee80211_ptr);
 	err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-				   ssid, ssid_len, ie, ie_len);
+				   ssid, ssid_len, ie, ie_len,
+				   key, key_len, key_idx);
 	wdev_unlock(dev->ieee80211_ptr);
 
 	return err;
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-07-08 00:45:17.000000000 +0200
@@ -247,6 +247,9 @@ struct ieee80211_mgd_work {
 
 	int tries;
 
+	u8 key[WLAN_KEY_LEN_WEP104];
+	u8 key_len, key_idx;
+
 	/* must be last */
 	u8 ie[0]; /* for auth or assoc frame, not probe */
 };
@@ -321,6 +324,7 @@ struct ieee80211_if_ibss {
 
 	bool fixed_bssid;
 	bool fixed_channel;
+	bool privacy;
 
 	u8 bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -1090,8 +1094,8 @@ int ieee80211_add_pending_skbs(struct ie
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
-			 u8 *extra, size_t extra_len,
-			 const u8 *bssid, int encrypt);
+			 u8 *extra, size_t extra_len, const u8 *bssid,
+			 const u8 *key, u8 key_len, u8 key_idx);
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 			     const u8 *ie, size_t ie_len);
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
--- wireless-testing.orig/net/mac80211/mlme.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2009-07-08 00:45:17.000000000 +0200
@@ -954,7 +954,7 @@ ieee80211_authenticate(struct ieee80211_
 	       sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
 
 	ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
-			    wk->bss->cbss.bssid, 0);
+			    wk->bss->cbss.bssid, NULL, 0, 0);
 	wk->auth_transaction = 2;
 
 	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -1176,7 +1176,8 @@ static void ieee80211_auth_challenge(str
 		return;
 	ieee80211_send_auth(sdata, 3, wk->auth_alg,
 			    elems.challenge - 2, elems.challenge_len + 2,
-			    wk->bss->cbss.bssid, 1);
+			    wk->bss->cbss.bssid,
+			    wk->key, wk->key_len, wk->key_idx);
 	wk->auth_transaction = 4;
 }
 
@@ -2175,6 +2176,12 @@ int ieee80211_mgd_auth(struct ieee80211_
 		wk->ie_len = req->ie_len;
 	}
 
+	if (req->key && req->key_len) {
+		wk->key_len = req->key_len;
+		wk->key_idx = req->key_idx;
+		memcpy(wk->key, req->key, req->key_len);
+	}
+
 	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
 	memcpy(wk->ssid, ssid + 2, ssid[1]);
 	wk->ssid_len = ssid[1];
--- wireless-testing.orig/net/mac80211/ibss.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/mac80211/ibss.c	2009-07-08 00:45:17.000000000 +0200
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(
 	 */
 	if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
 		ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
-				    sdata->u.ibss.bssid, 0);
+				    sdata->u.ibss.bssid, NULL, 0, 0);
 }
 
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(st
 
 	capability = WLAN_CAPABILITY_IBSS;
 
-	if (sdata->default_key)
+	if (ifibss->privacy)
 		capability |= WLAN_CAPABILITY_PRIVACY;
 	else
 		sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(stru
 		return;
 
 	capability = WLAN_CAPABILITY_IBSS;
-	if (sdata->default_key)
+	if (ifibss->privacy)
 		capability |= WLAN_CAPABILITY_PRIVACY;
-
 	if (ifibss->fixed_bssid)
 		bssid = ifibss->bssid;
 	if (ifibss->fixed_channel)
@@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211
 	} else
 		sdata->u.ibss.fixed_bssid = false;
 
+	sdata->u.ibss.privacy = params->privacy;
+
 	sdata->vif.bss_conf.beacon_int = params->beacon_interval;
 
 	sdata->u.ibss.channel = params->channel;
--- wireless-testing.orig/net/mac80211/util.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-07-08 00:45:17.000000000 +0200
@@ -31,6 +31,7 @@
 #include "mesh.h"
 #include "wme.h"
 #include "led.h"
+#include "wep.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
 void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -778,12 +779,13 @@ u32 ieee80211_mandatory_rates(struct iee
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
-			 u8 *extra, size_t extra_len,
-			 const u8 *bssid, int encrypt)
+			 u8 *extra, size_t extra_len, const u8 *bssid,
+			 const u8 *key, u8 key_len, u8 key_idx)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
+	int err;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    sizeof(*mgmt) + 6 + extra_len);
@@ -798,8 +800,6 @@ void ieee80211_send_auth(struct ieee8021
 	memset(mgmt, 0, 24 + 6);
 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					  IEEE80211_STYPE_AUTH);
-	if (encrypt)
-		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 	memcpy(mgmt->da, bssid, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -809,7 +809,13 @@ void ieee80211_send_auth(struct ieee8021
 	if (extra)
 		memcpy(skb_put(skb, extra_len), extra, extra_len);
 
-	ieee80211_tx_skb(sdata, skb, encrypt);
+	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
+		WARN_ON(err);
+	}
+
+	ieee80211_tx_skb(sdata, skb, 0);
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
--- wireless-testing.orig/net/mac80211/wep.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/mac80211/wep.c	2009-07-08 00:45:17.000000000 +0200
@@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct c
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-static int ieee80211_wep_encrypt(struct ieee80211_local *local,
-				 struct sk_buff *skb,
-				 const u8 *key, int keylen, int keyidx)
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  const u8 *key, int keylen, int keyidx)
 {
 	u8 *iv;
 	size_t len;
--- wireless-testing.orig/net/mac80211/wep.h	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/mac80211/wep.h	2009-07-08 00:45:17.000000000 +0200
@@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_
 void ieee80211_wep_free(struct ieee80211_local *local);
 void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 				size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  const u8 *key, int keylen, int keyidx);
 int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 			       size_t klen, u8 *data, size_t data_len);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
--- wireless-testing.orig/net/wireless/ibss.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/wireless/ibss.c	2009-07-08 00:45:17.000000000 +0200
@@ -39,6 +39,8 @@ void __cfg80211_ibss_joined(struct net_d
 	cfg80211_hold_bss(bss_from_pub(bss));
 	wdev->current_bss = bss_from_pub(bss);
 
+	cfg80211_upload_connect_keys(wdev);
+
 	nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
 				GFP_KERNEL);
 #ifdef CONFIG_WIRELESS_EXT
@@ -71,7 +73,8 @@ EXPORT_SYMBOL(cfg80211_ibss_joined);
 
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 struct cfg80211_ibss_params *params)
+			 struct cfg80211_ibss_params *params,
+			 struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
@@ -81,13 +84,18 @@ int __cfg80211_join_ibss(struct cfg80211
 	if (wdev->ssid_len)
 		return -EALREADY;
 
+	if (WARN_ON(wdev->connect_keys))
+		kfree(wdev->connect_keys);
+	wdev->connect_keys = connkeys;
+
 #ifdef CONFIG_WIRELESS_EXT
 	wdev->wext.ibss.channel = params->channel;
 #endif
 	err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
-
-	if (err)
+	if (err) {
+		wdev->connect_keys = NULL;
 		return err;
+	}
 
 	memcpy(wdev->ssid, params->ssid, params->ssid_len);
 	wdev->ssid_len = params->ssid_len;
@@ -97,13 +105,14 @@ int __cfg80211_join_ibss(struct cfg80211
 
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_ibss_params *params)
+		       struct cfg80211_ibss_params *params,
+		       struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
 
 	wdev_lock(wdev);
-	err = __cfg80211_join_ibss(rdev, dev, params);
+	err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
 	wdev_unlock(wdev);
 
 	return err;
@@ -112,9 +121,22 @@ int cfg80211_join_ibss(struct cfg80211_r
 static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	int i;
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+
+	/*
+	 * Delete all the keys ... pairwise keys can't really
+	 * exist any more anyway, but default keys might.
+	 */
+	if (rdev->ops->del_key)
+		for (i = 0; i < 6; i++)
+			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+
 	if (wdev->current_bss) {
 		cfg80211_unhold_bss(wdev->current_bss);
 		cfg80211_put_bss(&wdev->current_bss->pub);
@@ -172,11 +194,14 @@ int cfg80211_leave_ibss(struct cfg80211_
 }
 
 #ifdef CONFIG_WIRELESS_EXT
-static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
-				   struct wireless_dev *wdev)
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev)
 {
+	struct cfg80211_cached_keys *ck = NULL;
 	enum ieee80211_band band;
-	int i;
+	int i, err;
+
+	ASSERT_WDEV_LOCK(wdev);
 
 	if (!wdev->wext.ibss.beacon_interval)
 		wdev->wext.ibss.beacon_interval = 100;
@@ -216,8 +241,24 @@ static int cfg80211_ibss_wext_join(struc
 	if (!netif_running(wdev->netdev))
 		return 0;
 
-	return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
-				  wdev->netdev, &wdev->wext.ibss);
+	if (wdev->wext.keys)
+		wdev->wext.keys->def = wdev->wext.default_key;
+
+	wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
+
+	if (wdev->wext.keys) {
+		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+		if (!ck)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			ck->params[i].key = ck->data[i];
+	}
+	err = __cfg80211_join_ibss(rdev, wdev->netdev,
+				   &wdev->wext.ibss, ck);
+	if (err)
+		kfree(ck);
+
+	return err;
 }
 
 int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -265,7 +306,11 @@ int cfg80211_ibss_wext_siwfreq(struct ne
 		wdev->wext.ibss.channel_fixed = false;
 	}
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
@@ -333,7 +378,11 @@ int cfg80211_ibss_wext_siwessid(struct n
 	memcpy(wdev->wext.ibss.ssid, ssid, len);
 	wdev->wext.ibss.ssid_len = len;
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
@@ -414,7 +463,11 @@ int cfg80211_ibss_wext_siwap(struct net_
 	} else
 		wdev->wext.ibss.bssid = NULL;
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
--- wireless-testing.orig/net/wireless/util.c	2009-07-07 23:39:01.000000000 +0200
+++ wireless-testing/net/wireless/util.c	2009-07-08 00:45:17.000000000 +0200
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct 
 			set_mandatory_flags_band(wiphy->bands[band], band);
 }
 
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+				   struct key_params *params, int key_idx,
 				   const u8 *mac_addr)
 {
+	int i;
+
 	if (key_idx > 5)
 		return -EINVAL;
 
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struc
 		}
 	}
 
+	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
+		if (params->cipher == rdev->wiphy.cipher_suites[i])
+			break;
+	if (i == rdev->wiphy.n_cipher_suites)
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -523,3 +532,33 @@ const u8 *ieee80211_bss_get_ie(struct cf
 	return NULL;
 }
 EXPORT_SYMBOL(ieee80211_bss_get_ie);
+
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	struct net_device *dev = wdev->netdev;
+	int i;
+
+	if (!wdev->connect_keys)
+		return;
+
+	for (i = 0; i < 6; i++) {
+		if (!wdev->connect_keys->params[i].cipher)
+			continue;
+		if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+					&wdev->connect_keys->params[i]))
+			printk(KERN_ERR "%s: failed to set key %d\n",
+				dev->name, i);
+		if (wdev->connect_keys->def == i)
+			if (rdev->ops->set_default_key(wdev->wiphy, dev, i))
+				printk(KERN_ERR "%s: failed to set defkey %d\n",
+					dev->name, i);
+		if (wdev->connect_keys->defmgmt == i)
+			if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+				printk(KERN_ERR "%s: failed to set mgtdef %d\n",
+					dev->name, i);
+	}
+
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+}



^ permalink raw reply

* [PATCH v2] nl80211: introduce new key attributes
From: Johannes Berg @ 2009-07-08 11:29 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1247051499.4755.79.camel@johannes.local>

We will soon want to nest key attributes into
some new attribute for configuring static WEP
keys at connect() and ibss_join() time, so we
need nested attributes for that. However, key
attributes right now are 'global'. This patch
thus introduces new nested attributes for the
key settings and functions for parsing them.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
add #ifdef ability

 include/linux/nl80211.h |   36 ++++++++
 net/wireless/nl80211.c  |  203 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 192 insertions(+), 47 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2009-07-07 23:39:05.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2009-07-08 13:20:25.000000000 +0200
@@ -574,6 +574,9 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_PID: Process ID of a network namespace.
  *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ *	%NL80211_KEY_* sub-attributes
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -701,6 +704,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_PID,
 
+	NL80211_ATTR_KEY,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -729,6 +734,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
 #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_REG_RULES		32
@@ -1329,4 +1335,34 @@ enum nl80211_wpa_versions {
 	NL80211_WPA_VERSION_2 = 1 << 1,
 };
 
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *	keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *	CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+	__NL80211_KEY_INVALID,
+	NL80211_KEY_DATA,
+	NL80211_KEY_IDX,
+	NL80211_KEY_CIPHER,
+	NL80211_KEY_SEQ,
+	NL80211_KEY_DEFAULT,
+	NL80211_KEY_DEFAULT_MGMT,
+
+	/* keep last */
+	__NL80211_KEY_AFTER_LAST,
+	NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
--- wireless-testing.orig/net/wireless/nl80211.c	2009-07-07 23:39:05.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-07-08 13:20:01.000000000 +0200
@@ -77,6 +77,7 @@ static struct nla_policy nl80211_policy[
 	[NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
 	[NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
 
+	[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
 	[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
 				    .len = WLAN_MAX_KEY_LEN },
 	[NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
@@ -139,6 +140,18 @@ static struct nla_policy nl80211_policy[
 	[NL80211_ATTR_PID] = { .type = NLA_U32 },
 };
 
+/* policy for the attributes */
+static struct nla_policy
+nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
+	[NL80211_KEY_DATA] = { .type = NLA_BINARY,
+				    .len = WLAN_MAX_KEY_LEN },
+	[NL80211_KEY_IDX] = { .type = NLA_U8 },
+	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
+	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+	[NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
+	[NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
+};
+
 /* IE validation */
 static bool is_valid_ie_attr(const struct nlattr *attr)
 {
@@ -203,6 +216,100 @@ static int nl80211_msg_put_channel(struc
 
 /* netlink command implementations */
 
+struct key_parse {
+	struct key_params p;
+	int idx;
+	bool def, defmgmt;
+};
+
+static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
+{
+	struct nlattr *tb[NL80211_KEY_MAX + 1];
+	int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
+				   nl80211_key_policy);
+	if (err)
+		return err;
+
+	k->def = !!tb[NL80211_KEY_DEFAULT];
+	k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
+
+	if (tb[NL80211_KEY_IDX])
+		k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);
+
+	if (tb[NL80211_KEY_DATA]) {
+		k->p.key = nla_data(tb[NL80211_KEY_DATA]);
+		k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
+	}
+
+	if (tb[NL80211_KEY_SEQ]) {
+		k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
+		k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
+	}
+
+	if (tb[NL80211_KEY_CIPHER])
+		k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);
+
+	return 0;
+}
+
+static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
+{
+	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
+		k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
+		k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
+	}
+
+	if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
+		k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
+		k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
+	}
+
+	if (info->attrs[NL80211_ATTR_KEY_IDX])
+		k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+
+	if (info->attrs[NL80211_ATTR_KEY_CIPHER])
+		k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
+
+	k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
+	k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];
+
+	return 0;
+}
+
+static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
+{
+	int err;
+
+	memset(k, 0, sizeof(*k));
+	k->idx = -1;
+
+	if (info->attrs[NL80211_ATTR_KEY])
+		err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
+	else
+		err = nl80211_parse_key_old(info, k);
+
+	if (err)
+		return err;
+
+	if (k->def && k->defmgmt)
+		return -EINVAL;
+
+	if (k->idx != -1) {
+		if (k->defmgmt) {
+			if (k->idx < 4 || k->idx > 5)
+				return -EINVAL;
+		} else if (k->def) {
+			if (k->idx < 0 || k->idx > 3)
+				return -EINVAL;
+		} else {
+			if (k->idx < 0 || k->idx > 5)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
@@ -955,10 +1062,12 @@ static int nl80211_del_interface(struct 
 struct get_key_cookie {
 	struct sk_buff *msg;
 	int error;
+	int idx;
 };
 
 static void get_key_callback(void *c, struct key_params *params)
 {
+	struct nlattr *key;
 	struct get_key_cookie *cookie = c;
 
 	if (params->key)
@@ -973,6 +1082,26 @@ static void get_key_callback(void *c, st
 		NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
 			    params->cipher);
 
+	key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY);
+	if (!key)
+		goto nla_put_failure;
+
+	if (params->key)
+		NLA_PUT(cookie->msg, NL80211_KEY_DATA,
+			params->key_len, params->key);
+
+	if (params->seq)
+		NLA_PUT(cookie->msg, NL80211_KEY_SEQ,
+			params->seq_len, params->seq);
+
+	if (params->cipher)
+		NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER,
+			    params->cipher);
+
+	NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx);
+
+	nla_nest_end(cookie->msg, key);
+
 	return;
  nla_put_failure:
 	cookie->error = 1;
@@ -1026,6 +1155,7 @@ static int nl80211_get_key(struct sk_buf
 	}
 
 	cookie.msg = msg;
+	cookie.idx = key_idx;
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
@@ -1060,26 +1190,21 @@ static int nl80211_get_key(struct sk_buf
 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
+	struct key_parse key;
 	int err;
 	struct net_device *dev;
-	u8 key_idx;
 	int (*func)(struct wiphy *wiphy, struct net_device *netdev,
 		    u8 key_index);
 
-	if (!info->attrs[NL80211_ATTR_KEY_IDX])
-		return -EINVAL;
-
-	key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
 
-	if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) {
-		if (key_idx < 4 || key_idx > 5)
-			return -EINVAL;
-	} else if (key_idx > 3)
+	if (key.idx < 0)
 		return -EINVAL;
 
-	/* currently only support setting default key */
-	if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] &&
-	    !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT])
+	/* only support setting default key */
+	if (!key.def && !key.defmgmt)
 		return -EINVAL;
 
 	rtnl_lock();
@@ -1088,7 +1213,7 @@ static int nl80211_set_key(struct sk_buf
 	if (err)
 		goto unlock_rtnl;
 
-	if (info->attrs[NL80211_ATTR_KEY_DEFAULT])
+	if (key.def)
 		func = rdev->ops->set_default_key;
 	else
 		func = rdev->ops->set_default_mgmt_key;
@@ -1098,13 +1223,13 @@ static int nl80211_set_key(struct sk_buf
 		goto out;
 	}
 
-	err = func(&rdev->wiphy, dev, key_idx);
+	err = func(&rdev->wiphy, dev, key.idx);
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
 		if (func == rdev->ops->set_default_key)
-			dev->ieee80211_ptr->wext.default_key = key_idx;
+			dev->ieee80211_ptr->wext.default_key = key.idx;
 		else
-			dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
+			dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
 	}
 #endif
 
@@ -1123,34 +1248,20 @@ static int nl80211_new_key(struct sk_buf
 	struct cfg80211_registered_device *rdev;
 	int err, i;
 	struct net_device *dev;
-	struct key_params params;
-	u8 key_idx = 0;
+	struct key_parse key;
 	u8 *mac_addr = NULL;
 
-	memset(&params, 0, sizeof(params));
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
 
-	if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
+	if (!key.p.key)
 		return -EINVAL;
 
-	if (info->attrs[NL80211_ATTR_KEY_DATA]) {
-		params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
-		params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
-	}
-
-	if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
-		params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
-		params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
-	}
-
-	if (info->attrs[NL80211_ATTR_KEY_IDX])
-		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
-	params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-	if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
+	if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
 		return -EINVAL;
 
 	rtnl_lock();
@@ -1160,7 +1271,7 @@ static int nl80211_new_key(struct sk_buf
 		goto unlock_rtnl;
 
 	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-		if (params.cipher == rdev->wiphy.cipher_suites[i])
+		if (key.p.cipher == rdev->wiphy.cipher_suites[i])
 			break;
 	if (i == rdev->wiphy.n_cipher_suites) {
 		err = -EINVAL;
@@ -1172,7 +1283,7 @@ static int nl80211_new_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, &params);
+	err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1188,14 +1299,12 @@ static int nl80211_del_key(struct sk_buf
 	struct cfg80211_registered_device *rdev;
 	int err;
 	struct net_device *dev;
-	u8 key_idx = 0;
 	u8 *mac_addr = NULL;
+	struct key_parse key;
 
-	if (info->attrs[NL80211_ATTR_KEY_IDX])
-		key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
-
-	if (key_idx > 5)
-		return -EINVAL;
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
 
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
@@ -1211,13 +1320,13 @@ static int nl80211_del_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr);
+	err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
-		if (key_idx == dev->ieee80211_ptr->wext.default_key)
+		if (key.idx == dev->ieee80211_ptr->wext.default_key)
 			dev->ieee80211_ptr->wext.default_key = -1;
-		else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
+		else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key)
 			dev->ieee80211_ptr->wext.default_mgmt_key = -1;
 	}
 #endif



^ permalink raw reply

* Re: kernel .30 BROKE ATH5K with my AR5212 atheros.
From: Bob Copeland @ 2009-07-08 11:42 UTC (permalink / raw)
  To: Jasin Colegrove; +Cc: linux-wireless
In-Reply-To: <6c354a1a0907072358u7408d865h5b32c587f63f39d@mail.gmail.com>

On Wed, Jul 08, 2009 at 02:58:11AM -0400, Jasin Colegrove wrote:
> I haven't tried this yet, but I started up gitk and realized that the
> last good commit was the one previous to the bad commit. They where
> made 3 minutes apart in the ath5k dir. So I am assuming that the
> "Disable BMISS interrupts was not actually at fault. It just doesn't
> seem logical now that i look at it.

Yeah, that commit is near some changes that might cause what you
are seeing though, so maybe you made a wrong turn along the way?
E.g. "ath5k: Update reset code" introduced a bug for RF 5413 chips,
maybe others.  Another possible change is the txpower rework.

BTW, can you (re?)post the "Atheros AR5212 chip found (MAC xxx,
PHY xxxx)?"

> So I started another bisect of drivers/net/. Is this the main tree you
> where talking about or do you think I need to go further into the main
> tree? If so, how far?

Also at least /net (you can add multiple paths to git bisect).  If 
you can narrow it down to a small range then a bisect over the entire
tree would eliminate any doubt, but in that case it's easier to make a
bisect mistake.  As you say, it does sound like a driver issue though.

> stellar results. Once again, downgrading to kernel .29 fixes
> everything without changing any of my other settings. I am still 110%
> positive this is a kernel module/driver issue. It does make sense, no?

Yeah, unfortunately I don't really have any good ideas, but I've seen
a trickle of similar reports so it would be good to nail it down.  Thanks
for testing, it really helps a lot.

-- 
Bob Copeland %% www.bobcopeland.com


^ permalink raw reply

* [PATCH v2] cfg80211: rework key operation
From: Johannes Berg @ 2009-07-08 11:30 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1247051586.4755.81.camel@johannes.local>

This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.

In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.

Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v2: add #ifdef ability

 include/linux/nl80211.h    |    5 +
 include/net/cfg80211.h     |   18 ++++
 net/mac80211/ibss.c        |    9 +-
 net/mac80211/ieee80211_i.h |    8 +-
 net/mac80211/mlme.c        |   11 ++
 net/mac80211/util.c        |   16 ++--
 net/mac80211/wep.c         |    6 -
 net/mac80211/wep.h         |    3 
 net/wireless/core.c        |   11 +-
 net/wireless/core.h        |   32 ++++++--
 net/wireless/ibss.c        |   79 +++++++++++++++++---
 net/wireless/mlme.c        |   16 +++-
 net/wireless/nl80211.c     |  170 +++++++++++++++++++++++++++++++++++++++------
 net/wireless/sme.c         |   97 ++++++++++++++++++-------
 net/wireless/util.c        |   41 ++++++++++
 net/wireless/wext-compat.c |  167 +++++++++++++++++++++++++++-----------------
 net/wireless/wext-sme.c    |   30 ++++++-
 17 files changed, 556 insertions(+), 163 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2009-07-08 13:20:25.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2009-07-08 13:29:23.000000000 +0200
@@ -576,6 +576,9 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_KEY: key information in a nested attribute with
  *	%NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ *	and join_ibss(), key information is in a nested attribute each
+ *	with %NL80211_KEY_* sub-attributes
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -705,6 +708,7 @@ enum nl80211_attrs {
 	NL80211_ATTR_PID,
 
 	NL80211_ATTR_KEY,
+	NL80211_ATTR_KEYS,
 
 	/* add attributes here, update the policy in nl80211.c */
 
@@ -735,6 +739,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_REG_RULES		32
--- wireless-testing.orig/net/wireless/nl80211.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-07-08 13:29:10.000000000 +0200
@@ -143,8 +143,7 @@ static struct nla_policy nl80211_policy[
 /* policy for the attributes */
 static struct nla_policy
 nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
-	[NL80211_KEY_DATA] = { .type = NLA_BINARY,
-				    .len = WLAN_MAX_KEY_LEN },
+	[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
 	[NL80211_KEY_IDX] = { .type = NLA_U8 },
 	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
 	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
@@ -310,6 +309,83 @@ static int nl80211_parse_key(struct genl
 	return 0;
 }
 
+static struct cfg80211_cached_keys *
+nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
+		       struct nlattr *keys)
+{
+	struct key_parse parse;
+	struct nlattr *key;
+	struct cfg80211_cached_keys *result;
+	int rem, err, def = 0;
+
+	result = kzalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return ERR_PTR(-ENOMEM);
+
+	result->def = -1;
+	result->defmgmt = -1;
+
+	nla_for_each_nested(key, keys, rem) {
+		memset(&parse, 0, sizeof(parse));
+		parse.idx = -1;
+
+		err = nl80211_parse_key_new(key, &parse);
+		if (err)
+			goto error;
+		err = -EINVAL;
+		if (!parse.p.key)
+			goto error;
+		if (parse.idx < 0 || parse.idx > 4)
+			goto error;
+		if (parse.def) {
+			if (def)
+				goto error;
+			def = 1;
+			result->def = parse.idx;
+		} else if (parse.defmgmt)
+			goto error;
+		err = cfg80211_validate_key_settings(rdev, &parse.p,
+						     parse.idx, NULL);
+		if (err)
+			goto error;
+		result->params[parse.idx].cipher = parse.p.cipher;
+		result->params[parse.idx].key_len = parse.p.key_len;
+		result->params[parse.idx].key = result->data[parse.idx];
+		memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
+	}
+
+	return result;
+ error:
+	kfree(result);
+	return ERR_PTR(err);
+}
+
+static int nl80211_key_allowed(struct wireless_dev *wdev)
+{
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (!netif_running(wdev->netdev))
+		return -ENETDOWN;
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		if (!wdev->current_bss)
+			return -ENOLINK;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (wdev->sme_state != CFG80211_SME_CONNECTED)
+			return -ENOLINK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
@@ -1223,7 +1299,11 @@ static int nl80211_set_key(struct sk_buf
 		goto out;
 	}
 
-	err = func(&rdev->wiphy, dev, key.idx);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = func(&rdev->wiphy, dev, key.idx);
+
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
 		if (func == rdev->ops->set_default_key)
@@ -1232,6 +1312,7 @@ static int nl80211_set_key(struct sk_buf
 			dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
 	}
 #endif
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1246,7 +1327,7 @@ static int nl80211_set_key(struct sk_buf
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
-	int err, i;
+	int err;
 	struct net_device *dev;
 	struct key_parse key;
 	u8 *mac_addr = NULL;
@@ -1261,29 +1342,28 @@ static int nl80211_new_key(struct sk_buf
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-	if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
-		return -EINVAL;
-
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
 	if (err)
 		goto unlock_rtnl;
 
-	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-		if (key.p.cipher == rdev->wiphy.cipher_suites[i])
-			break;
-	if (i == rdev->wiphy.n_cipher_suites) {
-		err = -EINVAL;
+	if (!rdev->ops->add_key) {
+		err = -EOPNOTSUPP;
 		goto out;
 	}
 
-	if (!rdev->ops->add_key) {
-		err = -EOPNOTSUPP;
+	if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
+		err = -EINVAL;
 		goto out;
 	}
 
-	err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+					 mac_addr, &key.p);
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1320,7 +1400,10 @@ static int nl80211_del_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
@@ -1330,6 +1413,7 @@ static int nl80211_del_key(struct sk_buf
 			dev->ieee80211_ptr->wext.default_mgmt_key = -1;
 	}
 #endif
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -3174,6 +3258,7 @@ static int nl80211_authenticate(struct s
 	const u8 *bssid, *ssid, *ie = NULL;
 	int err, ssid_len, ie_len = 0;
 	enum nl80211_auth_type auth_type;
+	struct key_parse key;
 
 	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
 		return -EINVAL;
@@ -3190,6 +3275,25 @@ static int nl80211_authenticate(struct s
 	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
 		return -EINVAL;
 
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
+
+	if (key.idx >= 0) {
+		if (!key.p.key || !key.p.key_len)
+			return -EINVAL;
+		if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
+		     key.p.key_len != WLAN_KEY_LEN_WEP40) &&
+		    (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
+		     key.p.key_len != WLAN_KEY_LEN_WEP104))
+			return -EINVAL;
+		if (key.idx > 4)
+			return -EINVAL;
+	} else {
+		key.p.key_len = 0;
+		key.p.key = NULL;
+	}
+
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
@@ -3234,7 +3338,8 @@ static int nl80211_authenticate(struct s
 	}
 
 	err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-				 ssid, ssid_len, ie, ie_len);
+				 ssid, ssid_len, ie, ie_len,
+				 key.p.key, key.p.key_len, key.idx);
 
 out:
 	cfg80211_unlock_rdev(rdev);
@@ -3521,6 +3626,7 @@ static int nl80211_join_ibss(struct sk_b
 	struct net_device *dev;
 	struct cfg80211_ibss_params ibss;
 	struct wiphy *wiphy;
+	struct cfg80211_cached_keys *connkeys = NULL;
 	int err;
 
 	memset(&ibss, 0, sizeof(ibss));
@@ -3585,13 +3691,26 @@ static int nl80211_join_ibss(struct sk_b
 	}
 
 	ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+	ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+	if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+		connkeys = nl80211_parse_connkeys(rdev,
+					info->attrs[NL80211_ATTR_KEYS]);
+		if (IS_ERR(connkeys)) {
+			err = PTR_ERR(connkeys);
+			connkeys = NULL;
+			goto out;
+		}
+	}
 
-	err = cfg80211_join_ibss(rdev, dev, &ibss);
+	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
 
 out:
 	cfg80211_unlock_rdev(rdev);
 	dev_put(dev);
 unlock_rtnl:
+	if (err)
+		kfree(connkeys);
 	rtnl_unlock();
 	return err;
 }
@@ -3761,6 +3880,7 @@ static int nl80211_connect(struct sk_buf
 	struct net_device *dev;
 	struct cfg80211_connect_params connect;
 	struct wiphy *wiphy;
+	struct cfg80211_cached_keys *connkeys = NULL;
 	int err;
 
 	memset(&connect, 0, sizeof(connect));
@@ -3825,12 +3945,24 @@ static int nl80211_connect(struct sk_buf
 		}
 	}
 
-	err = cfg80211_connect(rdev, dev, &connect);
+	if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+		connkeys = nl80211_parse_connkeys(rdev,
+					info->attrs[NL80211_ATTR_KEYS]);
+		if (IS_ERR(connkeys)) {
+			err = PTR_ERR(connkeys);
+			connkeys = NULL;
+			goto out;
+		}
+	}
+
+	err = cfg80211_connect(rdev, dev, &connect, connkeys);
 
 out:
 	cfg80211_unlock_rdev(rdev);
 	dev_put(dev);
 unlock_rtnl:
+	if (err)
+		kfree(connkeys);
 	rtnl_unlock();
 	return err;
 }
--- wireless-testing.orig/net/wireless/wext-compat.c	2009-07-08 13:20:02.000000000 +0200
+++ wireless-testing/net/wireless/wext-compat.c	2009-07-08 13:29:10.000000000 +0200
@@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_de
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 
-static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
-				   struct net_device *dev, const u8 *addr,
-				   bool remove, bool tx_key, int idx,
-				   struct key_params *params)
-{
-	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int err;
+static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+				     struct net_device *dev, const u8 *addr,
+				     bool remove, bool tx_key, int idx,
+				     struct key_params *params)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err, i;
+
+	if (!wdev->wext.keys) {
+		wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
+					      GFP_KERNEL);
+		if (!wdev->wext.keys)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			wdev->wext.keys->params[i].key =
+				wdev->wext.keys->data[i];
+	}
+
+	if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
+	    wdev->iftype != NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
 
 	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		if (!wdev->current_bss)
+			return -ENOLINK;
+
 		if (!rdev->ops->set_default_mgmt_key)
 			return -EOPNOTSUPP;
 
@@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struc
 		return -EINVAL;
 
 	if (remove) {
-		err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+		err = 0;
+		if (wdev->current_bss)
+			err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
 		if (!err) {
+			if (!addr) {
+				wdev->wext.keys->params[idx].key_len = 0;
+				wdev->wext.keys->params[idx].cipher = 0;
+			}
 			if (idx == wdev->wext.default_key)
 				wdev->wext.default_key = -1;
 			else if (idx == wdev->wext.default_mgmt_key)
@@ -486,36 +509,64 @@ static int cfg80211_set_encryption(struc
 			return 0;
 
 		return err;
-	} else {
-		if (addr)
-			tx_key = false;
+	}
 
-		if (cfg80211_validate_key_settings(params, idx, addr))
-			return -EINVAL;
+	if (addr)
+		tx_key = false;
+
+	if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+		return -EINVAL;
 
+	err = 0;
+	if (wdev->current_bss)
 		err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
-		if (err)
-			return err;
+	if (err)
+		return err;
 
-		if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+	if (!addr) {
+		wdev->wext.keys->params[idx] = *params;
+		memcpy(wdev->wext.keys->data[idx],
+			params->key, params->key_len);
+		wdev->wext.keys->params[idx].key =
+			wdev->wext.keys->data[idx];
+	}
+
+	if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
+	    (tx_key || (!addr && wdev->wext.default_key == -1))) {
+		if (wdev->current_bss)
 			err = rdev->ops->set_default_key(&rdev->wiphy,
 							 dev, idx);
-			if (!err)
-				wdev->wext.default_key = idx;
-			return err;
-		}
+		if (!err)
+			wdev->wext.default_key = idx;
+		return err;
+	}
 
-		if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
-		    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+	    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+	    	if (wdev->current_bss)
 			err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
 							      dev, idx);
-			if (!err)
-				wdev->wext.default_mgmt_key = idx;
-			return err;
-		}
-
-		return 0;
+		if (!err)
+			wdev->wext.default_mgmt_key = idx;
+		return err;
 	}
+
+	return 0;
+}
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+				   struct net_device *dev, const u8 *addr,
+				   bool remove, bool tx_key, int idx,
+				   struct key_params *params)
+{
+	int err;
+
+	wdev_lock(dev->ieee80211_ptr);
+	err = __cfg80211_set_encryption(rdev, dev, addr, remove,
+					tx_key, idx, params);
+	wdev_unlock(dev->ieee80211_ptr);
+
+	return err;
 }
 
 int cfg80211_wext_siwencode(struct net_device *dev,
@@ -528,6 +579,10 @@ int cfg80211_wext_siwencode(struct net_d
 	bool remove = false;
 	struct key_params params;
 
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
+		return -EOPNOTSUPP;
+
 	/* no use -- only MFP (set_default_mgmt_key) is optional */
 	if (!rdev->ops->del_key ||
 	    !rdev->ops->add_key ||
@@ -548,9 +603,14 @@ int cfg80211_wext_siwencode(struct net_d
 		remove = true;
 	else if (erq->length == 0) {
 		/* No key data - just set the default TX key index */
-		err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+		err = 0;
+		wdev_lock(wdev);
+		if (wdev->current_bss)
+			err = rdev->ops->set_default_key(&rdev->wiphy,
+							 dev, idx);
 		if (!err)
 			wdev->wext.default_key = idx;
+		wdev_unlock(wdev);
 		return err;
 	}
 
@@ -583,6 +643,10 @@ int cfg80211_wext_siwencodeext(struct ne
 	struct key_params params;
 	u32 cipher;
 
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
+		return -EOPNOTSUPP;
+
 	/* no use -- only MFP (set_default_mgmt_key) is optional */
 	if (!rdev->ops->del_key ||
 	    !rdev->ops->add_key ||
@@ -656,37 +720,15 @@ int cfg80211_wext_siwencodeext(struct ne
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
 
-struct giwencode_cookie {
-	size_t buflen;
-	char *keybuf;
-};
-
-static void giwencode_get_key_cb(void *cookie, struct key_params *params)
-{
-	struct giwencode_cookie *data = cookie;
-
-	if (!params->key) {
-		data->buflen = 0;
-		return;
-	}
-
-	data->buflen = min_t(size_t, data->buflen, params->key_len);
-	memcpy(data->keybuf, params->key, data->buflen);
-}
-
 int cfg80211_wext_giwencode(struct net_device *dev,
 			    struct iw_request_info *info,
 			    struct iw_point *erq, char *keybuf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-	int idx, err;
-	struct giwencode_cookie data = {
-		.keybuf = keybuf,
-		.buflen = erq->length,
-	};
+	int idx;
 
-	if (!rdev->ops->get_key)
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 
 	idx = erq->flags & IW_ENCODE_INDEX;
@@ -701,21 +743,18 @@ int cfg80211_wext_giwencode(struct net_d
 
 	erq->flags = idx + 1;
 
-	err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
-				 giwencode_get_key_cb);
-	if (!err) {
-		erq->length = data.buflen;
-		erq->flags |= IW_ENCODE_ENABLED;
-		return 0;
-	}
-
-	if (err == -ENOENT) {
+	if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
 		erq->flags |= IW_ENCODE_DISABLED;
 		erq->length = 0;
 		return 0;
 	}
 
-	return err;
+	erq->length = min_t(size_t, erq->length,
+			    wdev->wext.keys->params[idx].key_len);
+	memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
+	erq->flags |= IW_ENCODE_ENABLED;
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
 
--- wireless-testing.orig/include/net/cfg80211.h	2009-07-08 13:20:02.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2009-07-08 13:29:10.000000000 +0200
@@ -647,12 +647,17 @@ struct cfg80211_crypto_settings {
  * @auth_type: Authentication type (algorithm)
  * @ie: Extra IEs to add to Authentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_auth_request {
 	struct cfg80211_bss *bss;
 	const u8 *ie;
 	size_t ie_len;
 	enum nl80211_auth_type auth_type;
+	const u8 *key;
+	u8 key_len, key_idx;
 };
 
 /**
@@ -727,6 +732,8 @@ struct cfg80211_disassoc_request {
  * @ie: information element(s) to include in the beacon
  * @ie_len: length of that
  * @beacon_interval: beacon interval to use
+ * @privacy: this is a protected network, keys will be configured
+ *	after joining
  */
 struct cfg80211_ibss_params {
 	u8 *ssid;
@@ -736,6 +743,7 @@ struct cfg80211_ibss_params {
 	u8 ssid_len, ie_len;
 	u16 beacon_interval;
 	bool channel_fixed;
+	bool privacy;
 };
 
 /**
@@ -755,6 +763,9 @@ struct cfg80211_ibss_params {
  * @assoc_ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
  * @crypto: crypto settings
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_connect_params {
 	struct ieee80211_channel *channel;
@@ -766,6 +777,8 @@ struct cfg80211_connect_params {
 	size_t ie_len;
 	bool privacy;
 	struct cfg80211_crypto_settings crypto;
+	const u8 *key;
+	u8 key_len, key_idx;
 };
 
 /**
@@ -1255,9 +1268,10 @@ extern void wiphy_unregister(struct wiph
  */
 extern void wiphy_free(struct wiphy *wiphy);
 
-/* internal struct */
+/* internal structs */
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
+struct cfg80211_cached_keys;
 
 #define MAX_AUTH_BSSES		4
 
@@ -1299,6 +1313,7 @@ struct wireless_dev {
 		CFG80211_SME_CONNECTED,
 	} sme_state;
 	struct cfg80211_conn *conn;
+	struct cfg80211_cached_keys *connect_keys;
 
 	struct list_head event_list;
 	spinlock_t event_lock;
@@ -1312,6 +1327,7 @@ struct wireless_dev {
 	struct {
 		struct cfg80211_ibss_params ibss;
 		struct cfg80211_connect_params connect;
+		struct cfg80211_cached_keys *keys;
 		u8 *ie;
 		size_t ie_len;
 		u8 bssid[ETH_ALEN];
--- wireless-testing.orig/net/wireless/core.h	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/wireless/core.h	2009-07-08 13:29:10.000000000 +0200
@@ -241,6 +241,12 @@ struct cfg80211_event {
 	};
 };
 
+struct cfg80211_cached_keys {
+	struct key_params params[6];
+	u8 data[6][WLAN_MAX_KEY_LEN];
+	int def, defmgmt;
+};
+
 
 /* free object */
 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -259,14 +265,18 @@ void cfg80211_bss_age(struct cfg80211_re
 /* IBSS */
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 struct cfg80211_ibss_params *params);
+			 struct cfg80211_ibss_params *params,
+			 struct cfg80211_cached_keys *connkeys);
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_ibss_params *params);
+		       struct cfg80211_ibss_params *params,
+		       struct cfg80211_cached_keys *connkeys);
 void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, bool nowext);
 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev);
 
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -275,12 +285,14 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 enum nl80211_auth_type auth_type,
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
-			 const u8 *ie, int ie_len);
+			 const u8 *ie, int ie_len,
+			 const u8 *key, int key_len, int key_idx);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
-		       const u8 *ie, int ie_len);
+		       const u8 *ie, int ie_len,
+		       const u8 *key, int key_len, int key_idx);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev,
 			  struct ieee80211_channel *chan,
@@ -313,10 +325,12 @@ void __cfg80211_connect_result(struct ne
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_connect_params *connect);
+		       struct cfg80211_connect_params *connect,
+		       struct cfg80211_cached_keys *connkeys);
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
 		     struct net_device *dev,
-		     struct cfg80211_connect_params *connect);
+		     struct cfg80211_connect_params *connect,
+		     struct cfg80211_cached_keys *connkeys);
 int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev, u16 reason,
 			  bool wextev);
@@ -326,11 +340,14 @@ int cfg80211_disconnect(struct cfg80211_
 void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
 		       const u8 *req_ie, size_t req_ie_len,
 		       const u8 *resp_ie, size_t resp_ie_len);
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev);
 
 void cfg80211_conn_work(struct work_struct *work);
 
 /* internal helpers */
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+				   struct key_params *params, int key_idx,
 				   const u8 *mac_addr);
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 			     size_t ie_len, u16 reason, bool from_ap);
@@ -338,5 +355,6 @@ void cfg80211_sme_scan_done(struct net_d
 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
 void cfg80211_sme_disassoc(struct net_device *dev, int idx);
 void __cfg80211_scan_done(struct work_struct *wk);
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
 
 #endif /* __NET_WIRELESS_CORE_H */
--- wireless-testing.orig/net/wireless/core.c	2009-07-08 13:20:02.000000000 +0200
+++ wireless-testing/net/wireless/core.c	2009-07-08 13:29:10.000000000 +0200
@@ -707,14 +707,10 @@ static int cfg80211_netdev_notifier_call
 		wdev_lock(wdev);
 		switch (wdev->iftype) {
 		case NL80211_IFTYPE_ADHOC:
-			if (wdev->wext.ibss.ssid_len)
-				__cfg80211_join_ibss(rdev, dev,
-						     &wdev->wext.ibss);
+			cfg80211_ibss_wext_join(rdev, wdev);
 			break;
 		case NL80211_IFTYPE_STATION:
-			if (wdev->wext.connect.ssid_len)
-				__cfg80211_connect(rdev, dev,
-						   &wdev->wext.connect);
+			cfg80211_mgd_wext_connect(rdev, wdev);
 			break;
 		default:
 			break;
@@ -731,6 +727,9 @@ static int cfg80211_netdev_notifier_call
 		}
 		mutex_unlock(&rdev->devlist_mtx);
 		mutex_destroy(&wdev->mtx);
+#ifdef CONFIG_WIRELESS_EXT
+		kfree(wdev->wext.keys);
+#endif
 		break;
 	case NETDEV_PRE_UP:
 		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
--- wireless-testing.orig/net/wireless/sme.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/wireless/sme.c	2009-07-08 13:29:10.000000000 +0200
@@ -126,7 +126,9 @@ static int cfg80211_conn_do_work(struct 
 					    params->channel, params->auth_type,
 					    params->bssid,
 					    params->ssid, params->ssid_len,
-					    NULL, 0);
+					    NULL, 0,
+					    params->key, params->key_len,
+					    params->key_idx);
 	case CFG80211_CONN_ASSOCIATE_NEXT:
 		BUG_ON(!rdev->ops->assoc);
 		wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -280,8 +282,12 @@ void cfg80211_sme_rx_auth(struct net_dev
 		/* select automatically between only open, shared, leap */
 		switch (wdev->conn->params.auth_type) {
 		case NL80211_AUTHTYPE_OPEN_SYSTEM:
-			wdev->conn->params.auth_type =
-				NL80211_AUTHTYPE_SHARED_KEY;
+			if (wdev->connect_keys)
+				wdev->conn->params.auth_type =
+					NL80211_AUTHTYPE_SHARED_KEY;
+			else
+				wdev->conn->params.auth_type =
+					NL80211_AUTHTYPE_NETWORK_EAP;
 			break;
 		case NL80211_AUTHTYPE_SHARED_KEY:
 			wdev->conn->params.auth_type =
@@ -354,10 +360,8 @@ void __cfg80211_connect_result(struct ne
 #endif
 
 	if (status == WLAN_STATUS_SUCCESS &&
-	    wdev->sme_state == CFG80211_SME_IDLE) {
-		wdev->sme_state = CFG80211_SME_CONNECTED;
-		return;
-	}
+	    wdev->sme_state == CFG80211_SME_IDLE)
+		goto success;
 
 	if (wdev->sme_state != CFG80211_SME_CONNECTING)
 		return;
@@ -371,24 +375,29 @@ void __cfg80211_connect_result(struct ne
 	if (wdev->conn)
 		wdev->conn->state = CFG80211_CONN_IDLE;
 
-	if (status == WLAN_STATUS_SUCCESS) {
-		bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-				       wdev->ssid, wdev->ssid_len,
-				       WLAN_CAPABILITY_ESS,
-				       WLAN_CAPABILITY_ESS);
-
-		if (WARN_ON(!bss))
-			return;
-
-		cfg80211_hold_bss(bss_from_pub(bss));
-		wdev->current_bss = bss_from_pub(bss);
-
-		wdev->sme_state = CFG80211_SME_CONNECTED;
-	} else {
+	if (status != WLAN_STATUS_SUCCESS) {
 		wdev->sme_state = CFG80211_SME_IDLE;
 		kfree(wdev->conn);
 		wdev->conn = NULL;
+		kfree(wdev->connect_keys);
+		wdev->connect_keys = NULL;
+		return;
 	}
+
+	bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+			       wdev->ssid, wdev->ssid_len,
+			       WLAN_CAPABILITY_ESS,
+			       WLAN_CAPABILITY_ESS);
+
+	if (WARN_ON(!bss))
+		return;
+
+	cfg80211_hold_bss(bss_from_pub(bss));
+	wdev->current_bss = bss_from_pub(bss);
+
+ success:
+	wdev->sme_state = CFG80211_SME_CONNECTED;
+	cfg80211_upload_connect_keys(wdev);
 }
 
 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -517,6 +526,8 @@ void __cfg80211_disconnected(struct net_
 			     size_t ie_len, u16 reason, bool from_ap)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	int i;
 #ifdef CONFIG_WIRELESS_EXT
 	union iwreq_data wrqu;
 #endif
@@ -544,8 +555,15 @@ void __cfg80211_disconnected(struct net_
 		wdev->conn = NULL;
 	}
 
-	nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
-				  reason, ie, ie_len, from_ap);
+	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
+
+	/*
+	 * Delete all the keys ... pairwise keys can't really
+	 * exist any more anyway, but default keys might.
+	 */
+	if (rdev->ops->del_key)
+		for (i = 0; i < 6; i++)
+			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 
 #ifdef CONFIG_WIRELESS_EXT
 	memset(&wrqu, 0, sizeof(wrqu));
@@ -581,7 +599,8 @@ EXPORT_SYMBOL(cfg80211_disconnected);
 
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_connect_params *connect)
+		       struct cfg80211_connect_params *connect,
+		       struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
@@ -591,6 +610,24 @@ int __cfg80211_connect(struct cfg80211_r
 	if (wdev->sme_state != CFG80211_SME_IDLE)
 		return -EALREADY;
 
+	if (WARN_ON(wdev->connect_keys)) {
+		kfree(wdev->connect_keys);
+		wdev->connect_keys = NULL;
+	}
+
+	if (connkeys && connkeys->def >= 0) {
+		int idx;
+
+		idx = connkeys->def;
+		/* If given a WEP key we may need it for shared key auth */
+		if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
+		    connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
+			connect->key_idx = idx;
+			connect->key = connkeys->params[idx].key;
+			connect->key_len = connkeys->params[idx].key_len;
+		}
+	}
+
 	if (!rdev->ops->connect) {
 		if (!rdev->ops->auth || !rdev->ops->assoc)
 			return -EOPNOTSUPP;
@@ -641,6 +678,7 @@ int __cfg80211_connect(struct cfg80211_r
 			cfg80211_get_conn_bss(wdev);
 
 		wdev->sme_state = CFG80211_SME_CONNECTING;
+		wdev->connect_keys = connkeys;
 
 		/* we're good if we have both BSSID and channel */
 		if (wdev->conn->params.bssid && wdev->conn->params.channel) {
@@ -663,13 +701,16 @@ int __cfg80211_connect(struct cfg80211_r
 			kfree(wdev->conn);
 			wdev->conn = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
+			wdev->connect_keys = NULL;
 		}
 
 		return err;
 	} else {
 		wdev->sme_state = CFG80211_SME_CONNECTING;
+		wdev->connect_keys = connkeys;
 		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
 		if (err) {
+			wdev->connect_keys = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
 			return err;
 		}
@@ -683,12 +724,13 @@ int __cfg80211_connect(struct cfg80211_r
 
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
 		     struct net_device *dev,
-		     struct cfg80211_connect_params *connect)
+		     struct cfg80211_connect_params *connect,
+		     struct cfg80211_cached_keys *connkeys)
 {
 	int err;
 
 	wdev_lock(dev->ieee80211_ptr);
-	err = __cfg80211_connect(rdev, dev, connect);
+	err = __cfg80211_connect(rdev, dev, connect, connkeys);
 	wdev_unlock(dev->ieee80211_ptr);
 
 	return err;
@@ -705,6 +747,9 @@ int __cfg80211_disconnect(struct cfg8021
 	if (wdev->sme_state == CFG80211_SME_IDLE)
 		return -EINVAL;
 
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+
 	if (!rdev->ops->disconnect) {
 		if (!rdev->ops->deauth)
 			return -EOPNOTSUPP;
--- wireless-testing.orig/net/wireless/wext-sme.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/wireless/wext-sme.c	2009-07-08 13:29:10.000000000 +0200
@@ -10,10 +10,11 @@
 #include <net/cfg80211.h>
 #include "nl80211.h"
 
-static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
-				     struct wireless_dev *wdev)
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev)
 {
-	int err;
+	struct cfg80211_cached_keys *ck = NULL;
+	int err, i;
 
 	ASSERT_RDEV_LOCK(rdev);
 	ASSERT_WDEV_LOCK(wdev);
@@ -25,10 +26,25 @@ static int cfg80211_mgd_wext_connect(str
 	wdev->wext.connect.ie_len = wdev->wext.ie_len;
 	wdev->wext.connect.privacy = wdev->wext.default_key != -1;
 
-	err = 0;
-	if (wdev->wext.connect.ssid_len != 0)
-		err = __cfg80211_connect(rdev, wdev->netdev,
-					 &wdev->wext.connect);
+	if (wdev->wext.keys) {
+		wdev->wext.keys->def = wdev->wext.default_key;
+		wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+	}
+
+	if (!wdev->wext.connect.ssid_len)
+		return 0;
+
+	if (wdev->wext.keys) {
+		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+		if (!ck)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			ck->params[i].key = ck->data[i];
+	}
+	err = __cfg80211_connect(rdev, wdev->netdev,
+				 &wdev->wext.connect, ck);
+	if (err)
+		kfree(ck);
 
 	return err;
 }
--- wireless-testing.orig/net/wireless/mlme.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/wireless/mlme.c	2009-07-08 13:29:10.000000000 +0200
@@ -328,7 +328,8 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 enum nl80211_auth_type auth_type,
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
-			 const u8 *ie, int ie_len)
+			 const u8 *ie, int ie_len,
+			 const u8 *key, int key_len, int key_idx)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_auth_request req;
@@ -337,6 +338,10 @@ int __cfg80211_mlme_auth(struct cfg80211
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+		if (!key || !key_len || key_idx < 0 || key_idx > 4)
+			return -EINVAL;
+
 	if (wdev->current_bss &&
 	    memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
 		return -EALREADY;
@@ -359,6 +364,9 @@ int __cfg80211_mlme_auth(struct cfg80211
 	req.auth_type = auth_type;
 	req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
 				   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+	req.key = key;
+	req.key_len = key_len;
+	req.key_idx = key_idx;
 	if (!req.bss)
 		return -ENOENT;
 
@@ -396,13 +404,15 @@ int cfg80211_mlme_auth(struct cfg80211_r
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
-		       const u8 *ie, int ie_len)
+		       const u8 *ie, int ie_len,
+		       const u8 *key, int key_len, int key_idx)
 {
 	int err;
 
 	wdev_lock(dev->ieee80211_ptr);
 	err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-				   ssid, ssid_len, ie, ie_len);
+				   ssid, ssid_len, ie, ie_len,
+				   key, key_len, key_idx);
 	wdev_unlock(dev->ieee80211_ptr);
 
 	return err;
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-07-08 13:29:10.000000000 +0200
@@ -247,6 +247,9 @@ struct ieee80211_mgd_work {
 
 	int tries;
 
+	u8 key[WLAN_KEY_LEN_WEP104];
+	u8 key_len, key_idx;
+
 	/* must be last */
 	u8 ie[0]; /* for auth or assoc frame, not probe */
 };
@@ -321,6 +324,7 @@ struct ieee80211_if_ibss {
 
 	bool fixed_bssid;
 	bool fixed_channel;
+	bool privacy;
 
 	u8 bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -1090,8 +1094,8 @@ int ieee80211_add_pending_skbs(struct ie
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
-			 u8 *extra, size_t extra_len,
-			 const u8 *bssid, int encrypt);
+			 u8 *extra, size_t extra_len, const u8 *bssid,
+			 const u8 *key, u8 key_len, u8 key_idx);
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 			     const u8 *ie, size_t ie_len);
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
--- wireless-testing.orig/net/mac80211/mlme.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2009-07-08 13:29:10.000000000 +0200
@@ -954,7 +954,7 @@ ieee80211_authenticate(struct ieee80211_
 	       sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
 
 	ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
-			    wk->bss->cbss.bssid, 0);
+			    wk->bss->cbss.bssid, NULL, 0, 0);
 	wk->auth_transaction = 2;
 
 	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -1176,7 +1176,8 @@ static void ieee80211_auth_challenge(str
 		return;
 	ieee80211_send_auth(sdata, 3, wk->auth_alg,
 			    elems.challenge - 2, elems.challenge_len + 2,
-			    wk->bss->cbss.bssid, 1);
+			    wk->bss->cbss.bssid,
+			    wk->key, wk->key_len, wk->key_idx);
 	wk->auth_transaction = 4;
 }
 
@@ -2175,6 +2176,12 @@ int ieee80211_mgd_auth(struct ieee80211_
 		wk->ie_len = req->ie_len;
 	}
 
+	if (req->key && req->key_len) {
+		wk->key_len = req->key_len;
+		wk->key_idx = req->key_idx;
+		memcpy(wk->key, req->key, req->key_len);
+	}
+
 	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
 	memcpy(wk->ssid, ssid + 2, ssid[1]);
 	wk->ssid_len = ssid[1];
--- wireless-testing.orig/net/mac80211/ibss.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/mac80211/ibss.c	2009-07-08 13:29:10.000000000 +0200
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(
 	 */
 	if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
 		ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
-				    sdata->u.ibss.bssid, 0);
+				    sdata->u.ibss.bssid, NULL, 0, 0);
 }
 
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(st
 
 	capability = WLAN_CAPABILITY_IBSS;
 
-	if (sdata->default_key)
+	if (ifibss->privacy)
 		capability |= WLAN_CAPABILITY_PRIVACY;
 	else
 		sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(stru
 		return;
 
 	capability = WLAN_CAPABILITY_IBSS;
-	if (sdata->default_key)
+	if (ifibss->privacy)
 		capability |= WLAN_CAPABILITY_PRIVACY;
-
 	if (ifibss->fixed_bssid)
 		bssid = ifibss->bssid;
 	if (ifibss->fixed_channel)
@@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211
 	} else
 		sdata->u.ibss.fixed_bssid = false;
 
+	sdata->u.ibss.privacy = params->privacy;
+
 	sdata->vif.bss_conf.beacon_int = params->beacon_interval;
 
 	sdata->u.ibss.channel = params->channel;
--- wireless-testing.orig/net/mac80211/util.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-07-08 13:29:10.000000000 +0200
@@ -31,6 +31,7 @@
 #include "mesh.h"
 #include "wme.h"
 #include "led.h"
+#include "wep.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
 void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -778,12 +779,13 @@ u32 ieee80211_mandatory_rates(struct iee
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
-			 u8 *extra, size_t extra_len,
-			 const u8 *bssid, int encrypt)
+			 u8 *extra, size_t extra_len, const u8 *bssid,
+			 const u8 *key, u8 key_len, u8 key_idx)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
+	int err;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    sizeof(*mgmt) + 6 + extra_len);
@@ -798,8 +800,6 @@ void ieee80211_send_auth(struct ieee8021
 	memset(mgmt, 0, 24 + 6);
 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					  IEEE80211_STYPE_AUTH);
-	if (encrypt)
-		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 	memcpy(mgmt->da, bssid, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -809,7 +809,13 @@ void ieee80211_send_auth(struct ieee8021
 	if (extra)
 		memcpy(skb_put(skb, extra_len), extra, extra_len);
 
-	ieee80211_tx_skb(sdata, skb, encrypt);
+	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
+		WARN_ON(err);
+	}
+
+	ieee80211_tx_skb(sdata, skb, 0);
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
--- wireless-testing.orig/net/mac80211/wep.c	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/mac80211/wep.c	2009-07-08 13:29:10.000000000 +0200
@@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct c
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-static int ieee80211_wep_encrypt(struct ieee80211_local *local,
-				 struct sk_buff *skb,
-				 const u8 *key, int keylen, int keyidx)
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  const u8 *key, int keylen, int keyidx)
 {
 	u8 *iv;
 	size_t len;
--- wireless-testing.orig/net/mac80211/wep.h	2009-07-08 13:20:01.000000000 +0200
+++ wireless-testing/net/mac80211/wep.h	2009-07-08 13:29:10.000000000 +0200
@@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_
 void ieee80211_wep_free(struct ieee80211_local *local);
 void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 				size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  const u8 *key, int keylen, int keyidx);
 int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 			       size_t klen, u8 *data, size_t data_len);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
--- wireless-testing.orig/net/wireless/ibss.c	2009-07-08 13:20:02.000000000 +0200
+++ wireless-testing/net/wireless/ibss.c	2009-07-08 13:29:10.000000000 +0200
@@ -39,6 +39,8 @@ void __cfg80211_ibss_joined(struct net_d
 	cfg80211_hold_bss(bss_from_pub(bss));
 	wdev->current_bss = bss_from_pub(bss);
 
+	cfg80211_upload_connect_keys(wdev);
+
 	nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
 				GFP_KERNEL);
 #ifdef CONFIG_WIRELESS_EXT
@@ -71,7 +73,8 @@ EXPORT_SYMBOL(cfg80211_ibss_joined);
 
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 struct cfg80211_ibss_params *params)
+			 struct cfg80211_ibss_params *params,
+			 struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
@@ -81,13 +84,18 @@ int __cfg80211_join_ibss(struct cfg80211
 	if (wdev->ssid_len)
 		return -EALREADY;
 
+	if (WARN_ON(wdev->connect_keys))
+		kfree(wdev->connect_keys);
+	wdev->connect_keys = connkeys;
+
 #ifdef CONFIG_WIRELESS_EXT
 	wdev->wext.ibss.channel = params->channel;
 #endif
 	err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
-
-	if (err)
+	if (err) {
+		wdev->connect_keys = NULL;
 		return err;
+	}
 
 	memcpy(wdev->ssid, params->ssid, params->ssid_len);
 	wdev->ssid_len = params->ssid_len;
@@ -97,13 +105,14 @@ int __cfg80211_join_ibss(struct cfg80211
 
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_ibss_params *params)
+		       struct cfg80211_ibss_params *params,
+		       struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
 
 	wdev_lock(wdev);
-	err = __cfg80211_join_ibss(rdev, dev, params);
+	err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
 	wdev_unlock(wdev);
 
 	return err;
@@ -112,9 +121,22 @@ int cfg80211_join_ibss(struct cfg80211_r
 static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	int i;
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+
+	/*
+	 * Delete all the keys ... pairwise keys can't really
+	 * exist any more anyway, but default keys might.
+	 */
+	if (rdev->ops->del_key)
+		for (i = 0; i < 6; i++)
+			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+
 	if (wdev->current_bss) {
 		cfg80211_unhold_bss(wdev->current_bss);
 		cfg80211_put_bss(&wdev->current_bss->pub);
@@ -172,11 +194,14 @@ int cfg80211_leave_ibss(struct cfg80211_
 }
 
 #ifdef CONFIG_WIRELESS_EXT
-static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
-				   struct wireless_dev *wdev)
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev)
 {
+	struct cfg80211_cached_keys *ck = NULL;
 	enum ieee80211_band band;
-	int i;
+	int i, err;
+
+	ASSERT_WDEV_LOCK(wdev);
 
 	if (!wdev->wext.ibss.beacon_interval)
 		wdev->wext.ibss.beacon_interval = 100;
@@ -216,8 +241,24 @@ static int cfg80211_ibss_wext_join(struc
 	if (!netif_running(wdev->netdev))
 		return 0;
 
-	return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
-				  wdev->netdev, &wdev->wext.ibss);
+	if (wdev->wext.keys)
+		wdev->wext.keys->def = wdev->wext.default_key;
+
+	wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
+
+	if (wdev->wext.keys) {
+		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+		if (!ck)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			ck->params[i].key = ck->data[i];
+	}
+	err = __cfg80211_join_ibss(rdev, wdev->netdev,
+				   &wdev->wext.ibss, ck);
+	if (err)
+		kfree(ck);
+
+	return err;
 }
 
 int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -265,7 +306,11 @@ int cfg80211_ibss_wext_siwfreq(struct ne
 		wdev->wext.ibss.channel_fixed = false;
 	}
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
@@ -333,7 +378,11 @@ int cfg80211_ibss_wext_siwessid(struct n
 	memcpy(wdev->wext.ibss.ssid, ssid, len);
 	wdev->wext.ibss.ssid_len = len;
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
@@ -414,7 +463,11 @@ int cfg80211_ibss_wext_siwap(struct net_
 	} else
 		wdev->wext.ibss.bssid = NULL;
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
--- wireless-testing.orig/net/wireless/util.c	2009-07-08 13:20:02.000000000 +0200
+++ wireless-testing/net/wireless/util.c	2009-07-08 13:29:10.000000000 +0200
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct 
 			set_mandatory_flags_band(wiphy->bands[band], band);
 }
 
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+				   struct key_params *params, int key_idx,
 				   const u8 *mac_addr)
 {
+	int i;
+
 	if (key_idx > 5)
 		return -EINVAL;
 
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struc
 		}
 	}
 
+	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
+		if (params->cipher == rdev->wiphy.cipher_suites[i])
+			break;
+	if (i == rdev->wiphy.n_cipher_suites)
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -523,3 +532,33 @@ const u8 *ieee80211_bss_get_ie(struct cf
 	return NULL;
 }
 EXPORT_SYMBOL(ieee80211_bss_get_ie);
+
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	struct net_device *dev = wdev->netdev;
+	int i;
+
+	if (!wdev->connect_keys)
+		return;
+
+	for (i = 0; i < 6; i++) {
+		if (!wdev->connect_keys->params[i].cipher)
+			continue;
+		if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+					&wdev->connect_keys->params[i]))
+			printk(KERN_ERR "%s: failed to set key %d\n",
+				dev->name, i);
+		if (wdev->connect_keys->def == i)
+			if (rdev->ops->set_default_key(wdev->wiphy, dev, i))
+				printk(KERN_ERR "%s: failed to set defkey %d\n",
+					dev->name, i);
+		if (wdev->connect_keys->defmgmt == i)
+			if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+				printk(KERN_ERR "%s: failed to set mgtdef %d\n",
+					dev->name, i);
+	}
+
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+}



^ permalink raw reply

* [PATCH v3] cfg80211: rework key operation
From: Johannes Berg @ 2009-07-08 12:22 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <1247052613.12857.0.camel@johannes.local>

This reworks the key operation in cfg80211, and now only
allows, from userspace, configuring keys (via nl80211)
after the connection has been established (in managed
mode), the IBSS been joined (in IBSS mode), at any time
(in AP[_VLAN] modes) or never for all the other modes.

In order to do shared key authentication correctly, it
is now possible to give a WEP key to the AUTH command.
To configure static WEP keys, these are given to the
CONNECT or IBSS_JOIN command directly, for a userspace
SME it is assumed it will configure it properly after
the connection has been established.

Since mac80211 used to check the default key in IBSS
mode to see whether or not the network is protected,
it needs an update in that area, as well as an update
to make use of the WEP key passed to auth() for shared
key authentication.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
v3: rebase to correct tree (w/o netns work)

 include/linux/nl80211.h    |    5 +
 include/net/cfg80211.h     |   18 ++++
 net/mac80211/ibss.c        |    9 +-
 net/mac80211/ieee80211_i.h |    8 +-
 net/mac80211/mlme.c        |   11 ++
 net/mac80211/util.c        |   16 ++--
 net/mac80211/wep.c         |    6 -
 net/mac80211/wep.h         |    3 
 net/wireless/core.c        |   11 +-
 net/wireless/core.h        |   32 ++++++--
 net/wireless/ibss.c        |   79 +++++++++++++++++---
 net/wireless/mlme.c        |   16 +++-
 net/wireless/nl80211.c     |  170 +++++++++++++++++++++++++++++++++++++++------
 net/wireless/sme.c         |   97 ++++++++++++++++++-------
 net/wireless/util.c        |   41 ++++++++++
 net/wireless/wext-compat.c |  167 +++++++++++++++++++++++++++-----------------
 net/wireless/wext-sme.c    |   30 ++++++-
 17 files changed, 556 insertions(+), 163 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2009-07-08 14:11:57.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h	2009-07-08 14:12:35.000000000 +0200
@@ -569,6 +569,9 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_KEY: key information in a nested attribute with
  *	%NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ *	and join_ibss(), key information is in a nested attribute each
+ *	with %NL80211_KEY_* sub-attributes
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -696,6 +699,7 @@ enum nl80211_attrs {
 	NL80211_ATTR_PREV_BSSID,
 
 	NL80211_ATTR_KEY,
+	NL80211_ATTR_KEYS,
 
 	/* add attributes here, update the policy in nl80211.c */
 
@@ -726,6 +730,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_REG_RULES		32
--- wireless-testing.orig/net/wireless/nl80211.c	2009-07-08 14:11:57.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c	2009-07-08 14:12:35.000000000 +0200
@@ -138,8 +138,7 @@ static struct nla_policy nl80211_policy[
 /* policy for the attributes */
 static struct nla_policy
 nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
-	[NL80211_KEY_DATA] = { .type = NLA_BINARY,
-				    .len = WLAN_MAX_KEY_LEN },
+	[NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
 	[NL80211_KEY_IDX] = { .type = NLA_U8 },
 	[NL80211_KEY_CIPHER] = { .type = NLA_U32 },
 	[NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
@@ -305,6 +304,83 @@ static int nl80211_parse_key(struct genl
 	return 0;
 }
 
+static struct cfg80211_cached_keys *
+nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
+		       struct nlattr *keys)
+{
+	struct key_parse parse;
+	struct nlattr *key;
+	struct cfg80211_cached_keys *result;
+	int rem, err, def = 0;
+
+	result = kzalloc(sizeof(*result), GFP_KERNEL);
+	if (!result)
+		return ERR_PTR(-ENOMEM);
+
+	result->def = -1;
+	result->defmgmt = -1;
+
+	nla_for_each_nested(key, keys, rem) {
+		memset(&parse, 0, sizeof(parse));
+		parse.idx = -1;
+
+		err = nl80211_parse_key_new(key, &parse);
+		if (err)
+			goto error;
+		err = -EINVAL;
+		if (!parse.p.key)
+			goto error;
+		if (parse.idx < 0 || parse.idx > 4)
+			goto error;
+		if (parse.def) {
+			if (def)
+				goto error;
+			def = 1;
+			result->def = parse.idx;
+		} else if (parse.defmgmt)
+			goto error;
+		err = cfg80211_validate_key_settings(rdev, &parse.p,
+						     parse.idx, NULL);
+		if (err)
+			goto error;
+		result->params[parse.idx].cipher = parse.p.cipher;
+		result->params[parse.idx].key_len = parse.p.key_len;
+		result->params[parse.idx].key = result->data[parse.idx];
+		memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
+	}
+
+	return result;
+ error:
+	kfree(result);
+	return ERR_PTR(err);
+}
+
+static int nl80211_key_allowed(struct wireless_dev *wdev)
+{
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (!netif_running(wdev->netdev))
+		return -ENETDOWN;
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_AP_VLAN:
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		if (!wdev->current_bss)
+			return -ENOLINK;
+		break;
+	case NL80211_IFTYPE_STATION:
+		if (wdev->sme_state != CFG80211_SME_CONNECTED)
+			return -ENOLINK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
@@ -1211,7 +1287,11 @@ static int nl80211_set_key(struct sk_buf
 		goto out;
 	}
 
-	err = func(&rdev->wiphy, dev, key.idx);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = func(&rdev->wiphy, dev, key.idx);
+
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
 		if (func == rdev->ops->set_default_key)
@@ -1220,6 +1300,7 @@ static int nl80211_set_key(struct sk_buf
 			dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
 	}
 #endif
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1234,7 +1315,7 @@ static int nl80211_set_key(struct sk_buf
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev;
-	int err, i;
+	int err;
 	struct net_device *dev;
 	struct key_parse key;
 	u8 *mac_addr = NULL;
@@ -1249,29 +1330,28 @@ static int nl80211_new_key(struct sk_buf
 	if (info->attrs[NL80211_ATTR_MAC])
 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
-	if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
-		return -EINVAL;
-
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
 	if (err)
 		goto unlock_rtnl;
 
-	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-		if (key.p.cipher == rdev->wiphy.cipher_suites[i])
-			break;
-	if (i == rdev->wiphy.n_cipher_suites) {
-		err = -EINVAL;
+	if (!rdev->ops->add_key) {
+		err = -EOPNOTSUPP;
 		goto out;
 	}
 
-	if (!rdev->ops->add_key) {
-		err = -EOPNOTSUPP;
+	if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
+		err = -EINVAL;
 		goto out;
 	}
 
-	err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
+					 mac_addr, &key.p);
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -1308,7 +1388,10 @@ static int nl80211_del_key(struct sk_buf
 		goto out;
 	}
 
-	err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
+	wdev_lock(dev->ieee80211_ptr);
+	err = nl80211_key_allowed(dev->ieee80211_ptr);
+	if (!err)
+		err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
 
 #ifdef CONFIG_WIRELESS_EXT
 	if (!err) {
@@ -1318,6 +1401,7 @@ static int nl80211_del_key(struct sk_buf
 			dev->ieee80211_ptr->wext.default_mgmt_key = -1;
 	}
 #endif
+	wdev_unlock(dev->ieee80211_ptr);
 
  out:
 	cfg80211_unlock_rdev(rdev);
@@ -3158,6 +3242,7 @@ static int nl80211_authenticate(struct s
 	const u8 *bssid, *ssid, *ie = NULL;
 	int err, ssid_len, ie_len = 0;
 	enum nl80211_auth_type auth_type;
+	struct key_parse key;
 
 	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
 		return -EINVAL;
@@ -3174,6 +3259,25 @@ static int nl80211_authenticate(struct s
 	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
 		return -EINVAL;
 
+	err = nl80211_parse_key(info, &key);
+	if (err)
+		return err;
+
+	if (key.idx >= 0) {
+		if (!key.p.key || !key.p.key_len)
+			return -EINVAL;
+		if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
+		     key.p.key_len != WLAN_KEY_LEN_WEP40) &&
+		    (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
+		     key.p.key_len != WLAN_KEY_LEN_WEP104))
+			return -EINVAL;
+		if (key.idx > 4)
+			return -EINVAL;
+	} else {
+		key.p.key_len = 0;
+		key.p.key = NULL;
+	}
+
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
@@ -3218,7 +3322,8 @@ static int nl80211_authenticate(struct s
 	}
 
 	err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-				 ssid, ssid_len, ie, ie_len);
+				 ssid, ssid_len, ie, ie_len,
+				 key.p.key, key.p.key_len, key.idx);
 
 out:
 	cfg80211_unlock_rdev(rdev);
@@ -3505,6 +3610,7 @@ static int nl80211_join_ibss(struct sk_b
 	struct net_device *dev;
 	struct cfg80211_ibss_params ibss;
 	struct wiphy *wiphy;
+	struct cfg80211_cached_keys *connkeys = NULL;
 	int err;
 
 	memset(&ibss, 0, sizeof(ibss));
@@ -3569,13 +3675,26 @@ static int nl80211_join_ibss(struct sk_b
 	}
 
 	ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
+	ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+	if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+		connkeys = nl80211_parse_connkeys(rdev,
+					info->attrs[NL80211_ATTR_KEYS]);
+		if (IS_ERR(connkeys)) {
+			err = PTR_ERR(connkeys);
+			connkeys = NULL;
+			goto out;
+		}
+	}
 
-	err = cfg80211_join_ibss(rdev, dev, &ibss);
+	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
 
 out:
 	cfg80211_unlock_rdev(rdev);
 	dev_put(dev);
 unlock_rtnl:
+	if (err)
+		kfree(connkeys);
 	rtnl_unlock();
 	return err;
 }
@@ -3745,6 +3864,7 @@ static int nl80211_connect(struct sk_buf
 	struct net_device *dev;
 	struct cfg80211_connect_params connect;
 	struct wiphy *wiphy;
+	struct cfg80211_cached_keys *connkeys = NULL;
 	int err;
 
 	memset(&connect, 0, sizeof(connect));
@@ -3809,12 +3929,24 @@ static int nl80211_connect(struct sk_buf
 		}
 	}
 
-	err = cfg80211_connect(rdev, dev, &connect);
+	if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+		connkeys = nl80211_parse_connkeys(rdev,
+					info->attrs[NL80211_ATTR_KEYS]);
+		if (IS_ERR(connkeys)) {
+			err = PTR_ERR(connkeys);
+			connkeys = NULL;
+			goto out;
+		}
+	}
+
+	err = cfg80211_connect(rdev, dev, &connect, connkeys);
 
 out:
 	cfg80211_unlock_rdev(rdev);
 	dev_put(dev);
 unlock_rtnl:
+	if (err)
+		kfree(connkeys);
 	rtnl_unlock();
 	return err;
 }
--- wireless-testing.orig/net/wireless/wext-compat.c	2009-07-08 14:11:57.000000000 +0200
+++ wireless-testing/net/wireless/wext-compat.c	2009-07-08 14:12:35.000000000 +0200
@@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_de
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
 
-static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
-				   struct net_device *dev, const u8 *addr,
-				   bool remove, bool tx_key, int idx,
-				   struct key_params *params)
-{
-	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int err;
+static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+				     struct net_device *dev, const u8 *addr,
+				     bool remove, bool tx_key, int idx,
+				     struct key_params *params)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err, i;
+
+	if (!wdev->wext.keys) {
+		wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
+					      GFP_KERNEL);
+		if (!wdev->wext.keys)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			wdev->wext.keys->params[i].key =
+				wdev->wext.keys->data[i];
+	}
+
+	if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
+	    wdev->iftype != NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
 
 	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+		if (!wdev->current_bss)
+			return -ENOLINK;
+
 		if (!rdev->ops->set_default_mgmt_key)
 			return -EOPNOTSUPP;
 
@@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struc
 		return -EINVAL;
 
 	if (remove) {
-		err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+		err = 0;
+		if (wdev->current_bss)
+			err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
 		if (!err) {
+			if (!addr) {
+				wdev->wext.keys->params[idx].key_len = 0;
+				wdev->wext.keys->params[idx].cipher = 0;
+			}
 			if (idx == wdev->wext.default_key)
 				wdev->wext.default_key = -1;
 			else if (idx == wdev->wext.default_mgmt_key)
@@ -486,36 +509,64 @@ static int cfg80211_set_encryption(struc
 			return 0;
 
 		return err;
-	} else {
-		if (addr)
-			tx_key = false;
+	}
 
-		if (cfg80211_validate_key_settings(params, idx, addr))
-			return -EINVAL;
+	if (addr)
+		tx_key = false;
+
+	if (cfg80211_validate_key_settings(rdev, params, idx, addr))
+		return -EINVAL;
 
+	err = 0;
+	if (wdev->current_bss)
 		err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
-		if (err)
-			return err;
+	if (err)
+		return err;
 
-		if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+	if (!addr) {
+		wdev->wext.keys->params[idx] = *params;
+		memcpy(wdev->wext.keys->data[idx],
+			params->key, params->key_len);
+		wdev->wext.keys->params[idx].key =
+			wdev->wext.keys->data[idx];
+	}
+
+	if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
+	    (tx_key || (!addr && wdev->wext.default_key == -1))) {
+		if (wdev->current_bss)
 			err = rdev->ops->set_default_key(&rdev->wiphy,
 							 dev, idx);
-			if (!err)
-				wdev->wext.default_key = idx;
-			return err;
-		}
+		if (!err)
+			wdev->wext.default_key = idx;
+		return err;
+	}
 
-		if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
-		    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+	    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+	    	if (wdev->current_bss)
 			err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
 							      dev, idx);
-			if (!err)
-				wdev->wext.default_mgmt_key = idx;
-			return err;
-		}
-
-		return 0;
+		if (!err)
+			wdev->wext.default_mgmt_key = idx;
+		return err;
 	}
+
+	return 0;
+}
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+				   struct net_device *dev, const u8 *addr,
+				   bool remove, bool tx_key, int idx,
+				   struct key_params *params)
+{
+	int err;
+
+	wdev_lock(dev->ieee80211_ptr);
+	err = __cfg80211_set_encryption(rdev, dev, addr, remove,
+					tx_key, idx, params);
+	wdev_unlock(dev->ieee80211_ptr);
+
+	return err;
 }
 
 int cfg80211_wext_siwencode(struct net_device *dev,
@@ -528,6 +579,10 @@ int cfg80211_wext_siwencode(struct net_d
 	bool remove = false;
 	struct key_params params;
 
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
+		return -EOPNOTSUPP;
+
 	/* no use -- only MFP (set_default_mgmt_key) is optional */
 	if (!rdev->ops->del_key ||
 	    !rdev->ops->add_key ||
@@ -548,9 +603,14 @@ int cfg80211_wext_siwencode(struct net_d
 		remove = true;
 	else if (erq->length == 0) {
 		/* No key data - just set the default TX key index */
-		err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+		err = 0;
+		wdev_lock(wdev);
+		if (wdev->current_bss)
+			err = rdev->ops->set_default_key(&rdev->wiphy,
+							 dev, idx);
 		if (!err)
 			wdev->wext.default_key = idx;
+		wdev_unlock(wdev);
 		return err;
 	}
 
@@ -583,6 +643,10 @@ int cfg80211_wext_siwencodeext(struct ne
 	struct key_params params;
 	u32 cipher;
 
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
+		return -EOPNOTSUPP;
+
 	/* no use -- only MFP (set_default_mgmt_key) is optional */
 	if (!rdev->ops->del_key ||
 	    !rdev->ops->add_key ||
@@ -656,37 +720,15 @@ int cfg80211_wext_siwencodeext(struct ne
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
 
-struct giwencode_cookie {
-	size_t buflen;
-	char *keybuf;
-};
-
-static void giwencode_get_key_cb(void *cookie, struct key_params *params)
-{
-	struct giwencode_cookie *data = cookie;
-
-	if (!params->key) {
-		data->buflen = 0;
-		return;
-	}
-
-	data->buflen = min_t(size_t, data->buflen, params->key_len);
-	memcpy(data->keybuf, params->key, data->buflen);
-}
-
 int cfg80211_wext_giwencode(struct net_device *dev,
 			    struct iw_request_info *info,
 			    struct iw_point *erq, char *keybuf)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-	int idx, err;
-	struct giwencode_cookie data = {
-		.keybuf = keybuf,
-		.buflen = erq->length,
-	};
+	int idx;
 
-	if (!rdev->ops->get_key)
+	if (wdev->iftype != NL80211_IFTYPE_STATION &&
+	    wdev->iftype != NL80211_IFTYPE_ADHOC)
 		return -EOPNOTSUPP;
 
 	idx = erq->flags & IW_ENCODE_INDEX;
@@ -701,21 +743,18 @@ int cfg80211_wext_giwencode(struct net_d
 
 	erq->flags = idx + 1;
 
-	err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
-				 giwencode_get_key_cb);
-	if (!err) {
-		erq->length = data.buflen;
-		erq->flags |= IW_ENCODE_ENABLED;
-		return 0;
-	}
-
-	if (err == -ENOENT) {
+	if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
 		erq->flags |= IW_ENCODE_DISABLED;
 		erq->length = 0;
 		return 0;
 	}
 
-	return err;
+	erq->length = min_t(size_t, erq->length,
+			    wdev->wext.keys->params[idx].key_len);
+	memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
+	erq->flags |= IW_ENCODE_ENABLED;
+
+	return 0;
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
 
--- wireless-testing.orig/include/net/cfg80211.h	2009-07-08 14:11:53.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h	2009-07-08 14:12:35.000000000 +0200
@@ -647,12 +647,17 @@ struct cfg80211_crypto_settings {
  * @auth_type: Authentication type (algorithm)
  * @ie: Extra IEs to add to Authentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_auth_request {
 	struct cfg80211_bss *bss;
 	const u8 *ie;
 	size_t ie_len;
 	enum nl80211_auth_type auth_type;
+	const u8 *key;
+	u8 key_len, key_idx;
 };
 
 /**
@@ -727,6 +732,8 @@ struct cfg80211_disassoc_request {
  * @ie: information element(s) to include in the beacon
  * @ie_len: length of that
  * @beacon_interval: beacon interval to use
+ * @privacy: this is a protected network, keys will be configured
+ *	after joining
  */
 struct cfg80211_ibss_params {
 	u8 *ssid;
@@ -736,6 +743,7 @@ struct cfg80211_ibss_params {
 	u8 ssid_len, ie_len;
 	u16 beacon_interval;
 	bool channel_fixed;
+	bool privacy;
 };
 
 /**
@@ -755,6 +763,9 @@ struct cfg80211_ibss_params {
  * @assoc_ie_len: Length of assoc_ie in octets
  * @privacy: indicates whether privacy-enabled APs should be used
  * @crypto: crypto settings
+ * @key_len: length of WEP key for shared key authentication
+ * @key_idx: index of WEP key for shared key authentication
+ * @key: WEP key for shared key authentication
  */
 struct cfg80211_connect_params {
 	struct ieee80211_channel *channel;
@@ -766,6 +777,8 @@ struct cfg80211_connect_params {
 	size_t ie_len;
 	bool privacy;
 	struct cfg80211_crypto_settings crypto;
+	const u8 *key;
+	u8 key_len, key_idx;
 };
 
 /**
@@ -1223,9 +1236,10 @@ extern void wiphy_unregister(struct wiph
  */
 extern void wiphy_free(struct wiphy *wiphy);
 
-/* internal struct */
+/* internal structs */
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
+struct cfg80211_cached_keys;
 
 #define MAX_AUTH_BSSES		4
 
@@ -1267,6 +1281,7 @@ struct wireless_dev {
 		CFG80211_SME_CONNECTED,
 	} sme_state;
 	struct cfg80211_conn *conn;
+	struct cfg80211_cached_keys *connect_keys;
 
 	struct list_head event_list;
 	spinlock_t event_lock;
@@ -1280,6 +1295,7 @@ struct wireless_dev {
 	struct {
 		struct cfg80211_ibss_params ibss;
 		struct cfg80211_connect_params connect;
+		struct cfg80211_cached_keys *keys;
 		u8 *ie;
 		size_t ie_len;
 		u8 bssid[ETH_ALEN];
--- wireless-testing.orig/net/wireless/core.h	2009-07-08 14:11:53.000000000 +0200
+++ wireless-testing/net/wireless/core.h	2009-07-08 14:12:35.000000000 +0200
@@ -238,6 +238,12 @@ struct cfg80211_event {
 	};
 };
 
+struct cfg80211_cached_keys {
+	struct key_params params[6];
+	u8 data[6][WLAN_MAX_KEY_LEN];
+	int def, defmgmt;
+};
+
 
 /* free object */
 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -256,14 +262,18 @@ void cfg80211_bss_age(struct cfg80211_re
 /* IBSS */
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 struct cfg80211_ibss_params *params);
+			 struct cfg80211_ibss_params *params,
+			 struct cfg80211_cached_keys *connkeys);
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_ibss_params *params);
+		       struct cfg80211_ibss_params *params,
+		       struct cfg80211_cached_keys *connkeys);
 void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, bool nowext);
 void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev);
 
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -272,12 +282,14 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 enum nl80211_auth_type auth_type,
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
-			 const u8 *ie, int ie_len);
+			 const u8 *ie, int ie_len,
+			 const u8 *key, int key_len, int key_idx);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
-		       const u8 *ie, int ie_len);
+		       const u8 *ie, int ie_len,
+		       const u8 *key, int key_len, int key_idx);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev,
 			  struct ieee80211_channel *chan,
@@ -310,10 +322,12 @@ void __cfg80211_connect_result(struct ne
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_connect_params *connect);
+		       struct cfg80211_connect_params *connect,
+		       struct cfg80211_cached_keys *connkeys);
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
 		     struct net_device *dev,
-		     struct cfg80211_connect_params *connect);
+		     struct cfg80211_connect_params *connect,
+		     struct cfg80211_cached_keys *connkeys);
 int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev, u16 reason,
 			  bool wextev);
@@ -323,11 +337,14 @@ int cfg80211_disconnect(struct cfg80211_
 void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
 		       const u8 *req_ie, size_t req_ie_len,
 		       const u8 *resp_ie, size_t resp_ie_len);
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev);
 
 void cfg80211_conn_work(struct work_struct *work);
 
 /* internal helpers */
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+				   struct key_params *params, int key_idx,
 				   const u8 *mac_addr);
 void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 			     size_t ie_len, u16 reason, bool from_ap);
@@ -335,5 +352,6 @@ void cfg80211_sme_scan_done(struct net_d
 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
 void cfg80211_sme_disassoc(struct net_device *dev, int idx);
 void __cfg80211_scan_done(struct work_struct *wk);
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
 
 #endif /* __NET_WIRELESS_CORE_H */
--- wireless-testing.orig/net/wireless/core.c	2009-07-08 14:11:53.000000000 +0200
+++ wireless-testing/net/wireless/core.c	2009-07-08 14:12:35.000000000 +0200
@@ -666,14 +666,10 @@ static int cfg80211_netdev_notifier_call
 		wdev_lock(wdev);
 		switch (wdev->iftype) {
 		case NL80211_IFTYPE_ADHOC:
-			if (wdev->wext.ibss.ssid_len)
-				__cfg80211_join_ibss(rdev, dev,
-						     &wdev->wext.ibss);
+			cfg80211_ibss_wext_join(rdev, wdev);
 			break;
 		case NL80211_IFTYPE_STATION:
-			if (wdev->wext.connect.ssid_len)
-				__cfg80211_connect(rdev, dev,
-						   &wdev->wext.connect);
+			cfg80211_mgd_wext_connect(rdev, wdev);
 			break;
 		default:
 			break;
@@ -690,6 +686,9 @@ static int cfg80211_netdev_notifier_call
 		}
 		mutex_unlock(&rdev->devlist_mtx);
 		mutex_destroy(&wdev->mtx);
+#ifdef CONFIG_WIRELESS_EXT
+		kfree(wdev->wext.keys);
+#endif
 		break;
 	case NETDEV_PRE_UP:
 		if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
--- wireless-testing.orig/net/wireless/sme.c	2009-07-08 14:11:57.000000000 +0200
+++ wireless-testing/net/wireless/sme.c	2009-07-08 14:12:35.000000000 +0200
@@ -125,7 +125,9 @@ static int cfg80211_conn_do_work(struct 
 					    params->channel, params->auth_type,
 					    params->bssid,
 					    params->ssid, params->ssid_len,
-					    NULL, 0);
+					    NULL, 0,
+					    params->key, params->key_len,
+					    params->key_idx);
 	case CFG80211_CONN_ASSOCIATE_NEXT:
 		BUG_ON(!rdev->ops->assoc);
 		wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -279,8 +281,12 @@ void cfg80211_sme_rx_auth(struct net_dev
 		/* select automatically between only open, shared, leap */
 		switch (wdev->conn->params.auth_type) {
 		case NL80211_AUTHTYPE_OPEN_SYSTEM:
-			wdev->conn->params.auth_type =
-				NL80211_AUTHTYPE_SHARED_KEY;
+			if (wdev->connect_keys)
+				wdev->conn->params.auth_type =
+					NL80211_AUTHTYPE_SHARED_KEY;
+			else
+				wdev->conn->params.auth_type =
+					NL80211_AUTHTYPE_NETWORK_EAP;
 			break;
 		case NL80211_AUTHTYPE_SHARED_KEY:
 			wdev->conn->params.auth_type =
@@ -353,10 +359,8 @@ void __cfg80211_connect_result(struct ne
 #endif
 
 	if (status == WLAN_STATUS_SUCCESS &&
-	    wdev->sme_state == CFG80211_SME_IDLE) {
-		wdev->sme_state = CFG80211_SME_CONNECTED;
-		return;
-	}
+	    wdev->sme_state == CFG80211_SME_IDLE)
+		goto success;
 
 	if (wdev->sme_state != CFG80211_SME_CONNECTING)
 		return;
@@ -370,24 +374,29 @@ void __cfg80211_connect_result(struct ne
 	if (wdev->conn)
 		wdev->conn->state = CFG80211_CONN_IDLE;
 
-	if (status == WLAN_STATUS_SUCCESS) {
-		bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-				       wdev->ssid, wdev->ssid_len,
-				       WLAN_CAPABILITY_ESS,
-				       WLAN_CAPABILITY_ESS);
-
-		if (WARN_ON(!bss))
-			return;
-
-		cfg80211_hold_bss(bss_from_pub(bss));
-		wdev->current_bss = bss_from_pub(bss);
-
-		wdev->sme_state = CFG80211_SME_CONNECTED;
-	} else {
+	if (status != WLAN_STATUS_SUCCESS) {
 		wdev->sme_state = CFG80211_SME_IDLE;
 		kfree(wdev->conn);
 		wdev->conn = NULL;
+		kfree(wdev->connect_keys);
+		wdev->connect_keys = NULL;
+		return;
 	}
+
+	bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+			       wdev->ssid, wdev->ssid_len,
+			       WLAN_CAPABILITY_ESS,
+			       WLAN_CAPABILITY_ESS);
+
+	if (WARN_ON(!bss))
+		return;
+
+	cfg80211_hold_bss(bss_from_pub(bss));
+	wdev->current_bss = bss_from_pub(bss);
+
+ success:
+	wdev->sme_state = CFG80211_SME_CONNECTED;
+	cfg80211_upload_connect_keys(wdev);
 }
 
 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -516,6 +525,8 @@ void __cfg80211_disconnected(struct net_
 			     size_t ie_len, u16 reason, bool from_ap)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	int i;
 #ifdef CONFIG_WIRELESS_EXT
 	union iwreq_data wrqu;
 #endif
@@ -543,8 +554,15 @@ void __cfg80211_disconnected(struct net_
 		wdev->conn = NULL;
 	}
 
-	nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev,
-				  reason, ie, ie_len, from_ap);
+	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
+
+	/*
+	 * Delete all the keys ... pairwise keys can't really
+	 * exist any more anyway, but default keys might.
+	 */
+	if (rdev->ops->del_key)
+		for (i = 0; i < 6; i++)
+			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
 
 #ifdef CONFIG_WIRELESS_EXT
 	memset(&wrqu, 0, sizeof(wrqu));
@@ -580,7 +598,8 @@ EXPORT_SYMBOL(cfg80211_disconnected);
 
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_connect_params *connect)
+		       struct cfg80211_connect_params *connect,
+		       struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
@@ -590,6 +609,24 @@ int __cfg80211_connect(struct cfg80211_r
 	if (wdev->sme_state != CFG80211_SME_IDLE)
 		return -EALREADY;
 
+	if (WARN_ON(wdev->connect_keys)) {
+		kfree(wdev->connect_keys);
+		wdev->connect_keys = NULL;
+	}
+
+	if (connkeys && connkeys->def >= 0) {
+		int idx;
+
+		idx = connkeys->def;
+		/* If given a WEP key we may need it for shared key auth */
+		if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
+		    connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
+			connect->key_idx = idx;
+			connect->key = connkeys->params[idx].key;
+			connect->key_len = connkeys->params[idx].key_len;
+		}
+	}
+
 	if (!rdev->ops->connect) {
 		if (!rdev->ops->auth || !rdev->ops->assoc)
 			return -EOPNOTSUPP;
@@ -640,6 +677,7 @@ int __cfg80211_connect(struct cfg80211_r
 			cfg80211_get_conn_bss(wdev);
 
 		wdev->sme_state = CFG80211_SME_CONNECTING;
+		wdev->connect_keys = connkeys;
 
 		/* we're good if we have both BSSID and channel */
 		if (wdev->conn->params.bssid && wdev->conn->params.channel) {
@@ -662,13 +700,16 @@ int __cfg80211_connect(struct cfg80211_r
 			kfree(wdev->conn);
 			wdev->conn = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
+			wdev->connect_keys = NULL;
 		}
 
 		return err;
 	} else {
 		wdev->sme_state = CFG80211_SME_CONNECTING;
+		wdev->connect_keys = connkeys;
 		err = rdev->ops->connect(&rdev->wiphy, dev, connect);
 		if (err) {
+			wdev->connect_keys = NULL;
 			wdev->sme_state = CFG80211_SME_IDLE;
 			return err;
 		}
@@ -682,12 +723,13 @@ int __cfg80211_connect(struct cfg80211_r
 
 int cfg80211_connect(struct cfg80211_registered_device *rdev,
 		     struct net_device *dev,
-		     struct cfg80211_connect_params *connect)
+		     struct cfg80211_connect_params *connect,
+		     struct cfg80211_cached_keys *connkeys)
 {
 	int err;
 
 	wdev_lock(dev->ieee80211_ptr);
-	err = __cfg80211_connect(rdev, dev, connect);
+	err = __cfg80211_connect(rdev, dev, connect, connkeys);
 	wdev_unlock(dev->ieee80211_ptr);
 
 	return err;
@@ -704,6 +746,9 @@ int __cfg80211_disconnect(struct cfg8021
 	if (wdev->sme_state == CFG80211_SME_IDLE)
 		return -EINVAL;
 
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+
 	if (!rdev->ops->disconnect) {
 		if (!rdev->ops->deauth)
 			return -EOPNOTSUPP;
--- wireless-testing.orig/net/wireless/wext-sme.c	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/wireless/wext-sme.c	2009-07-08 14:12:35.000000000 +0200
@@ -10,10 +10,11 @@
 #include <net/cfg80211.h>
 #include "nl80211.h"
 
-static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
-				     struct wireless_dev *wdev)
+int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
+			      struct wireless_dev *wdev)
 {
-	int err;
+	struct cfg80211_cached_keys *ck = NULL;
+	int err, i;
 
 	ASSERT_RDEV_LOCK(rdev);
 	ASSERT_WDEV_LOCK(wdev);
@@ -25,10 +26,25 @@ static int cfg80211_mgd_wext_connect(str
 	wdev->wext.connect.ie_len = wdev->wext.ie_len;
 	wdev->wext.connect.privacy = wdev->wext.default_key != -1;
 
-	err = 0;
-	if (wdev->wext.connect.ssid_len != 0)
-		err = __cfg80211_connect(rdev, wdev->netdev,
-					 &wdev->wext.connect);
+	if (wdev->wext.keys) {
+		wdev->wext.keys->def = wdev->wext.default_key;
+		wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
+	}
+
+	if (!wdev->wext.connect.ssid_len)
+		return 0;
+
+	if (wdev->wext.keys) {
+		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+		if (!ck)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			ck->params[i].key = ck->data[i];
+	}
+	err = __cfg80211_connect(rdev, wdev->netdev,
+				 &wdev->wext.connect, ck);
+	if (err)
+		kfree(ck);
 
 	return err;
 }
--- wireless-testing.orig/net/wireless/mlme.c	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/wireless/mlme.c	2009-07-08 14:12:35.000000000 +0200
@@ -328,7 +328,8 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 enum nl80211_auth_type auth_type,
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
-			 const u8 *ie, int ie_len)
+			 const u8 *ie, int ie_len,
+			 const u8 *key, int key_len, int key_idx)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_auth_request req;
@@ -337,6 +338,10 @@ int __cfg80211_mlme_auth(struct cfg80211
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+		if (!key || !key_len || key_idx < 0 || key_idx > 4)
+			return -EINVAL;
+
 	if (wdev->current_bss &&
 	    memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
 		return -EALREADY;
@@ -359,6 +364,9 @@ int __cfg80211_mlme_auth(struct cfg80211
 	req.auth_type = auth_type;
 	req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
 				   WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+	req.key = key;
+	req.key_len = key_len;
+	req.key_idx = key_idx;
 	if (!req.bss)
 		return -ENOENT;
 
@@ -396,13 +404,15 @@ int cfg80211_mlme_auth(struct cfg80211_r
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
-		       const u8 *ie, int ie_len)
+		       const u8 *ie, int ie_len,
+		       const u8 *key, int key_len, int key_idx)
 {
 	int err;
 
 	wdev_lock(dev->ieee80211_ptr);
 	err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
-				   ssid, ssid_len, ie, ie_len);
+				   ssid, ssid_len, ie, ie_len,
+				   key, key_len, key_idx);
 	wdev_unlock(dev->ieee80211_ptr);
 
 	return err;
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-07-08 14:12:35.000000000 +0200
@@ -247,6 +247,9 @@ struct ieee80211_mgd_work {
 
 	int tries;
 
+	u8 key[WLAN_KEY_LEN_WEP104];
+	u8 key_len, key_idx;
+
 	/* must be last */
 	u8 ie[0]; /* for auth or assoc frame, not probe */
 };
@@ -321,6 +324,7 @@ struct ieee80211_if_ibss {
 
 	bool fixed_bssid;
 	bool fixed_channel;
+	bool privacy;
 
 	u8 bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -1090,8 +1094,8 @@ int ieee80211_add_pending_skbs(struct ie
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
-			 u8 *extra, size_t extra_len,
-			 const u8 *bssid, int encrypt);
+			 u8 *extra, size_t extra_len, const u8 *bssid,
+			 const u8 *key, u8 key_len, u8 key_idx);
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
 			     const u8 *ie, size_t ie_len);
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
--- wireless-testing.orig/net/mac80211/mlme.c	2009-07-08 14:11:48.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2009-07-08 14:12:35.000000000 +0200
@@ -954,7 +954,7 @@ ieee80211_authenticate(struct ieee80211_
 	       sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
 
 	ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
-			    wk->bss->cbss.bssid, 0);
+			    wk->bss->cbss.bssid, NULL, 0, 0);
 	wk->auth_transaction = 2;
 
 	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -1176,7 +1176,8 @@ static void ieee80211_auth_challenge(str
 		return;
 	ieee80211_send_auth(sdata, 3, wk->auth_alg,
 			    elems.challenge - 2, elems.challenge_len + 2,
-			    wk->bss->cbss.bssid, 1);
+			    wk->bss->cbss.bssid,
+			    wk->key, wk->key_len, wk->key_idx);
 	wk->auth_transaction = 4;
 }
 
@@ -2175,6 +2176,12 @@ int ieee80211_mgd_auth(struct ieee80211_
 		wk->ie_len = req->ie_len;
 	}
 
+	if (req->key && req->key_len) {
+		wk->key_len = req->key_len;
+		wk->key_idx = req->key_idx;
+		memcpy(wk->key, req->key, req->key_len);
+	}
+
 	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
 	memcpy(wk->ssid, ssid + 2, ssid[1]);
 	wk->ssid_len = ssid[1];
--- wireless-testing.orig/net/mac80211/ibss.c	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/mac80211/ibss.c	2009-07-08 14:12:35.000000000 +0200
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(
 	 */
 	if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
 		ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
-				    sdata->u.ibss.bssid, 0);
+				    sdata->u.ibss.bssid, NULL, 0, 0);
 }
 
 static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(st
 
 	capability = WLAN_CAPABILITY_IBSS;
 
-	if (sdata->default_key)
+	if (ifibss->privacy)
 		capability |= WLAN_CAPABILITY_PRIVACY;
 	else
 		sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(stru
 		return;
 
 	capability = WLAN_CAPABILITY_IBSS;
-	if (sdata->default_key)
+	if (ifibss->privacy)
 		capability |= WLAN_CAPABILITY_PRIVACY;
-
 	if (ifibss->fixed_bssid)
 		bssid = ifibss->bssid;
 	if (ifibss->fixed_channel)
@@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211
 	} else
 		sdata->u.ibss.fixed_bssid = false;
 
+	sdata->u.ibss.privacy = params->privacy;
+
 	sdata->vif.bss_conf.beacon_int = params->beacon_interval;
 
 	sdata->u.ibss.channel = params->channel;
--- wireless-testing.orig/net/mac80211/util.c	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/mac80211/util.c	2009-07-08 14:12:35.000000000 +0200
@@ -31,6 +31,7 @@
 #include "mesh.h"
 #include "wme.h"
 #include "led.h"
+#include "wep.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
 void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -778,12 +779,13 @@ u32 ieee80211_mandatory_rates(struct iee
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
-			 u8 *extra, size_t extra_len,
-			 const u8 *bssid, int encrypt)
+			 u8 *extra, size_t extra_len, const u8 *bssid,
+			 const u8 *key, u8 key_len, u8 key_idx)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
+	int err;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    sizeof(*mgmt) + 6 + extra_len);
@@ -798,8 +800,6 @@ void ieee80211_send_auth(struct ieee8021
 	memset(mgmt, 0, 24 + 6);
 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 					  IEEE80211_STYPE_AUTH);
-	if (encrypt)
-		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 	memcpy(mgmt->da, bssid, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -809,7 +809,13 @@ void ieee80211_send_auth(struct ieee8021
 	if (extra)
 		memcpy(skb_put(skb, extra_len), extra, extra_len);
 
-	ieee80211_tx_skb(sdata, skb, encrypt);
+	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
+		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
+		WARN_ON(err);
+	}
+
+	ieee80211_tx_skb(sdata, skb, 0);
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
--- wireless-testing.orig/net/mac80211/wep.c	2009-07-08 14:11:48.000000000 +0200
+++ wireless-testing/net/mac80211/wep.c	2009-07-08 14:12:35.000000000 +0200
@@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct c
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-static int ieee80211_wep_encrypt(struct ieee80211_local *local,
-				 struct sk_buff *skb,
-				 const u8 *key, int keylen, int keyidx)
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  const u8 *key, int keylen, int keyidx)
 {
 	u8 *iv;
 	size_t len;
--- wireless-testing.orig/net/mac80211/wep.h	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/mac80211/wep.h	2009-07-08 14:12:35.000000000 +0200
@@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_
 void ieee80211_wep_free(struct ieee80211_local *local);
 void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 				size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local,
+			  struct sk_buff *skb,
+			  const u8 *key, int keylen, int keyidx);
 int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
 			       size_t klen, u8 *data, size_t data_len);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
--- wireless-testing.orig/net/wireless/ibss.c	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/wireless/ibss.c	2009-07-08 14:12:35.000000000 +0200
@@ -39,6 +39,8 @@ void __cfg80211_ibss_joined(struct net_d
 	cfg80211_hold_bss(bss_from_pub(bss));
 	wdev->current_bss = bss_from_pub(bss);
 
+	cfg80211_upload_connect_keys(wdev);
+
 	nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
 				GFP_KERNEL);
 #ifdef CONFIG_WIRELESS_EXT
@@ -71,7 +73,8 @@ EXPORT_SYMBOL(cfg80211_ibss_joined);
 
 int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
-			 struct cfg80211_ibss_params *params)
+			 struct cfg80211_ibss_params *params,
+			 struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
@@ -81,13 +84,18 @@ int __cfg80211_join_ibss(struct cfg80211
 	if (wdev->ssid_len)
 		return -EALREADY;
 
+	if (WARN_ON(wdev->connect_keys))
+		kfree(wdev->connect_keys);
+	wdev->connect_keys = connkeys;
+
 #ifdef CONFIG_WIRELESS_EXT
 	wdev->wext.ibss.channel = params->channel;
 #endif
 	err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
-
-	if (err)
+	if (err) {
+		wdev->connect_keys = NULL;
 		return err;
+	}
 
 	memcpy(wdev->ssid, params->ssid, params->ssid_len);
 	wdev->ssid_len = params->ssid_len;
@@ -97,13 +105,14 @@ int __cfg80211_join_ibss(struct cfg80211
 
 int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev,
-		       struct cfg80211_ibss_params *params)
+		       struct cfg80211_ibss_params *params,
+		       struct cfg80211_cached_keys *connkeys)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	int err;
 
 	wdev_lock(wdev);
-	err = __cfg80211_join_ibss(rdev, dev, params);
+	err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
 	wdev_unlock(wdev);
 
 	return err;
@@ -112,9 +121,22 @@ int cfg80211_join_ibss(struct cfg80211_r
 static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	int i;
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+
+	/*
+	 * Delete all the keys ... pairwise keys can't really
+	 * exist any more anyway, but default keys might.
+	 */
+	if (rdev->ops->del_key)
+		for (i = 0; i < 6; i++)
+			rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
+
 	if (wdev->current_bss) {
 		cfg80211_unhold_bss(wdev->current_bss);
 		cfg80211_put_bss(&wdev->current_bss->pub);
@@ -172,11 +194,14 @@ int cfg80211_leave_ibss(struct cfg80211_
 }
 
 #ifdef CONFIG_WIRELESS_EXT
-static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
-				   struct wireless_dev *wdev)
+int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
+			    struct wireless_dev *wdev)
 {
+	struct cfg80211_cached_keys *ck = NULL;
 	enum ieee80211_band band;
-	int i;
+	int i, err;
+
+	ASSERT_WDEV_LOCK(wdev);
 
 	if (!wdev->wext.ibss.beacon_interval)
 		wdev->wext.ibss.beacon_interval = 100;
@@ -216,8 +241,24 @@ static int cfg80211_ibss_wext_join(struc
 	if (!netif_running(wdev->netdev))
 		return 0;
 
-	return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
-				  wdev->netdev, &wdev->wext.ibss);
+	if (wdev->wext.keys)
+		wdev->wext.keys->def = wdev->wext.default_key;
+
+	wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
+
+	if (wdev->wext.keys) {
+		ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
+		if (!ck)
+			return -ENOMEM;
+		for (i = 0; i < 6; i++)
+			ck->params[i].key = ck->data[i];
+	}
+	err = __cfg80211_join_ibss(rdev, wdev->netdev,
+				   &wdev->wext.ibss, ck);
+	if (err)
+		kfree(ck);
+
+	return err;
 }
 
 int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -265,7 +306,11 @@ int cfg80211_ibss_wext_siwfreq(struct ne
 		wdev->wext.ibss.channel_fixed = false;
 	}
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
@@ -333,7 +378,11 @@ int cfg80211_ibss_wext_siwessid(struct n
 	memcpy(wdev->wext.ibss.ssid, ssid, len);
 	wdev->wext.ibss.ssid_len = len;
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
@@ -414,7 +463,11 @@ int cfg80211_ibss_wext_siwap(struct net_
 	} else
 		wdev->wext.ibss.bssid = NULL;
 
-	return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_lock(wdev);
+	err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
+	wdev_unlock(wdev);
+
+	return err;
 }
 /* temporary symbol - mark GPL - in the future the handler won't be */
 EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
--- wireless-testing.orig/net/wireless/util.c	2009-07-08 14:11:49.000000000 +0200
+++ wireless-testing/net/wireless/util.c	2009-07-08 14:12:35.000000000 +0200
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct 
 			set_mandatory_flags_band(wiphy->bands[band], band);
 }
 
-int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+				   struct key_params *params, int key_idx,
 				   const u8 *mac_addr)
 {
+	int i;
+
 	if (key_idx > 5)
 		return -EINVAL;
 
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struc
 		}
 	}
 
+	for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
+		if (params->cipher == rdev->wiphy.cipher_suites[i])
+			break;
+	if (i == rdev->wiphy.n_cipher_suites)
+		return -EINVAL;
+
 	return 0;
 }
 
@@ -523,3 +532,33 @@ const u8 *ieee80211_bss_get_ie(struct cf
 	return NULL;
 }
 EXPORT_SYMBOL(ieee80211_bss_get_ie);
+
+void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+	struct net_device *dev = wdev->netdev;
+	int i;
+
+	if (!wdev->connect_keys)
+		return;
+
+	for (i = 0; i < 6; i++) {
+		if (!wdev->connect_keys->params[i].cipher)
+			continue;
+		if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
+					&wdev->connect_keys->params[i]))
+			printk(KERN_ERR "%s: failed to set key %d\n",
+				dev->name, i);
+		if (wdev->connect_keys->def == i)
+			if (rdev->ops->set_default_key(wdev->wiphy, dev, i))
+				printk(KERN_ERR "%s: failed to set defkey %d\n",
+					dev->name, i);
+		if (wdev->connect_keys->defmgmt == i)
+			if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
+				printk(KERN_ERR "%s: failed to set mgtdef %d\n",
+					dev->name, i);
+	}
+
+	kfree(wdev->connect_keys);
+	wdev->connect_keys = NULL;
+}



^ permalink raw reply

* Re: mac80211 and broadcast frames
From: John W. Linville @ 2009-07-08 12:57 UTC (permalink / raw)
  To: Valentin Manea; +Cc: Luis R. Rodriguez, David Ross, linux-wireless
In-Reply-To: <4A544B15.8030106@mrs.ro>

On Wed, Jul 08, 2009 at 10:30:29AM +0300, Valentin Manea wrote:
>
>
> On 07/07/2009 07:15 PM, Luis R. Rodriguez wrote:
>> On Tue, Jul 7, 2009 at 7:48 AM, John W. Linville<linville@tuxdriver.com>  wrote:
>>> On Tue, Jul 07, 2009 at 09:10:52PM +1000, David Ross wrote:
>>>> Actually it is required to be a mutual BASIC rate (not extended rates) -
>>>> not necessarily the "lowest possible" - David.
>>> True, but FWIW I think all of our rate scaling algorithms choose the
>>> lowest rate.
>>
>> And then iwlwifi and ath9k have their own rate control algo, and at
>> least ath9k uses the lowest valid rate IIRC.
>>
>>    Luis
>
>
>   I've found the code in ath9k and you are right, it always chooses the  
> lowest rate.
>   So, basically to transmit multicast frames at a better bitrate I have  
> to hack the rate control algorithm, right?

Yes.  Feel free to suggest patches for all of the available (i.e. both
generic and device-dependent) algorithms as well.

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.
			¡Viva Honduras Libre!

^ permalink raw reply

* [PATCH] p54: Fix for Bugzilla #13725 - tx refused but queue active
From: Larry Finger @ 2009-07-08 13:33 UTC (permalink / raw)
  To: John W Linville; +Cc: chunkeey, linux-kernel, linux-wireless, rjw, davem

In the mainline kernel, p54usb will fail because the TX queue length can
become < 0. This problem has been reported as Bugzilla #13725. The failure
is expressed by the following message in the logs:

WARNING: at net/mac80211/tx.c:1325 ieee80211_tx+0x23c/0x298 [mac80211]()
Hardware name: HP Pavilion dv2700 Notebook PC
tx refused but queue active

This problem has been recently observed in the wireless-testing tree, where
a full solution is being tested. That fix is too invasive for 2.6.31-rcX,
but the simple change supplied here will prevent the failure.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---

John,

This patch should be sent to mainline. As stated above, it should not be
applied to wireless-testing.

Thanks,

Larry
---

Index: linux-2.6/drivers/net/wireless/p54/p54common.c
===================================================================
--- linux-2.6.orig/drivers/net/wireless/p54/p54common.c
+++ linux-2.6/drivers/net/wireless/p54/p54common.c
@@ -912,13 +912,14 @@ static void p54_rx_frame_sent(struct iee
 		}
 
 		__skb_unlink(entry, &priv->tx_queue);
-		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
 		frame_len = entry->len;
 		entry_hdr = (struct p54_hdr *) entry->data;
 		entry_data = (struct p54_tx_data *) entry_hdr->data;
-		priv->tx_stats[entry_data->hw_queue].len--;
+		if (priv->tx_stats[entry_data->hw_queue].len)
+			priv->tx_stats[entry_data->hw_queue].len--;
 		priv->stats.dot11ACKFailureCount += payload->tries - 1;
+		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
 		/*
 		 * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are

---

^ permalink raw reply

* [PATCH 41/44] includecheck fix: include/linux, rfkill.h
From: Jaswinder Singh Rajput @ 2009-07-08 15:55 UTC (permalink / raw)
  To: johannes, linux-wireless, Andrew Morton, Sam Ravnborg, LKML
In-Reply-To: <1247063308.4382.12.camel@ht.satnam>


fix the following 'make includecheck' warning:

  include/linux/rfkill.h: linux/types.h is included more than once.

Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com>
---
 include/linux/rfkill.h |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index e73e242..2ce2983 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -99,7 +99,6 @@ enum rfkill_user_states {
 #undef RFKILL_STATE_UNBLOCKED
 #undef RFKILL_STATE_HARD_BLOCKED
 
-#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-- 
1.6.0.6




^ permalink raw reply related

* Re: WANTED: someone who knows what exactly that ssb thingy is intended/used for
From: Michael Buesch @ 2009-07-08 16:30 UTC (permalink / raw)
  To: Stefan Bader; +Cc: Ubuntu Kernel Team, linux-wireless
In-Reply-To: <4A548A3C.20800@canonical.com>

On Wednesday 08 July 2009 13:59:56 Stefan Bader wrote:
> Hi all,
> 
> I somehow wondered why on a Dell Inspiron 1521 the wireless is not cooperating 
> by default. The problem turns out to be the ssb module, which is not only a 
> dependency to the b44 driver (for the wired network card) but also likes to 
> handle the Broadcom 4328 device.

ssb is an internal bus on your b43 and b44 cards. So your setup looks like this:

pci-bus |
        |
        |>---ssb-
        |       |>-wireless core (b43 drives this)
        |       |>-management cores...
        |
        |>---ssb-
                |>-etheret core (b44 drives this)
                |>-management cores...

> In the end wireless works well when removing b44, ssb and wl. Then loading wl 
> first, followed by b44 (which pulls in ssb).

b43/b44/ssb are not compatible with wl. Uninstall wl.



-- 
Greetings, Michael.

^ permalink raw reply

* Re: [PATCH] Assign next hop address to pending mesh frames once the path is resolved.
From: Javier Cardona @ 2009-07-08 17:02 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless
In-Reply-To: <1247049613.4755.65.camel@johannes.local>

Johannes,

On Wed, Jul 8, 2009 at 3:40 AM, Johannes Berg<johannes@sipsolutions.net> wrote:
> On Tue, 2009-07-07 at 22:53 -0700, Javier Cardona wrote:
>> Regression.  Frames transmitted when a mesh path was wating to be resolved were
>> being transmitted with an invalid Receiver Address.
>
>> -     rcu_assign_pointer(mpath->next_hop, sta);
>> +     struct sk_buff *skb, *skb_first = NULL;
>> +     struct ieee80211_hdr *hdr;
>> +
>> +     rcu_read_lock();
>> +     mpath->next_hop = sta;
>> +
>> +     while ((skb = skb_dequeue(&mpath->frame_queue)) != skb_first) {
>> +             if (!skb_first)
>> +                     skb_first = skb;
>> +             hdr = (struct ieee80211_hdr *) skb->data;
>> +             memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
>> +             skb_queue_tail(&mpath->frame_queue, skb);
>> +     }
>> +     if (skb_first)
>> +             skb_queue_tail(&mpath->frame_queue, skb_first);
>> +
>> +     rcu_read_unlock();
>
> Since skb queues have a locks, why use rcu too?

The some mpath members are rcu protected.  I thought I had to extend
the rcu section to cover both mpath->next_hop and mpath->frame_queue.
But now I see that the latter does not need protection, so I'll revert
that to just rcu_assign_pointer(mpath->next_hop, sta);

> Also I think you should probably use a different pattern -- this looks
> prone to breakage, maybe something like
>
>        sk_buff_head tmpq;
>        unsigned long flags;
>
>        __skb_queue_head_init(&tmpq);
>
>        spin_lock_irqsave(&frame_queue->lock);
>
>        while (skb = __skb_dequeue(&frame_queue)) {
>                hdr = (struct ieee80211_hdr *) skb->data;
>                memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
>                __skb_queue_tail(&tmpq, skb);
>        }
>
>        skb_queue_splice(&tmpq, frame_queue);
>        spin_unlock_irqrestore(&frame_queue->lock);

Oh, nice, cleaner and less locking. v2 will follow shortly.

Thanks!

Javier

-- 
Javier Cardona
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply

* Re: mac80211 and broadcast frames
From: Luis R. Rodriguez @ 2009-07-08 17:10 UTC (permalink / raw)
  To: John W. Linville
  Cc: Valentin Manea, David Ross, linux-wireless, Jouni.Malinen
In-Reply-To: <20090708125727.GC4253@tuxdriver.com>

On Wed, Jul 8, 2009 at 5:57 AM, John W. Linville<linville@tuxdriver.com> wrote:
> On Wed, Jul 08, 2009 at 10:30:29AM +0300, Valentin Manea wrote:
>>
>>
>> On 07/07/2009 07:15 PM, Luis R. Rodriguez wrote:
>>> On Tue, Jul 7, 2009 at 7:48 AM, John W. Linville<linville@tuxdriver.com>  wrote:
>>>> On Tue, Jul 07, 2009 at 09:10:52PM +1000, David Ross wrote:
>>>>> Actually it is required to be a mutual BASIC rate (not extended rates) -
>>>>> not necessarily the "lowest possible" - David.
>>>> True, but FWIW I think all of our rate scaling algorithms choose the
>>>> lowest rate.
>>>
>>> And then iwlwifi and ath9k have their own rate control algo, and at
>>> least ath9k uses the lowest valid rate IIRC.
>>>
>>>    Luis
>>
>>
>>   I've found the code in ath9k and you are right, it always chooses the
>> lowest rate.
>>   So, basically to transmit multicast frames at a better bitrate I have
>> to hack the rate control algorithm, right?
>
> Yes.  Feel free to suggest patches for all of the available (i.e. both
> generic and device-dependent) algorithms as well.

BTW all this code is very generic between all drivers right now. The
rate control patches I sent a while back generalize all this and add
*one helper* routine which is used by all drivers for figuring the
rate for broadcasts. Once those patches are applied you can then just
focus on improving that one helper and then *every* driver will
benefit from your work.

The reason for this being a common helper instead of just embedded
directly into mac80211 was that in the future some rate control
algorithms may want to user higher rates for broadcast later. If there
is a way to make this generic and still use a higher rate the generic
helper can be extended. If rate control algorithms disagree with that
implementation or want to change it they can simply drop the helper
and implement their own solution.

  Luis

^ permalink raw reply

* Re: Slow wired network when wireless card is also active
From: David Webber @ 2009-07-08 18:19 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <dcc24d260907032143h38165b8as9f18da70b16ed2a@mail.gmail.com>

On Fri, Jul 3, 2009 at 11:43 PM, David Webber <dwebber@illinois.edu> wrote:
>
> I'm trying to use Jaunty on my Centrino laptop as a wireless access
> point / NAT. My cable modem is plugged in to the ethernet port.
> Strangely, when I enable the wireless card (via hostapd or simply
> 'ifconfig wlan1 192.168.0.1 up'), my WIRED network slows down. On a
> terminal on the laptop, I see transfer speeds drop from over about 200
> K/s to about 40 K/s. As far as I can tell, the problem is not affected
> by iptables rules, ip_forward on/off, or ipv6. Just having the
> wireless card present and active seems to affect the wired interface.
> The problem may have something to do with having hostapd active, but
> I'm not sure.
>
> Aside: I have an intel wireless card built-in but since it can't do
> hostap-mode, I purchased the ath9k cardbus card. The intel card is
> disabled by function-key and is not active on boot. I have recent
> versions of the kernel and hostapd from the subversion repositories
> discussed on linuxwireless.org.
>
> Linux version 2.6.30-custom-wl (root@whitebook) (gcc version 4.3.3
> (Ubuntu 4.3.3-5ubuntu4) ) #1 SMP Thu Jun 18 19:22:02 CDT 2009
>
> 00:00.0 Host bridge: Intel Corporation 82852/82855 GM/GME/PM/GMV
> Processor to I/O Controller (rev 02)
> 00:00.1 System peripheral: Intel Corporation 82852/82855 GM/GME/PM/GMV
> Processor to I/O Controller (rev 02)
> 00:00.3 System peripheral: Intel Corporation 82852/82855 GM/GME/PM/GMV
> Processor to I/O Controller (rev 02)
> 00:02.0 VGA compatible controller: Intel Corporation 82852/855GM
> Integrated Graphics Device (rev 02)
> 00:02.1 Display controller: Intel Corporation 82852/855GM Integrated
> Graphics Device (rev 02)
> 00:1d.0 USB Controller: Intel Corporation 82801DB/DBL/DBM
> (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (rev 03)
> 00:1d.1 USB Controller: Intel Corporation 82801DB/DBL/DBM
> (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (rev 03)
> 00:1d.2 USB Controller: Intel Corporation 82801DB/DBL/DBM
> (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (rev 03)
> 00:1d.7 USB Controller: Intel Corporation 82801DB/DBM (ICH4/ICH4-M)
> USB2 EHCI Controller (rev 03)
> 00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 83)
> 00:1f.0 ISA bridge: Intel Corporation 82801DBM (ICH4-M) LPC Interface
> Bridge (rev 03)
> 00:1f.1 IDE interface: Intel Corporation 82801DBM (ICH4-M) IDE
> Controller (rev 03)
> 00:1f.3 SMBus: Intel Corporation 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M)
> SMBus Controller (rev 03)
> 00:1f.5 Multimedia audio controller: Intel Corporation 82801DB/DBL/DBM
> (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (rev 03)
> 00:1f.6 Modem: Intel Corporation 82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M)
> AC'97 Modem Controller (rev 03)
> 01:01.0 Network controller: Intel Corporation PRO/Wireless 2200BG
> [Calexico2] Network Connection (rev 05)
> 01:02.0 Ethernet controller: Realtek Semiconductor Co., Ltd.
> RTL-8139/8139C/8139C+ (rev 10)
> 01:04.0 CardBus bridge: Texas Instruments PCI1410 PC card Cardbus
> Controller (rev 02)
> 01:05.0 FireWire (IEEE 1394): VIA Technologies, Inc. VT6306 Fire II
> IEEE 1394 OHCI Link Layer Controller (rev 80)
> 02:00.0 Network controller: Atheros Communications Inc. AR5008
> Wireless Network Adapter (rev 01)
>
> Speed test:
> (start with everything active. NAT works, other computers can reach
> the internet through the laptop, but the speed is just slow. For this
> test, no other machines were connected so they're not consuming the
> bandwidth)
> $ wget http://cosmos.cites.uiuc.edu/pub/ubuntu-iso/9.04/ubuntu-9.04-desktop-amd64.iso
> [snip] 47.6K/s eta 4h 56m
> $ sudo ifdown wlan1
> [snip] 44.5K/s eta 5h 54m
> $ sudo ifconfig mon.wlan1 down
> [snip] 245K/s eta 45m 7s
>
> As you can see, I lose about a factor of 5 when the wireless card is active.
>
> I also posted this question to
> https://answers.launchpad.net/ubuntu/+question/76037
>
> Thanks in advance,
> David

I tracked this down to the Realtek ethernet.  When I plugged my cable
modem over USB rather than over ethernet, the speed improved to
normal.  I've seen on other forums a problem with slowness using
reatek ethernet.  Strange that it would only show up when two network
interfaces are active though.

David

^ permalink raw reply

* Re: [PATCH 41/44] includecheck fix: include/linux, rfkill.h
From: Marcel Holtmann @ 2009-07-08 19:32 UTC (permalink / raw)
  To: Jaswinder Singh Rajput
  Cc: johannes, linux-wireless, Andrew Morton, Sam Ravnborg, LKML
In-Reply-To: <1247068554.4382.106.camel@ht.satnam>

Hi Jaswinder,

> fix the following 'make includecheck' warning:
> 
>   include/linux/rfkill.h: linux/types.h is included more than once.
> 
> Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com>
> ---
>  include/linux/rfkill.h |    1 -
>  1 files changed, 0 insertions(+), 1 deletions(-)
> 
> diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
> index e73e242..2ce2983 100644
> --- a/include/linux/rfkill.h
> +++ b/include/linux/rfkill.h
> @@ -99,7 +99,6 @@ enum rfkill_user_states {
>  #undef RFKILL_STATE_UNBLOCKED
>  #undef RFKILL_STATE_HARD_BLOCKED
>  
> -#include <linux/types.h>
>  #include <linux/kernel.h>
>  #include <linux/list.h>
>  #include <linux/mutex.h>

with the #ifdef __KERNEL__ in between it is kinda weird, but patch seems
correct.

Regards

Marcel



^ permalink raw reply

* [PATCH] wireless: fix supported cards for rtl8187
From: Marcin Slusarz @ 2009-07-08 20:03 UTC (permalink / raw)
  To: John W. Linville; +Cc: Linux wireless, Przemyslaw Kulczycki, LKML

Different revisions of WUSB54GC-EU use different chipsets -
v2 uses rtl8187, but v3 uses Ralink RT3070.

Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
Cc: Przemyslaw Kulczycki <azrael@autocom.pl>
Cc: John W. Linville <linville@tuxdriver.com>
Cc: Linux wireless <linux-wireless@vger.kernel.org>
---
 drivers/net/wireless/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5bc00db..7d5902d 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -431,7 +431,7 @@ config RTL8187
 	  ASUS P5B Deluxe
 	  Toshiba Satellite Pro series of laptops
 	  Asus Wireless Link
-	  Linksys WUSB54GC-EU
+	  Linksys WUSB54GC-EU v2
 
 	  Thanks to Realtek for their support!
 
-- 
1.6.3.3



^ permalink raw reply related

* pull request: wireless-2.6 2009-07-08
From: John W. Linville @ 2009-07-08 20:37 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev, linux-kernel

Dave,

Here is a collection of bug fixes, build fixes, and minor hardware
enablement patches intended for 2.6.31.  I don't think there is anything
controversial.

Please let me know if there are problems!

Thanks,

John

---

Individual patches are available here:

	http://www.kernel.org/pub/linux/kernel/people/linville/wireless-2.6/

---

The following changes since commit 0ca1b08eba627b4245efd0f71b55a062bf163777:
  David S. Miller (1):
        Revert "p54: Use SKB list handling helpers instead of by-hand code."

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master

Andrey Yurovsky (1):
      mac80211: fix allocation in mesh_queue_preq

Clyde McPherson (2):
      b43: Add support for 4318E
      ssb: Add support for 4318E

Hin-Tak Leung (1):
      zd1211rw: adding SONY IFU-WLM2 (054c:0257) as a zd1211b device

Jaswinder Singh Rajput (1):
      includecheck fix: include/linux, rfkill.h

Jay Sternberg (1):
      Atheros Kconfig needs to be dependent on WLAN_80211

Jiri Slaby (1):
      Wireless: nl80211, fix lock imbalance

Johannes Berg (4):
      hp-wmi: fix rfkill bug
      cfg80211: fix refcount leak
      mac80211_hwsim: avoid NULL access
      mac80211: fix docbook

Larry Finger (2):
      b43/b43legacy: fix radio LED initialization
      p54: tx refused but queue active

Luciano Coelho (1):
      mac80211: minstrel: avoid accessing negative indices in rix_to_ndx()

Pascal Terjan (1):
      zd1211rw: 07b8:6001 is a ZD1211B

Samuel Ortiz (1):
      iwmc3200wifi: add Kconfig help

Vasanthakumar Thiagarajan (1):
      ath9k: Fix leak in tx descriptor

 Documentation/DocBook/mac80211.tmpl        |    2 --
 drivers/net/wireless/ath/Kconfig           |    1 +
 drivers/net/wireless/ath/ath9k/xmit.c      |    9 ++++++++-
 drivers/net/wireless/b43/b43.h             |    1 +
 drivers/net/wireless/b43/main.c            |    7 +++++--
 drivers/net/wireless/b43/pcmcia.c          |    1 +
 drivers/net/wireless/b43legacy/b43legacy.h |    1 +
 drivers/net/wireless/b43legacy/main.c      |    7 +++++--
 drivers/net/wireless/iwmc3200wifi/Kconfig  |    9 +++++++++
 drivers/net/wireless/mac80211_hwsim.c      |    1 +
 drivers/net/wireless/p54/p54common.c       |    5 +++--
 drivers/net/wireless/zd1211rw/zd_usb.c     |    3 ++-
 drivers/platform/x86/hp-wmi.c              |    2 +-
 drivers/ssb/pcmcia.c                       |    6 ++++--
 include/linux/rfkill.h                     |    1 -
 net/mac80211/mesh_hwmp.c                   |    2 +-
 net/mac80211/rc80211_minstrel.c            |    5 ++++-
 net/wireless/nl80211.c                     |    1 +
 net/wireless/scan.c                        |    1 -
 19 files changed, 48 insertions(+), 17 deletions(-)

diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl
index e369866..f3f37f1 100644
--- a/Documentation/DocBook/mac80211.tmpl
+++ b/Documentation/DocBook/mac80211.tmpl
@@ -184,8 +184,6 @@ usage should require reading the full document.
 !Finclude/net/mac80211.h ieee80211_ctstoself_get
 !Finclude/net/mac80211.h ieee80211_ctstoself_duration
 !Finclude/net/mac80211.h ieee80211_generic_frame_duration
-!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb
-!Finclude/net/mac80211.h ieee80211_hdrlen
 !Finclude/net/mac80211.h ieee80211_wake_queue
 !Finclude/net/mac80211.h ieee80211_stop_queue
 !Finclude/net/mac80211.h ieee80211_wake_queues
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index d26e7b4..eb0337c 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -1,5 +1,6 @@
 config ATH_COMMON
 	tristate "Atheros Wireless Cards"
+	depends on WLAN_80211
 	depends on ATH5K || ATH9K || AR9170_USB
 
 source "drivers/net/wireless/ath/ath5k/Kconfig"
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b61a071..4ccf48e 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -355,7 +355,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 		}
 
 		if (bf_next == NULL) {
-			INIT_LIST_HEAD(&bf_head);
+			/*
+			 * Make sure the last desc is reclaimed if it
+			 * not a holding desc.
+			 */
+			if (!bf_last->bf_stale)
+				list_move_tail(&bf->list, &bf_head);
+			else
+				INIT_LIST_HEAD(&bf_head);
 		} else {
 			ASSERT(!list_empty(bf_q));
 			list_move_tail(&bf->list, &bf_head);
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index f580c28..4044806 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -648,6 +648,7 @@ struct b43_wl {
 	u8 nr_devs;
 
 	bool radiotap_enabled;
+	bool radio_enabled;
 
 	/* The beacon we are currently using (AP or IBSS mode).
 	 * This beacon stuff is protected by the irq_lock. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 6456afe..e71c8d9 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3497,8 +3497,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
 	if (phy->ops->set_rx_antenna)
 		phy->ops->set_rx_antenna(dev, antenna);
 
-	if (!!conf->radio_enabled != phy->radio_on) {
-		if (conf->radio_enabled) {
+	if (wl->radio_enabled != phy->radio_on) {
+		if (wl->radio_enabled) {
 			b43_software_rfkill(dev, false);
 			b43info(dev->wl, "Radio turned on by software\n");
 			if (!dev->radio_hw_enable) {
@@ -4339,6 +4339,7 @@ static int b43_op_start(struct ieee80211_hw *hw)
 	wl->beacon0_uploaded = 0;
 	wl->beacon1_uploaded = 0;
 	wl->beacon_templates_virgin = 1;
+	wl->radio_enabled = 1;
 
 	mutex_lock(&wl->mutex);
 
@@ -4378,6 +4379,7 @@ static void b43_op_stop(struct ieee80211_hw *hw)
 	if (b43_status(dev) >= B43_STAT_STARTED)
 		b43_wireless_core_stop(dev);
 	b43_wireless_core_exit(dev);
+	wl->radio_enabled = 0;
 	mutex_unlock(&wl->mutex);
 
 	cancel_work_sync(&(wl->txpower_adjust_work));
@@ -4560,6 +4562,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 		B43_WARN_ON(1);
 
 	dev->phy.gmode = have_2ghz_phy;
+	dev->phy.radio_on = 1;
 	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
 	b43_wireless_core_reset(dev, tmp);
 
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index 3cfc303..6c3a749 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -35,6 +35,7 @@
 
 static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
 	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
 	PCMCIA_DEVICE_NULL,
 };
 
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 77fda14..038baa8 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -607,6 +607,7 @@ struct b43legacy_wl {
 	u8 nr_devs;
 
 	bool radiotap_enabled;
+	bool radio_enabled;
 
 	/* The beacon we are currently using (AP or IBSS mode).
 	 * This beacon stuff is protected by the irq_lock. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index e5136fb..c4973c1 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2689,8 +2689,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
 	/* Antennas for RX and management frame TX. */
 	b43legacy_mgmtframe_txantenna(dev, antenna_tx);
 
-	if (!!conf->radio_enabled != phy->radio_on) {
-		if (conf->radio_enabled) {
+	if (wl->radio_enabled != phy->radio_on) {
+		if (wl->radio_enabled) {
 			b43legacy_radio_turn_on(dev);
 			b43legacyinfo(dev->wl, "Radio turned on by software\n");
 			if (!dev->radio_hw_enable)
@@ -3441,6 +3441,7 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
 	wl->beacon0_uploaded = 0;
 	wl->beacon1_uploaded = 0;
 	wl->beacon_templates_virgin = 1;
+	wl->radio_enabled = 1;
 
 	mutex_lock(&wl->mutex);
 
@@ -3479,6 +3480,7 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
 	if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
 		b43legacy_wireless_core_stop(dev);
 	b43legacy_wireless_core_exit(dev);
+	wl->radio_enabled = 0;
 	mutex_unlock(&wl->mutex);
 }
 
@@ -3620,6 +3622,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
 		have_bphy = 1;
 
 	dev->phy.gmode = (have_gphy || have_bphy);
+	dev->phy.radio_on = 1;
 	tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
 	b43legacy_wireless_core_reset(dev, tmp);
 
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig
index 1eccb6d..030401d 100644
--- a/drivers/net/wireless/iwmc3200wifi/Kconfig
+++ b/drivers/net/wireless/iwmc3200wifi/Kconfig
@@ -4,6 +4,15 @@ config IWM
 	depends on CFG80211
 	select WIRELESS_EXT
 	select FW_LOADER
+	help
+	  The Intel Wireless Multicomm 3200 hardware is a combo
+	  card with GPS, Bluetooth, WiMax and 802.11 radios. It
+	  runs over SDIO and is typically found on Moorestown
+	  based platform. This driver takes care of the 802.11
+	  part, which is a fullmac one.
+
+	  If you choose to build it as a module, it'll be called
+	  iwmc3200wifi.ko.
 
 config IWM_DEBUG
 	bool "Enable full debugging output in iwmc3200wifi"
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index e789c6e..a111bda 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -418,6 +418,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
 			continue;
 
 		if (!data2->started || !hwsim_ps_rx_ok(data2, skb) ||
+		    !data->channel || !data2->channel ||
 		    data->channel->center_freq != data2->channel->center_freq ||
 		    !(data->group & data2->group))
 			continue;
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 48d81d9..22ca122 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -912,13 +912,14 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 		}
 
 		__skb_unlink(entry, &priv->tx_queue);
-		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
 		frame_len = entry->len;
 		entry_hdr = (struct p54_hdr *) entry->data;
 		entry_data = (struct p54_tx_data *) entry_hdr->data;
-		priv->tx_stats[entry_data->hw_queue].len--;
+		if (priv->tx_stats[entry_data->hw_queue].len)
+			priv->tx_stats[entry_data->hw_queue].len--;
 		priv->stats.dot11ACKFailureCount += payload->tries - 1;
+		spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
 		/*
 		 * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 14a19ba..0e6e446 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -38,7 +38,6 @@ static struct usb_device_id usb_ids[] = {
 	/* ZD1211 */
 	{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
-	{ USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
@@ -61,6 +60,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
+	{ USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -87,6 +87,7 @@ static struct usb_device_id usb_ids[] = {
 	{ USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 4ac2311..ca50856 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -171,7 +171,7 @@ static int hp_wmi_tablet_state(void)
 static int hp_wmi_set_block(void *data, bool blocked)
 {
 	unsigned long b = (unsigned long) data;
-	int query = BIT(b + 8) | ((!!blocked) << b);
+	int query = BIT(b + 8) | ((!blocked) << b);
 
 	return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
 }
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index fbfadba..d288608 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -678,7 +678,8 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 			sprom->board_rev = tuple.TupleData[1];
 			break;
 		case SSB_PCMCIA_CIS_PA:
-			GOTO_ERROR_ON(tuple.TupleDataLen != 9,
+			GOTO_ERROR_ON((tuple.TupleDataLen != 9) &&
+				      (tuple.TupleDataLen != 10),
 				      "pa tpl size");
 			sprom->pa0b0 = tuple.TupleData[1] |
 				 ((u16)tuple.TupleData[2] << 8);
@@ -718,7 +719,8 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 			sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1];
 			break;
 		case SSB_PCMCIA_CIS_BFLAGS:
-			GOTO_ERROR_ON(tuple.TupleDataLen != 3,
+			GOTO_ERROR_ON((tuple.TupleDataLen != 3) &&
+				      (tuple.TupleDataLen != 5),
 				      "bfl tpl size");
 			sprom->boardflags_lo = tuple.TupleData[1] |
 					 ((u16)tuple.TupleData[2] << 8);
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index e73e242..2ce2983 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -99,7 +99,6 @@ enum rfkill_user_states {
 #undef RFKILL_STATE_UNBLOCKED
 #undef RFKILL_STATE_HARD_BLOCKED
 
-#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 003cb47..f49ef28 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -637,7 +637,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct mesh_preq_queue *preq_node;
 
-	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
+	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC);
 	if (!preq_node) {
 		printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n");
 		return;
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index b218b98..37771ab 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -66,7 +66,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
 	for (i = rix; i >= 0; i--)
 		if (mi->r[i].rix == rix)
 			break;
-	WARN_ON(mi->r[i].rix != rix);
+	WARN_ON(i < 0);
 	return i;
 }
 
@@ -181,6 +181,9 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 			break;
 
 		ndx = rix_to_ndx(mi, ar[i].idx);
+		if (ndx < 0)
+			continue;
+
 		mi->r[ndx].attempts += ar[i].count;
 
 		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 241bddd..43bdb13 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -447,6 +447,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
 	rdev = __cfg80211_drv_from_info(info);
 	if (IS_ERR(rdev)) {
+		mutex_unlock(&cfg80211_mutex);
 		result = PTR_ERR(rdev);
 		goto unlock;
 	}
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e95b638..f8e71b3 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -366,7 +366,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 	found = rb_find_bss(dev, res);
 
 	if (found) {
-		kref_get(&found->ref);
 		found->pub.beacon_interval = res->pub.beacon_interval;
 		found->pub.tsf = res->pub.tsf;
 		found->pub.signal = res->pub.signal;
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.
			¡Viva Honduras Libre!

^ permalink raw reply related

* [regression] ath5k: Overrides regulatory domain set for cfg80211
From: Frans Pop @ 2009-07-08 21:40 UTC (permalink / raw)
  To: linux-wireless; +Cc: netdev, Linux Kernel Mailing List

In /etc/modprobe.d I have a file containing:
options cfg80211 ieee80211_regdom=EU

During boot this results in:
<snip>
cfg80211: Using static regulatory domain info
cfg80211: Regulatory domain: EU
	(start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
	(2402000 KHz - 2482000 KHz @ 40000 KHz), (600 mBi, 2000 mBm)
	(5170000 KHz - 5190000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
	(5190000 KHz - 5210000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
	(5210000 KHz - 5230000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
	(5230000 KHz - 5330000 KHz @ 40000 KHz), (600 mBi, 2000 mBm)
	(5490000 KHz - 5710000 KHz @ 40000 KHz), (600 mBi, 3000 mBm)
cfg80211: Calling CRDA for country: EU
</snip>

But with 2.6.31-rc2 I then get (the lines marked with "!" are not there 
with .30):
<snip>
  ath5k 0000:02:00.0: enabling device (0000 -> 0002)
  ath5k 0000:02:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
  ath5k 0000:02:00.0: registered as 'phy0'
! ath: EEPROM regdomain: 0x30
! ath: EEPROM indicates we should expect a direct regpair map
! ath: Country alpha2 being used: AM
! ath: Regpair used: 0x30
  phy0: Selected rate control algorithm 'minstrel'
  ath5k phy0: Atheros AR5213A chip found (MAC: 0x59, PHY: 0x43)
  ath5k phy0: RF2112B 2GHz radio found (0x46)
! cfg80211: Calling CRDA for country: AM
</snip>

So it looks as if ath5k has started to override the regdomain I want.

Cheers,
FJP

^ permalink raw reply

* Re: [PATCH] wireless: fix supported cards for rtl8187
From: Hin-Tak Leung @ 2009-07-08 21:49 UTC (permalink / raw)
  To: Marcin Slusarz
  Cc: John W. Linville, Linux wireless, Przemyslaw Kulczycki, LKML
In-Reply-To: <4A54FB81.30302@gmail.com>

On Wed, Jul 8, 2009 at 9:03 PM, Marcin Slusarz<marcin.slusarz@gmail.com> wrote:
> Different revisions of WUSB54GC-EU use different chipsets -
> v2 uses rtl8187, but v3 uses Ralink RT3070.
>
> Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
> Cc: Przemyslaw Kulczycki <azrael@autocom.pl>
> Cc: John W. Linville <linville@tuxdriver.com>
> Cc: Linux wireless <linux-wireless@vger.kernel.org>
> ---
>  drivers/net/wireless/Kconfig |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
> index 5bc00db..7d5902d 100644
> --- a/drivers/net/wireless/Kconfig
> +++ b/drivers/net/wireless/Kconfig
> @@ -431,7 +431,7 @@ config RTL8187
>          ASUS P5B Deluxe
>          Toshiba Satellite Pro series of laptops
>          Asus Wireless Link
> -         Linksys WUSB54GC-EU
> +         Linksys WUSB54GC-EU v2

Is there a v1, and what does it use?

>
>          Thanks to Realtek for their support!
>
> --
> 1.6.3.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply

* Re: [regression] ath5k: Overrides regulatory domain set for cfg80211
From: Luis R. Rodriguez @ 2009-07-08 22:08 UTC (permalink / raw)
  To: Frans Pop; +Cc: linux-wireless, netdev, Linux Kernel Mailing List
In-Reply-To: <200907082340.07787.elendil@planet.nl>

On Wed, Jul 8, 2009 at 2:40 PM, Frans Pop<elendil@planet.nl> wrote:
> In /etc/modprobe.d I have a file containing:
> options cfg80211 ieee80211_regdom=EU
>
> During boot this results in:
> <snip>
> cfg80211: Using static regulatory domain info
> cfg80211: Regulatory domain: EU
>        (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
>        (2402000 KHz - 2482000 KHz @ 40000 KHz), (600 mBi, 2000 mBm)
>        (5170000 KHz - 5190000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5190000 KHz - 5210000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5210000 KHz - 5230000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5230000 KHz - 5330000 KHz @ 40000 KHz), (600 mBi, 2000 mBm)
>        (5490000 KHz - 5710000 KHz @ 40000 KHz), (600 mBi, 3000 mBm)
> cfg80211: Calling CRDA for country: EU
> </snip>
>
> But with 2.6.31-rc2 I then get (the lines marked with "!" are not there
> with .30):
> <snip>
>  ath5k 0000:02:00.0: enabling device (0000 -> 0002)
>  ath5k 0000:02:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
>  ath5k 0000:02:00.0: registered as 'phy0'
> ! ath: EEPROM regdomain: 0x30
> ! ath: EEPROM indicates we should expect a direct regpair map
> ! ath: Country alpha2 being used: AM
> ! ath: Regpair used: 0x30
>  phy0: Selected rate control algorithm 'minstrel'
>  ath5k phy0: Atheros AR5213A chip found (MAC: 0x59, PHY: 0x43)
>  ath5k phy0: RF2112B 2GHz radio found (0x46)
> ! cfg80211: Calling CRDA for country: AM
> </snip>
>
> So it looks

*looks*

> as if ath5k has started to override the regdomain I want.

It looks as if, but you a few things you should be aware of.

First, its not that anything is being ignored, user input is always
welcomed to help compliance you are just using a wrong ISO-3166
alpha2.

EU is not a country and as such is only left on older kernels with
CONFIG_WIRELESS_OLD_REGULATORY  enabled. So "EU" is deprecated for non
CONFIG_WIRELESS_OLD_REGULATORY based kernels now. For further
information please also read
Documentation/feature-removal-schedule.txt. Please use a valid
ISO-3166 alpha2 country code, I also advise to abandon the usage of
the ieee80211_regdom module parameter which we do eventually intend on
deprecating and if you know anyone using that please suggest the same.

Eventually, as you will read from the feature-removal schedule, we
intend on getting the Linux desktop to provide automatic hints of the
user's location through things like GeoClue. Reason for removing the
module parameter is its not the proper way to pass information to the
kernel, we now have a netlink interface for this exact purpose. Until
the desktop catches up we'll keep the ieee80211_regdom module
parameter, but the proper new way to set your regulatory domain as a
user is through iw [1] which does use netlink. Some distributions
(like Fedora) automatically set your country based on the timezone
information. So in the end you should not have to do this at all as a
user.

Another thing you should note is that if a driver has a regulatory
domain hint then the driver regulatory domain is always trusted, users
can *further* help compliance by selecting their country. What this
means since Atheros drivers do have EEPROM reading for the regulatory
domain that will be used first, thus enabling only channels allowed by
the programmed EEPROM. A user input can then only disable channel, but
never enable new ones. For devices with no regulatory at all the user
can have more of a say as no driver regulatory hint is available but
by default, in the absence of a driver regulatory hint, we world roam.

[1] http://wireless.kernel.org/en/users/Documentation/iw

  Luis

^ permalink raw reply

* Re: [PATCH] wireless: fix supported cards for rtl8187
From: Marcin Slusarz @ 2009-07-08 22:18 UTC (permalink / raw)
  To: Hin-Tak Leung
  Cc: John W. Linville, Linux wireless, Przemyslaw Kulczycki, LKML
In-Reply-To: <3ace41890907081449m3ad6c4fdt55781848eedaec1e@mail.gmail.com>

Hin-Tak Leung wrote:
> On Wed, Jul 8, 2009 at 9:03 PM, Marcin Slusarz<marcin.slusarz@gmail.com> wrote:
>> Different revisions of WUSB54GC-EU use different chipsets -
>> v2 uses rtl8187, but v3 uses Ralink RT3070.
>>
>> Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
>> Cc: Przemyslaw Kulczycki <azrael@autocom.pl>
>> Cc: John W. Linville <linville@tuxdriver.com>
>> Cc: Linux wireless <linux-wireless@vger.kernel.org>
>> ---
>>  drivers/net/wireless/Kconfig |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
>> index 5bc00db..7d5902d 100644
>> --- a/drivers/net/wireless/Kconfig
>> +++ b/drivers/net/wireless/Kconfig
>> @@ -431,7 +431,7 @@ config RTL8187
>>          ASUS P5B Deluxe
>>          Toshiba Satellite Pro series of laptops
>>          Asus Wireless Link
>> -         Linksys WUSB54GC-EU
>> +         Linksys WUSB54GC-EU v2
> 
> Is there a v1, and what does it use?

I don't know.

Marcin


^ permalink raw reply

* Re: [regression] ath5k: Overrides regulatory domain set for cfg80211
From: Frans Pop @ 2009-07-09  1:11 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless, netdev, Linux Kernel Mailing List
In-Reply-To: <43e72e890907081508n6fa5781an1dcbda078efc5379@mail.gmail.com>

Thanks for the quick reply and elaborate explanation Luis.

On Thursday 09 July 2009, Luis R. Rodriguez wrote:
> It looks as if, but you a few things you should be aware of.

I was aware that things are changing in this area, but as I'm running 
Debian stable (Lenny) on this box I don't yet have a "new" userland and 
would like to see things continue to work correctly.
For Debian iw is available in testing/unstable, but not in stable.

It also means that I don't have the CRDA agent running, so IIUC currently 
the 'calls to CRDA' don't actually do anything for me. From that 
perspective I guess you could say nothing actually breaks.

> First, its not that anything is being ignored, user input is always
> welcomed to help compliance you are just using a wrong ISO-3166
> alpha2.
>
> EU is not a country and as such is only left on older kernels with
> CONFIG_WIRELESS_OLD_REGULATORY  enabled. So "EU" is deprecated for non
> CONFIG_WIRELESS_OLD_REGULATORY based kernels now.

I *do* have CONFIG_WIRELESS_OLD_REGULATORY set for exactly the reason that 
I know I don't yet have the new userland.

And if I change the country code to NL, I still get the same problem:
cfg80211: Using static regulatory domain info
cfg80211: Regulatory domain: US
        (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
        (2402000 KHz - 2472000 KHz @ 40000 KHz), (600 mBi, 2700 mBm)
        (5170000 KHz - 5190000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
        (5190000 KHz - 5210000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
        (5210000 KHz - 5230000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
        (5230000 KHz - 5330000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
        (5735000 KHz - 5835000 KHz @ 40000 KHz), (600 mBi, 3000 mBm)
  [Weird, when I specified EU I at least got the EU domain here.]
  [Now I specify NL and it gives me US; how's that an improvement?]
cfg80211: Calling CRDA for country: NL
  [no agent, so this does not actually change anything]
ath5k 0000:02:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
ath5k 0000:02:00.0: registered as 'phy0'
ath: EEPROM regdomain: 0x30
ath: EEPROM indicates we should expect a direct regpair map
ath: Country alpha2 being used: AM
ath: Regpair used: 0x30
phy0: Selected rate control algorithm 'minstrel'
ath5k phy0: Atheros AR5213A chip found (MAC: 0x59, PHY: 0x43)
ath5k phy0: RF2112B 2GHz radio found (0x46)
cfg80211: Calling CRDA for country: AM
  [no agent, so this does not actually change anything]

> For further information please also read
> Documentation/feature-removal-schedule.txt. Please use a valid
> ISO-3166 alpha2 country code, I also advise to abandon the usage of
> the ieee80211_regdom module parameter which we do eventually intend on
> deprecating and if you know anyone using that please suggest the same.

As mentioned above I do not currently have the option of abandoning it.
Please continue to provide full backwards compatibility with "old" 
userland until all major distros have iw and crda in their stable 
releases.

> Eventually, as you will read from the feature-removal schedule, we
> intend on getting the Linux desktop to provide automatic hints of the
> user's location through things like GeoClue. Reason for removing the
> module parameter is its not the proper way to pass information to the
> kernel, we now have a netlink interface for this exact purpose. Until
> the desktop catches up we'll keep the ieee80211_regdom module
> parameter, but the proper new way to set your regulatory domain as a
> user is through iw [1] which does use netlink. Some distributions
> (like Fedora) automatically set your country based on the timezone
> information. So in the end you should not have to do this at all as a
> user.

Excellent for the future, but not yet an option for me.

> Another thing you should note is that if a driver has a regulatory
> domain hint then the driver regulatory domain is always trusted, users
> can *further* help compliance by selecting their country. What this 
> means since Atheros drivers do have EEPROM reading for the regulatory
> domain that will be used first, thus enabling only channels allowed by
> the programmed EEPROM.

That seems particularly bad in my case. For some weird reason this Trust 
PCMCIA card seems to have AM in its EEPROM, which is Armenia...
The card was bought in the Netherlands (NL), which is also where I live.

I have no idea what the regulations are in Armenia, but it seems damned 
silly to me to be restricted in this way just because of random hardware 
manufacturer's settings. I thought in the Linux world we'd long accepted 
that hardware manufacturers can't be trusted to get such things right.
Even ignoring the completely valid case of someone buying hardware in one 
country and then moving to another one.

I can to some extend understand respecting hardware settings for APs, but 
for a wireless NIC it seems a useless limitation. And I also suspect that 
manufacturers of (cheap) NICs are much more likely to get the hardware 
setting wrong (basically by not caring).

Cheers,
FJP

^ permalink raw reply

* Re: pull request: wireless-2.6 2009-07-08
From: David Miller @ 2009-07-09  1:14 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <20090708203745.GK4253@tuxdriver.com>

From: "John W. Linville" <linville@tuxdriver.com>
Date: Wed, 8 Jul 2009 16:37:45 -0400

> Here is a collection of bug fixes, build fixes, and minor hardware
> enablement patches intended for 2.6.31.  I don't think there is anything
> controversial.
> 
> Please let me know if there are problems!

Pulled into net-2.6, thanks!

^ permalink raw reply

* Re: [regression] ath5k: Overrides regulatory domain set for cfg80211
From: Luis R. Rodriguez @ 2009-07-09  2:07 UTC (permalink / raw)
  To: Frans Pop; +Cc: linux-wireless, netdev, Linux Kernel Mailing List
In-Reply-To: <200907090311.40205.elendil@planet.nl>

On Wed, Jul 8, 2009 at 6:11 PM, Frans Pop<elendil@planet.nl> wrote:

>> First, its not that anything is being ignored, user input is always
>> welcomed to help compliance you are just using a wrong ISO-3166
>> alpha2.
>>
>> EU is not a country and as such is only left on older kernels with
>> CONFIG_WIRELESS_OLD_REGULATORY  enabled. So "EU" is deprecated for non
>> CONFIG_WIRELESS_OLD_REGULATORY based kernels now.
>
> I *do* have CONFIG_WIRELESS_OLD_REGULATORY set for exactly the reason that
> I know I don't yet have the new userland.

That was the purpose for it after all.

> And if I change the country code to NL, I still get the same problem:
> cfg80211: Using static regulatory domain info
> cfg80211: Regulatory domain: US
>        (start_freq - end_freq @ bandwidth), (max_antenna_gain, max_eirp)
>        (2402000 KHz - 2472000 KHz @ 40000 KHz), (600 mBi, 2700 mBm)
>        (5170000 KHz - 5190000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5190000 KHz - 5210000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5210000 KHz - 5230000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5230000 KHz - 5330000 KHz @ 40000 KHz), (600 mBi, 2300 mBm)
>        (5735000 KHz - 5835000 KHz @ 40000 KHz), (600 mBi, 3000 mBm)
>  [Weird, when I specified EU I at least got the EU domain here.]

EU is a valid regulatory domain only when the relic option
CONFIG_WIRELESS_OLD_REGULATORY is used. When you use OLD_REG and "EU"
you get stuck to a statically defined regulatory domain in the kernel.

>  [Now I specify NL and it gives me US; how's that an improvement?]

Since you are using OLD_REG the default is "US", that was the behavior
prior to the new regulatory code so its left as is. So that is by
design following the old crap regulatory code design.

> cfg80211: Calling CRDA for country: NL
>  [no agent, so this does not actually change anything]

Users of OLD_REG who do not have new userspace should stick to using
the 3 static regulatory domains:

  1) US *
  2) JP
  3) EU

Unfortunately, the default is "US".

> ath5k 0000:02:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
> ath5k 0000:02:00.0: registered as 'phy0'
> ath: EEPROM regdomain: 0x30
> ath: EEPROM indicates we should expect a direct regpair map
> ath: Country alpha2 being used: AM
> ath: Regpair used: 0x30
> phy0: Selected rate control algorithm 'minstrel'
> ath5k phy0: Atheros AR5213A chip found (MAC: 0x59, PHY: 0x43)
> ath5k phy0: RF2112B 2GHz radio found (0x46)
> cfg80211: Calling CRDA for country: AM
>  [no agent, so this does not actually change anything]

Yes, by default you world roam when using an Atheros device and no
userspace agent is available. This is by design. ath5k previously used
to allow every single channel, restricting these further is not a
regression but more a regulatory fix on Linux. Its what allows us
vendors like Atheros to support Linux. For further information please
refer to:

http://wireless.kernel.org/en/vendors/VendorSupport
http://wireless.kernel.org/en/developers/Regulatory

>> For further information please also read
>> Documentation/feature-removal-schedule.txt. Please use a valid
>> ISO-3166 alpha2 country code, I also advise to abandon the usage of
>> the ieee80211_regdom module parameter which we do eventually intend on
>> deprecating and if you know anyone using that please suggest the same.
>
> As mentioned above I do not currently have the option of abandoning it.

Yes you do, but you don't seem to want to do anything beyond what your
distribution offers, which is different.

Users of OLD_REG with Atheros devices will world roam because we do
care about regulatory compliance.

> Please continue to provide full backwards compatibility with "old"
> userland until all major distros have iw and crda in their stable
> releases.

That's already done. You are missing the big picture, that of proper
regulatory compliance. Fixing regulatory compliance is not a
regression, it means more devices get proper support in Linux and more
vendors can be attracted to do the same.

>> Eventually, as you will read from the feature-removal schedule, we
>> intend on getting the Linux desktop to provide automatic hints of the
>> user's location through things like GeoClue. Reason for removing the
>> module parameter is its not the proper way to pass information to the
>> kernel, we now have a netlink interface for this exact purpose. Until
>> the desktop catches up we'll keep the ieee80211_regdom module
>> parameter, but the proper new way to set your regulatory domain as a
>> user is through iw [1] which does use netlink. Some distributions
>> (like Fedora) automatically set your country based on the timezone
>> information. So in the end you should not have to do this at all as a
>> user.
>
> Excellent for the future, but not yet an option for me.
>
>> Another thing you should note is that if a driver has a regulatory
>> domain hint then the driver regulatory domain is always trusted, users
>> can *further* help compliance by selecting their country. What this
>> means since Atheros drivers do have EEPROM reading for the regulatory
>> domain that will be used first, thus enabling only channels allowed by
>> the programmed EEPROM.
>
> That seems particularly bad in my case. For some weird reason this Trust
> PCMCIA card seems to have AM in its EEPROM, which is Armenia...
> The card was bought in the Netherlands (NL), which is also where I live.

Yeah the short story of that is Armenia and Netherlands both have the
same regulatory rules, the first alpha2 that matched the same group
was picked up, which just so happened to be Armenia. In the future it
will be easier if cards are just programmed with the alpha2 country
code or with a world regulatory domain code, and just abandon the
grouping idea. That is something we will have to look forward to
change and promote for future device. What counts for regulatory
purposes is your device is complaint. The alternative was to keep all
the regulatory information statically in the kernel for each
regulatory group for Atheros devices.

> I have no idea what the regulations are in Armenia, but it seems damned
> silly to me to be restricted in this way just because of random hardware
> manufacturer's settings. I thought in the Linux world we'd long accepted
> that hardware manufacturers can't be trusted to get such things right.

The world of Linux with wireless is in its diapers when it comes to
regulatory compliance, we just started. And a key feature to
regulatory compliance with today's legislation is to trust the
device's origin. As stupid as it may seem -- current legislation puts
vendors in positions to assume that some devices will never go to
another country. The law is obviously outdated but companies cannot
simply start being flexible without legislation actually changing.

What we are doing with Linux is paving the way for the future for a
decent regulatory infrastructure which makes sense and allows dynamic
communication and roaming. Slowly the hope is legislation will catch
on.

> Even ignoring the completely valid case of someone buying hardware in one
> country and then moving to another one.

Yes, I agree this is silly as well, but legislation needs to be
respected. Devices which have potential to roam to different countries
tend to get custom world regulatory domains assigned to them.

We have a good world roaming infrastructure with cfg80211 now, but you
have to kiss OLD_REG goodbye to use it.

> I can to some extend understand respecting hardware settings for APs, but
> for a wireless NIC it seems a useless limitation.

You are right to a certain degree. The thing is wireless cards *can*
be used as APs on a regular desktops. Perhaps not with iwlagn, but
with ath5k and ath9k you can do AP, IBSS, Mesh, all of which actually
do start transmit with out any AP being around. For these cases you
*do* need to ensure proper regulatory compliance. And we haven't even
touched on DFS!

> And I also suspect that
> manufacturers of (cheap) NICs are much more likely to get the hardware
> setting wrong (basically by not caring).

Sure, which is why we did the work we did on Linux. Regardless of how
sloppy the wireless vendors are today Linux has IMHO the best
regulatory infrastructure of all OSes. Nice thing about it too is most
of it is licensed under a permissive license so even the people in
Redmond could actually pick up a few things or two (yeah right)

  Luis

^ permalink raw reply

* Re: [PATCH 41/44] includecheck fix: include/linux, rfkill.h
From: Jaswinder Singh Rajput @ 2009-07-09  4:01 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: johannes, linux-wireless, Andrew Morton, Sam Ravnborg, LKML
In-Reply-To: <1247081557.9709.16.camel@localhost.localdomain>

Hello Marcel,

On Wed, 2009-07-08 at 12:32 -0700, Marcel Holtmann wrote:
> Hi Jaswinder,
> 
> > fix the following 'make includecheck' warning:
> > 
> >   include/linux/rfkill.h: linux/types.h is included more than once.
> > 
> > Signed-off-by: Jaswinder Singh Rajput <jaswinderrajput@gmail.com>
> > ---
> >  include/linux/rfkill.h |    1 -
> >  1 files changed, 0 insertions(+), 1 deletions(-)
> > 
> > diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
> > index e73e242..2ce2983 100644
> > --- a/include/linux/rfkill.h
> > +++ b/include/linux/rfkill.h
> > @@ -99,7 +99,6 @@ enum rfkill_user_states {
> >  #undef RFKILL_STATE_UNBLOCKED
> >  #undef RFKILL_STATE_HARD_BLOCKED
> >  
> > -#include <linux/types.h>
> >  #include <linux/kernel.h>
> >  #include <linux/list.h>
> >  #include <linux/mutex.h>
> 
> with the #ifdef __KERNEL__ in between it is kinda weird, but patch seems
> correct.
> 

ACK or Reviewed-by ?

Thanks,
--
JSR


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox