Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 0/9] cfg80211 fixes, cleanups, improvements
From: Johannes Berg @ 2009-07-07  1:56 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

This has a whole bunch of cfg80211 fixes, most
notably work to actually do locking in cfg80211
properly! Sorry, my head was too small to grasp
all of that in cfg80211 at once, so I deferred
locking for the connect() API to this series.

johannes


^ permalink raw reply

* [PATCH] mac80211: fix sparse warning
From: Johannes Berg @ 2009-07-07  1:54 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

ieee80211_testmode_cmd can very well be static.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/mac80211/cfg.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- wireless-testing.orig/net/mac80211/cfg.c	2009-07-07 03:53:56.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c	2009-07-07 03:53:58.000000000 +0200
@@ -1289,7 +1289,7 @@ static void ieee80211_rfkill_poll(struct
 }
 
 #ifdef CONFIG_NL80211_TESTMODE
-int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 



^ permalink raw reply

* [PATCH 3/3] mac80211: refactor the WEP code to be directly usable
From: Johannes Berg @ 2009-07-07  1:45 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20090707014515.024822579@sipsolutions.net>

The new key work for cfg80211 will only give us the WEP
key for shared auth to do that authentication, and not
via the regular key settings, so we need to be able to
encrypt a single frame in software, and that without a
key struct. Thus, refactor the WEP code to not require
a key structure but use the key, len and idx directly.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/mac80211/wep.c |   52 +++++++++++++++++++++++-----------------------------
 net/mac80211/wep.h |    4 ----
 2 files changed, 23 insertions(+), 33 deletions(-)

--- wireless-testing.orig/net/mac80211/wep.c	2009-07-07 03:43:38.000000000 +0200
+++ wireless-testing/net/mac80211/wep.c	2009-07-07 03:43:41.000000000 +0200
@@ -67,10 +67,10 @@ static inline bool ieee80211_wep_weak_iv
 
 
 static void ieee80211_wep_get_iv(struct ieee80211_local *local,
-				 struct ieee80211_key *key, u8 *iv)
+				 int keylen, int keyidx, u8 *iv)
 {
 	local->wep_iv++;
-	if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen))
+	if (ieee80211_wep_weak_iv(local->wep_iv, keylen))
 		local->wep_iv += 0x0100;
 
 	if (!iv)
@@ -79,13 +79,13 @@ static void ieee80211_wep_get_iv(struct 
 	*iv++ = (local->wep_iv >> 16) & 0xff;
 	*iv++ = (local->wep_iv >> 8) & 0xff;
 	*iv++ = local->wep_iv & 0xff;
-	*iv++ = key->conf.keyidx << 6;
+	*iv++ = keyidx << 6;
 }
 
 
 static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
 				struct sk_buff *skb,
-				struct ieee80211_key *key)
+				int keylen, int keyidx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	unsigned int hdrlen;
@@ -100,7 +100,7 @@ static u8 *ieee80211_wep_add_iv(struct i
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	newhdr = skb_push(skb, WEP_IV_LEN);
 	memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
-	ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
+	ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
 	return newhdr + hdrlen;
 }
 
@@ -144,26 +144,17 @@ void ieee80211_wep_encrypt_data(struct c
  *
  * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
  */
-int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
-			  struct ieee80211_key *key)
+static int ieee80211_wep_encrypt(struct ieee80211_local *local,
+				 struct sk_buff *skb,
+				 const u8 *key, int keylen, int keyidx)
 {
-	u32 klen;
-	u8 *rc4key, *iv;
+	u8 *iv;
 	size_t len;
+	u8 rc4key[3 + WLAN_KEY_LEN_WEP104];
 
-	if (!key || key->conf.alg != ALG_WEP)
-		return -1;
-
-	klen = 3 + key->conf.keylen;
-	rc4key = kmalloc(klen, GFP_ATOMIC);
-	if (!rc4key)
-		return -1;
-
-	iv = ieee80211_wep_add_iv(local, skb, key);
-	if (!iv) {
-		kfree(rc4key);
+	iv = ieee80211_wep_add_iv(local, skb, keylen, keyidx);
+	if (!iv)
 		return -1;
-	}
 
 	len = skb->len - (iv + WEP_IV_LEN - skb->data);
 
@@ -171,16 +162,14 @@ int ieee80211_wep_encrypt(struct ieee802
 	memcpy(rc4key, iv, 3);
 
 	/* Copy rest of the WEP key (the secret part) */
-	memcpy(rc4key + 3, key->conf.key, key->conf.keylen);
+	memcpy(rc4key + 3, key, keylen);
 
 	/* Add room for ICV */
 	skb_put(skb, WEP_ICV_LEN);
 
-	ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen,
+	ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, keylen + 3,
 				   iv + WEP_IV_LEN, len);
 
-	kfree(rc4key);
-
 	return 0;
 }
 
@@ -216,8 +205,9 @@ int ieee80211_wep_decrypt_data(struct cr
  * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
  * is moved to the beginning of the skb and skb length will be reduced.
  */
-int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
-			  struct ieee80211_key *key)
+static int ieee80211_wep_decrypt(struct ieee80211_local *local,
+				 struct sk_buff *skb,
+				 struct ieee80211_key *key)
 {
 	u32 klen;
 	u8 *rc4key;
@@ -314,12 +304,16 @@ static int wep_encrypt_skb(struct ieee80
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
 	if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
-		if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
+		if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
+					  tx->key->conf.keylen,
+					  tx->key->conf.keyidx))
 			return -1;
 	} else {
 		info->control.hw_key = &tx->key->conf;
 		if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
-			if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
+			if (!ieee80211_wep_add_iv(tx->local, skb,
+						  tx->key->conf.keylen,
+						  tx->key->conf.keyidx))
 				return -1;
 		}
 	}
--- wireless-testing.orig/net/mac80211/wep.h	2009-07-07 03:43:38.000000000 +0200
+++ wireless-testing/net/mac80211/wep.h	2009-07-07 03:43:41.000000000 +0200
@@ -22,10 +22,6 @@ void ieee80211_wep_encrypt_data(struct c
 				size_t klen, u8 *data, size_t data_len);
 int ieee80211_wep_decrypt_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,
-			  struct ieee80211_key *key);
-int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
-			  struct ieee80211_key *key);
 bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
 ieee80211_rx_result

-- 


^ permalink raw reply

* [PATCH 2/3] mac80211: rework MLME for multiple authentications
From: Johannes Berg @ 2009-07-07  1:45 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20090707014515.024822579@sipsolutions.net>

Sit tight. This shakes up the world as you know
it. Let go of your spaghetti tongs, they will no
longer be required, the horrible statemachine in
net/mac80211/mlme.c is no more...

With the cfg80211 SME mac80211 now has much less
to keep track of, but, on the other hand, for FT
it needs to be able to keep track of at least one
authentication being in progress while associated.
So convert from a single state machine to having
small ones for all the different things we need to
do. For real FT it will still need work wrt. PS,
but this should be a good step.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/mac80211/cfg.c            |  105 ---
 net/mac80211/debugfs_netdev.c |   38 -
 net/mac80211/ieee80211_i.h    |   86 +-
 net/mac80211/iface.c          |   28 
 net/mac80211/mlme.c           | 1340 ++++++++++++++++++++++--------------------
 net/mac80211/rx.c             |   29 
 net/mac80211/scan.c           |   23 
 7 files changed, 754 insertions(+), 895 deletions(-)

--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-07-07 03:37:02.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-07-07 03:37:03.000000000 +0200
@@ -227,11 +227,32 @@ struct mesh_preq_queue {
 	u8 flags;
 };
 
+enum ieee80211_mgd_state {
+	IEEE80211_MGD_STATE_IDLE,
+	IEEE80211_MGD_STATE_PROBE,
+	IEEE80211_MGD_STATE_AUTH,
+	IEEE80211_MGD_STATE_ASSOC,
+};
+
+struct ieee80211_mgd_work {
+	struct list_head list;
+	struct ieee80211_bss *bss;
+	int ie_len;
+	u8 prev_bssid[ETH_ALEN];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 ssid_len;
+	unsigned long timeout;
+	enum ieee80211_mgd_state state;
+	u16 auth_alg, auth_transaction;
+
+	int tries;
+
+	/* must be last */
+	u8 ie[0]; /* for auth or assoc frame, not probe */
+};
+
 /* flags used in struct ieee80211_if_managed.flags */
 enum ieee80211_sta_flags {
-	IEEE80211_STA_PREV_BSSID_SET	= BIT(0),
-	IEEE80211_STA_AUTHENTICATED	= BIT(1),
-	IEEE80211_STA_ASSOCIATED	= BIT(2),
 	IEEE80211_STA_PROBEREQ_POLL	= BIT(3),
 	IEEE80211_STA_CONTROL_PORT	= BIT(4),
 	IEEE80211_STA_WMM_ENABLED	= BIT(5),
@@ -243,8 +264,6 @@ enum ieee80211_sta_flags {
 /* flags for MLME request */
 enum ieee80211_sta_request {
 	IEEE80211_STA_REQ_SCAN,
-	IEEE80211_STA_REQ_AUTH,
-	IEEE80211_STA_REQ_RUN,
 };
 
 struct ieee80211_if_managed {
@@ -254,35 +273,17 @@ struct ieee80211_if_managed {
 	struct work_struct chswitch_work;
 	struct work_struct beacon_loss_work;
 
-	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
+	struct mutex mtx;
+	struct ieee80211_bss *associated;
+	struct list_head work_list;
 
-	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	size_t ssid_len;
-
-	enum {
-		IEEE80211_STA_MLME_DISABLED,
-		IEEE80211_STA_MLME_DIRECT_PROBE,
-		IEEE80211_STA_MLME_AUTHENTICATE,
-		IEEE80211_STA_MLME_ASSOCIATE,
-		IEEE80211_STA_MLME_ASSOCIATED,
-	} state;
+	u8 bssid[ETH_ALEN];
 
 	u16 aid;
 	u16 capab;
-	u8 *extra_ie; /* to be added to the end of AssocReq */
-	size_t extra_ie_len;
-
-	/* The last AssocReq/Resp IEs */
-	u8 *assocreq_ies, *assocresp_ies;
-	size_t assocreq_ies_len, assocresp_ies_len;
 
 	struct sk_buff_head skb_queue;
 
-	int assoc_scan_tries; /* number of scans done pre-association */
-	int direct_probe_tries; /* retries for direct probes */
-	int auth_tries; /* retries for auth req */
-	int assoc_tries; /* retries for assoc req */
-
 	unsigned long timers_running; /* used for quiesce/restart */
 	bool powersave; /* powersave requested for this iface */
 
@@ -292,9 +293,6 @@ struct ieee80211_if_managed {
 
 	unsigned int flags;
 
-	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
-	int auth_transaction;
-
 	u32 beacon_crc;
 
 	enum {
@@ -304,10 +302,6 @@ struct ieee80211_if_managed {
 	} mfp; /* management frame protection */
 
 	int wmm_last_param_set;
-
-	/* Extra IE data for management frames */
-	u8 *sme_auth_ie;
-	size_t sme_auth_ie_len;
 };
 
 enum ieee80211_ibss_request {
@@ -466,18 +460,9 @@ struct ieee80211_sub_if_data {
 	union {
 		struct {
 			struct dentry *drop_unencrypted;
-			struct dentry *state;
 			struct dentry *bssid;
-			struct dentry *prev_bssid;
-			struct dentry *ssid_len;
 			struct dentry *aid;
 			struct dentry *capab;
-			struct dentry *extra_ie_len;
-			struct dentry *auth_tries;
-			struct dentry *assoc_tries;
-			struct dentry *auth_alg;
-			struct dentry *auth_transaction;
-			struct dentry *flags;
 			struct dentry *force_unicast_rateidx;
 			struct dentry *max_ratectrl_rateidx;
 		} sta;
@@ -926,11 +911,16 @@ extern const struct iw_handler_def ieee8
 
 /* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
+int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+		       struct cfg80211_auth_request *req);
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+			struct cfg80211_assoc_request *req);
+int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+			 struct cfg80211_deauth_request *req);
+int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
+			   struct cfg80211_disassoc_request *req);
 ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
 					  struct sk_buff *skb);
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata);
-int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
-int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
 void ieee80211_send_pspoll(struct ieee80211_local *local,
 			   struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
@@ -964,8 +954,6 @@ int ieee80211_request_scan(struct ieee80
 void ieee80211_scan_cancel(struct ieee80211_local *local);
 ieee80211_rx_result
 ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
-			       const char *ie, size_t len);
 
 void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
 struct ieee80211_bss *
@@ -981,8 +969,6 @@ ieee80211_rx_bss_get(struct ieee80211_lo
 		     u8 *ssid, u8 ssid_len);
 void ieee80211_rx_bss_put(struct ieee80211_local *local,
 			  struct ieee80211_bss *bss);
-void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
-			     int freq, u8 *ssid, u8 ssid_len);
 
 /* interface handling */
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
--- wireless-testing.orig/net/mac80211/cfg.c	2009-07-07 03:36:58.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c	2009-07-07 03:37:03.000000000 +0200
@@ -1172,122 +1172,25 @@ static int ieee80211_scan(struct wiphy *
 static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
 			  struct cfg80211_auth_request *req)
 {
-	struct ieee80211_sub_if_data *sdata;
-	const u8 *ssid;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	switch (req->auth_type) {
-	case NL80211_AUTHTYPE_OPEN_SYSTEM:
-		sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN;
-		break;
-	case NL80211_AUTHTYPE_SHARED_KEY:
-		sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY;
-		break;
-	case NL80211_AUTHTYPE_FT:
-		sdata->u.mgd.auth_alg = WLAN_AUTH_FT;
-		break;
-	case NL80211_AUTHTYPE_NETWORK_EAP:
-		sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP;
-		break;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN);
-
-	sdata->local->oper_channel = req->bss->channel;
-	ieee80211_hw_config(sdata->local, 0);
-
-	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
-	if (!ssid)
-		return -EINVAL;
-	sdata->u.mgd.ssid_len = *(ssid + 1);
-	memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len);
-
-	kfree(sdata->u.mgd.sme_auth_ie);
-	sdata->u.mgd.sme_auth_ie = NULL;
-	sdata->u.mgd.sme_auth_ie_len = 0;
-	if (req->ie) {
-		sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL);
-		if (sdata->u.mgd.sme_auth_ie == NULL)
-			return -ENOMEM;
-		memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len);
-		sdata->u.mgd.sme_auth_ie_len = req->ie_len;
-	}
-
-	sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
-	ieee80211_sta_req_auth(sdata);
-	return 0;
+	return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
 			   struct cfg80211_assoc_request *req)
 {
-	struct ieee80211_sub_if_data *sdata;
-	int ret, i;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 ||
-	    !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
-		return -ENOLINK; /* not authenticated */
-
-	sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N;
-
-	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
-		if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
-		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
-		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
-			sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N;
-
-	sdata->local->oper_channel = req->bss->channel;
-	ieee80211_hw_config(sdata->local, 0);
-
-	ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
-	if (ret && ret != -EALREADY)
-		return ret;
-
-	if (req->use_mfp) {
-		sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
-		sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
-	} else {
-		sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
-		sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
-	}
-
-	if (req->prev_bssid) {
-		sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET;
-		memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN);
-	} else
-		sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-
-	if (req->crypto.control_port)
-		sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
-	else
-		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
-
-	sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
-	ieee80211_sta_req_auth(sdata);
-	return 0;
+	return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
 			    struct cfg80211_deauth_request *req)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	/* TODO: req->ie, req->peer_addr */
-	return ieee80211_sta_deauthenticate(sdata, req->reason_code);
+	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
 			      struct cfg80211_disassoc_request *req)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
-	/* TODO: req->ie, req->peer_addr */
-	return ieee80211_sta_disassociate(sdata, req->reason_code);
+	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
--- wireless-testing.orig/net/mac80211/iface.c	2009-07-07 03:29:38.000000000 +0200
+++ wireless-testing/net/mac80211/iface.c	2009-07-07 03:37:03.000000000 +0200
@@ -229,9 +229,6 @@ static int ieee80211_open(struct net_dev
 		ieee80211_configure_filter(local);
 		spin_unlock_bh(&local->filter_lock);
 		break;
-	case NL80211_IFTYPE_STATION:
-		sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
-		/* fall through */
 	default:
 		conf.vif = &sdata->vif;
 		conf.type = sdata->vif.type;
@@ -358,18 +355,6 @@ static int ieee80211_stop(struct net_dev
 	rcu_read_unlock();
 
 	/*
-	 * Announce that we are leaving the network, in case we are a
-	 * station interface type. This must be done before removing
-	 * all stations associated with sta_info_flush, otherwise STA
-	 * information will be gone and no announce being done.
-	 */
-	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-		if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED)
-			ieee80211_sta_deauthenticate(sdata,
-				WLAN_REASON_DEAUTH_LEAVING);
-	}
-
-	/*
 	 * Remove all stations associated with this interface.
 	 *
 	 * This must be done before calling ops->remove_interface()
@@ -461,7 +446,6 @@ static int ieee80211_stop(struct net_dev
 		spin_unlock_bh(&local->filter_lock);
 		break;
 	case NL80211_IFTYPE_STATION:
-		memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
 		del_timer_sync(&sdata->u.mgd.chswitch_timer);
 		del_timer_sync(&sdata->u.mgd.timer);
 		/*
@@ -484,10 +468,6 @@ static int ieee80211_stop(struct net_dev
 		 */
 		synchronize_rcu();
 		skb_queue_purge(&sdata->u.mgd.skb_queue);
-
-		kfree(sdata->u.mgd.extra_ie);
-		sdata->u.mgd.extra_ie = NULL;
-		sdata->u.mgd.extra_ie_len = 0;
 		/* fall through */
 	case NL80211_IFTYPE_ADHOC:
 		if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
@@ -649,11 +629,6 @@ static void ieee80211_teardown_sdata(str
 			kfree_skb(sdata->u.ibss.presp);
 		break;
 	case NL80211_IFTYPE_STATION:
-		kfree(sdata->u.mgd.extra_ie);
-		kfree(sdata->u.mgd.assocreq_ies);
-		kfree(sdata->u.mgd.assocresp_ies);
-		kfree(sdata->u.mgd.sme_auth_ie);
-		break;
 	case NL80211_IFTYPE_WDS:
 	case NL80211_IFTYPE_AP_VLAN:
 	case NL80211_IFTYPE_MONITOR:
@@ -936,7 +911,8 @@ u32 __ieee80211_recalc_idle(struct ieee8
 			continue;
 		/* do not count disabled managed interfaces */
 		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-		    sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED)
+		    !sdata->u.mgd.associated &&
+		    list_empty(&sdata->u.mgd.work_list))
 			continue;
 		/* do not count unused IBSS interfaces */
 		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
--- wireless-testing.orig/net/mac80211/mlme.c	2009-07-07 03:37:02.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2009-07-07 03:37:03.000000000 +0200
@@ -27,20 +27,51 @@
 #include "rate.h"
 #include "led.h"
 
-#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2
 #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
 #define IEEE80211_AUTH_MAX_TRIES 3
 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
 #define IEEE80211_ASSOC_MAX_TRIES 3
 #define IEEE80211_MONITORING_INTERVAL (2 * HZ)
 #define IEEE80211_PROBE_WAIT (HZ / 5)
-#define IEEE80211_PROBE_IDLE_TIME (60 * HZ)
-#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 
 #define TMR_RUNNING_TIMER	0
 #define TMR_RUNNING_CHANSW	1
 
+/*
+ * All cfg80211 functions have to be called outside a locked
+ * section so that they can acquire a lock themselves... This
+ * is much simpler than queuing up things in cfg80211, but we
+ * do need some indirection for that here.
+ */
+enum rx_mgmt_action {
+	/* no action required */
+	RX_MGMT_NONE,
+
+	/* caller must call cfg80211_send_rx_auth() */
+	RX_MGMT_CFG80211_AUTH,
+
+	/* caller must call cfg80211_send_rx_assoc() */
+	RX_MGMT_CFG80211_ASSOC,
+
+	/* caller must call cfg80211_send_deauth() */
+	RX_MGMT_CFG80211_DEAUTH,
+
+	/* caller must call cfg80211_send_disassoc() */
+	RX_MGMT_CFG80211_DISASSOC,
+
+	/* caller must call cfg80211_auth_timeout() & free work */
+	RX_MGMT_CFG80211_AUTH_TO,
+
+	/* caller must call cfg80211_assoc_timeout() & free work */
+	RX_MGMT_CFG80211_ASSOC_TO,
+};
+
 /* utils */
+static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd)
+{
+	WARN_ON(!mutex_is_locked(&ifmgd->mtx));
+}
+
 static int ecw2cw(int ecw)
 {
 	return (1 << ecw) - 1;
@@ -74,11 +105,10 @@ static int ieee80211_compatible_rates(st
  */
 static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 			       struct ieee80211_ht_info *hti,
-			       u16 ap_ht_cap_flags)
+			       const u8 *bssid, u16 ap_ht_cap_flags)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_supported_band *sband;
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct sta_info *sta;
 	u32 changed = 0;
 	u16 ht_opmode;
@@ -127,12 +157,10 @@ static u32 ieee80211_enable_ht(struct ie
 		ieee80211_hw_config(local, 0);
 
 		rcu_read_lock();
-
-		sta = sta_info_get(local, ifmgd->bssid);
+		sta = sta_info_get(local, bssid);
 		if (sta)
 			rate_control_rate_update(local, sband, sta,
 						 IEEE80211_RC_HT_CHANGED);
-
 		rcu_read_unlock();
         }
 
@@ -155,7 +183,8 @@ static u32 ieee80211_enable_ht(struct ie
 
 /* frame sending functions */
 
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
+				 struct ieee80211_mgd_work *wk)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
@@ -165,14 +194,13 @@ static void ieee80211_send_assoc(struct 
 	const u8 *ies, *ht_ie;
 	int i, len, count, rates_len, supp_rates_len;
 	u16 capab;
-	struct ieee80211_bss *bss;
 	int wmm = 0;
 	struct ieee80211_supported_band *sband;
 	u32 rates = 0;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-			    sizeof(*mgmt) + 200 + ifmgd->extra_ie_len +
-			    ifmgd->ssid_len);
+			    sizeof(*mgmt) + 200 + wk->ie_len +
+			    wk->ssid_len);
 	if (!skb) {
 		printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
 		       "frame\n", sdata->dev->name);
@@ -191,45 +219,35 @@ static void ieee80211_send_assoc(struct 
 			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
 	}
 
-	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-				   local->hw.conf.channel->center_freq,
-				   ifmgd->ssid, ifmgd->ssid_len);
-	if (bss) {
-		if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
-			capab |= WLAN_CAPABILITY_PRIVACY;
-		if (bss->wmm_used)
-			wmm = 1;
-
-		/* get all rates supported by the device and the AP as
-		 * some APs don't like getting a superset of their rates
-		 * in the association request (e.g. D-Link DAP 1353 in
-		 * b-only mode) */
-		rates_len = ieee80211_compatible_rates(bss, sband, &rates);
-
-		if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
-		    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
-			capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
-
-		ieee80211_rx_bss_put(local, bss);
-	} else {
-		rates = ~0;
-		rates_len = sband->n_bitrates;
-	}
+	if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
+		capab |= WLAN_CAPABILITY_PRIVACY;
+	if (wk->bss->wmm_used)
+		wmm = 1;
+
+	/* get all rates supported by the device and the AP as
+	 * some APs don't like getting a superset of their rates
+	 * in the association request (e.g. D-Link DAP 1353 in
+	 * b-only mode) */
+	rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates);
+
+	if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
+	    (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
+		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
+	memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-	memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
+	memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN);
 
-	if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {
+	if (!is_zero_ether_addr(wk->prev_bssid)) {
 		skb_put(skb, 10);
 		mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 						  IEEE80211_STYPE_REASSOC_REQ);
 		mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
 		mgmt->u.reassoc_req.listen_interval =
 				cpu_to_le16(local->hw.conf.listen_interval);
-		memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid,
+		memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid,
 		       ETH_ALEN);
 	} else {
 		skb_put(skb, 4);
@@ -241,10 +259,10 @@ static void ieee80211_send_assoc(struct 
 	}
 
 	/* SSID */
-	ies = pos = skb_put(skb, 2 + ifmgd->ssid_len);
+	ies = pos = skb_put(skb, 2 + wk->ssid_len);
 	*pos++ = WLAN_EID_SSID;
-	*pos++ = ifmgd->ssid_len;
-	memcpy(pos, ifmgd->ssid, ifmgd->ssid_len);
+	*pos++ = wk->ssid_len;
+	memcpy(pos, wk->ssid, wk->ssid_len);
 
 	/* add all rates which were marked to be used above */
 	supp_rates_len = rates_len;
@@ -299,9 +317,9 @@ static void ieee80211_send_assoc(struct 
 		}
 	}
 
-	if (ifmgd->extra_ie) {
-		pos = skb_put(skb, ifmgd->extra_ie_len);
-		memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len);
+	if (wk->ie_len && wk->ie) {
+		pos = skb_put(skb, wk->ie_len);
+		memcpy(pos, wk->ie, wk->ie_len);
 	}
 
 	if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
@@ -326,7 +344,7 @@ static void ieee80211_send_assoc(struct 
 	 */
 	if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
 	    sband->ht_cap.ht_supported &&
-	    (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) &&
+	    (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) &&
 	    ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
 	    (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) {
 		struct ieee80211_ht_info *ht_info =
@@ -363,18 +381,12 @@ static void ieee80211_send_assoc(struct 
 		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
 	}
 
-	kfree(ifmgd->assocreq_ies);
-	ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies;
-	ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL);
-	if (ifmgd->assocreq_ies)
-		memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len);
-
 	ieee80211_tx_skb(sdata, skb, 0);
 }
 
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
-					   u16 stype, u16 reason)
+					   const u8 *bssid, u16 stype, u16 reason)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -391,9 +403,9 @@ static void ieee80211_send_deauth_disass
 
 	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
 	memset(mgmt, 0, 24);
-	memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
+	memcpy(mgmt->da, bssid, ETH_ALEN);
 	memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-	memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
+	memcpy(mgmt->bssid, bssid, ETH_ALEN);
 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
 	skb_put(skb, 2);
 	/* u.deauth.reason_code == u.disassoc.reason_code */
@@ -477,28 +489,26 @@ static void ieee80211_chswitch_work(stru
 {
 	struct ieee80211_sub_if_data *sdata =
 		container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
-	struct ieee80211_bss *bss;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
 	if (!netif_running(sdata->dev))
 		return;
 
-	bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
-				   sdata->local->hw.conf.channel->center_freq,
-				   ifmgd->ssid, ifmgd->ssid_len);
-	if (!bss)
-		goto exit;
+	mutex_lock(&ifmgd->mtx);
+	if (!ifmgd->associated)
+		goto out;
 
 	sdata->local->oper_channel = sdata->local->csa_channel;
+	ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
+
 	/* XXX: shouldn't really modify cfg80211-owned data! */
-	if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
-		bss->cbss.channel = sdata->local->oper_channel;
+	ifmgd->associated->cbss.channel = sdata->local->oper_channel;
 
-	ieee80211_rx_bss_put(sdata->local, bss);
-exit:
-	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
 	ieee80211_wake_queues_by_reason(&sdata->local->hw,
 					IEEE80211_QUEUE_STOP_REASON_CSA);
+ out:
+	ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+	mutex_unlock(&ifmgd->mtx);
 }
 
 static void ieee80211_chswitch_timer(unsigned long data)
@@ -523,7 +533,9 @@ void ieee80211_sta_process_chanswitch(st
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
 
-	if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
+	ASSERT_MGD_MTX(ifmgd);
+
+	if (!ifmgd->associated)
 		return;
 
 	if (sdata->local->sw_scanning || sdata->local->hw_scanning)
@@ -634,7 +646,7 @@ void ieee80211_recalc_ps(struct ieee8021
 	}
 
 	if (count == 1 && found->u.mgd.powersave &&
-	    (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) &&
+	    found->u.mgd.associated && list_empty(&found->u.mgd.work_list) &&
 	    !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
 		s32 beaconint_us;
 
@@ -789,9 +801,6 @@ static u32 ieee80211_handle_bss_capabili
 					   u16 capab, bool erp_valid, u8 erp)
 {
 	struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-#endif
 	u32 changed = 0;
 	bool use_protection;
 	bool use_short_preamble;
@@ -808,42 +817,16 @@ static u32 ieee80211_handle_bss_capabili
 	use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME);
 
 	if (use_protection != bss_conf->use_cts_prot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
-			       sdata->dev->name,
-			       use_protection ? "enabled" : "disabled",
-			       ifmgd->bssid);
-		}
-#endif
 		bss_conf->use_cts_prot = use_protection;
 		changed |= BSS_CHANGED_ERP_CTS_PROT;
 	}
 
 	if (use_short_preamble != bss_conf->use_short_preamble) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: switched to %s barker preamble"
-			       " (BSSID=%pM)\n",
-			       sdata->dev->name,
-			       use_short_preamble ? "short" : "long",
-			       ifmgd->bssid);
-		}
-#endif
 		bss_conf->use_short_preamble = use_short_preamble;
 		changed |= BSS_CHANGED_ERP_PREAMBLE;
 	}
 
 	if (use_short_slot != bss_conf->use_short_slot) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: switched to %s slot time"
-			       " (BSSID=%pM)\n",
-			       sdata->dev->name,
-			       use_short_slot ? "short" : "long",
-			       ifmgd->bssid);
-		}
-#endif
 		bss_conf->use_short_slot = use_short_slot;
 		changed |= BSS_CHANGED_ERP_SLOT;
 	}
@@ -852,32 +835,23 @@ static u32 ieee80211_handle_bss_capabili
 }
 
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_bss *bss,
 				     u32 bss_info_changed)
 {
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
-
-	struct ieee80211_bss *bss;
 
 	bss_info_changed |= BSS_CHANGED_ASSOC;
-	ifmgd->flags |= IEEE80211_STA_ASSOCIATED;
+	/* set timing information */
+	sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
+	sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
+	sdata->vif.bss_conf.dtim_period = bss->dtim_period;
+
+	bss_info_changed |= BSS_CHANGED_BEACON_INT;
+	bss_info_changed |= ieee80211_handle_bss_capability(sdata,
+		bss->cbss.capability, bss->has_erp_value, bss->erp_value);
 
-	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-				   conf->channel->center_freq,
-				   ifmgd->ssid, ifmgd->ssid_len);
-	if (bss) {
-		/* set timing information */
-		sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
-		sdata->vif.bss_conf.timestamp = bss->cbss.tsf;
-		sdata->vif.bss_conf.dtim_period = bss->dtim_period;
-
-		bss_info_changed |= BSS_CHANGED_BEACON_INT;
-		bss_info_changed |= ieee80211_handle_bss_capability(sdata,
-			bss->cbss.capability, bss->has_erp_value, bss->erp_value);
-
-		ieee80211_rx_bss_put(local, bss);
-	}
+	sdata->u.mgd.associated = bss;
+	memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN);
 
 	ieee80211_led_assoc(local, 1);
 
@@ -905,152 +879,133 @@ static void ieee80211_set_associated(str
 	netif_carrier_on(sdata->dev);
 }
 
-static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
+		       struct ieee80211_mgd_work *wk)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 
-	ifmgd->direct_probe_tries++;
-	if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
+	wk->tries++;
+	if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
 		printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
-		       sdata->dev->name, ifmgd->bssid);
-		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-		ieee80211_recalc_idle(local);
-		cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid,
-					   GFP_KERNEL);
+		       sdata->dev->name, wk->bss->cbss.bssid);
 
 		/*
 		 * Most likely AP is not in the range so remove the
-		 * bss information associated to the AP
+		 * bss struct for that AP.
 		 */
-		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-				sdata->local->hw.conf.channel->center_freq,
-				ifmgd->ssid, ifmgd->ssid_len);
+		cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
 
 		/*
 		 * We might have a pending scan which had no chance to run yet
-		 * due to state == IEEE80211_STA_MLME_DIRECT_PROBE.
-		 * Hence, queue the STAs work again
+		 * due to work needing to be done. Hence, queue the STAs work
+		 * again for that.
 		 */
 		queue_work(local->hw.workqueue, &ifmgd->work);
-		return;
+		return RX_MGMT_CFG80211_AUTH_TO;
 	}
 
-	printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
-			sdata->dev->name, ifmgd->bssid,
-			ifmgd->direct_probe_tries);
-
-	ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+	printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n",
+			sdata->dev->name, wk->bss->cbss.bssid,
+			wk->tries);
 
-	/* Direct probe is sent to broadcast address as some APs
+	/*
+	 * Direct probe is sent to broadcast address as some APs
 	 * will not answer to direct packet in unassociated state.
 	 */
-	ieee80211_send_probe_req(sdata, NULL,
-				 ifmgd->ssid, ifmgd->ssid_len, NULL, 0);
+	ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0);
 
-	mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+	mod_timer(&ifmgd->timer, wk->timeout);
+
+	return RX_MGMT_NONE;
 }
 
 
-static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
+		       struct ieee80211_mgd_work *wk)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 
-	ifmgd->auth_tries++;
-	if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+	wk->tries++;
+	if (wk->tries > IEEE80211_AUTH_MAX_TRIES) {
 		printk(KERN_DEBUG "%s: authentication with AP %pM"
 		       " timed out\n",
-		       sdata->dev->name, ifmgd->bssid);
-		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-		ieee80211_recalc_idle(local);
-		cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid,
-					   GFP_KERNEL);
-		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-				sdata->local->hw.conf.channel->center_freq,
-				ifmgd->ssid, ifmgd->ssid_len);
+		       sdata->dev->name, wk->bss->cbss.bssid);
+
+		/*
+		 * Most likely AP is not in the range so remove the
+		 * bss struct for that AP.
+		 */
+		cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
 
 		/*
 		 * We might have a pending scan which had no chance to run yet
-		 * due to state == IEEE80211_STA_MLME_AUTHENTICATE.
-		 * Hence, queue the STAs work again
+		 * due to work needing to be done. Hence, queue the STAs work
+		 * again for that.
 		 */
 		queue_work(local->hw.workqueue, &ifmgd->work);
-		return;
+		return RX_MGMT_CFG80211_AUTH_TO;
 	}
 
-	ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-	printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
-	       sdata->dev->name, ifmgd->bssid);
-
-	ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie,
-			    ifmgd->sme_auth_ie_len, ifmgd->bssid, 0);
-	ifmgd->auth_transaction = 2;
+	printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n",
+	       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->auth_transaction = 2;
 
-	mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+	wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+	mod_timer(&ifmgd->timer, wk->timeout);
+
+	return RX_MGMT_NONE;
 }
 
-/*
- * The disassoc 'reason' argument can be either our own reason
- * if self disconnected or a reason code from the AP.
- */
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-				   bool deauth, bool self_disconnected,
-				   u16 reason)
+				   const u8 *bssid, bool deauth)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_conf *conf = &local_to_hw(local)->conf;
-	struct ieee80211_bss *bss;
 	struct sta_info *sta;
 	u32 changed = 0, config_changed = 0;
 
-	if (deauth) {
-		ifmgd->direct_probe_tries = 0;
-		ifmgd->auth_tries = 0;
-	}
-	ifmgd->assoc_scan_tries = 0;
-	ifmgd->assoc_tries = 0;
+	ASSERT_MGD_MTX(ifmgd);
+
+	ifmgd->associated = NULL;
+	memset(ifmgd->bssid, 0, ETH_ALEN);
+
+	/*
+	 * we need to commit the associated = NULL change because the
+	 * scan code uses that to determine whether this iface should
+	 * go to/wake up from powersave or not -- and could otherwise
+	 * wake the queues erroneously.
+	 */
+	smp_mb();
+
+	/*
+	 * Thus, we can only afterwards stop the queues -- to account
+	 * for the case where another CPU is finishing a scan at this
+	 * time -- we don't want the scan code to enable queues.
+	 */
 
 	netif_tx_stop_all_queues(sdata->dev);
 	netif_carrier_off(sdata->dev);
 
 	rcu_read_lock();
-	sta = sta_info_get(local, ifmgd->bssid);
+	sta = sta_info_get(local, bssid);
 	if (sta)
 		ieee80211_sta_tear_down_BA_sessions(sta);
 	rcu_read_unlock();
 
-	bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
-				   conf->channel->center_freq,
-				   ifmgd->ssid, ifmgd->ssid_len);
-
-	if (bss)
-		ieee80211_rx_bss_put(local, bss);
-
-	if (self_disconnected) {
-		if (deauth)
-			ieee80211_send_deauth_disassoc(sdata,
-				IEEE80211_STYPE_DEAUTH, reason);
-		else
-			ieee80211_send_deauth_disassoc(sdata,
-				IEEE80211_STYPE_DISASSOC, reason);
-	}
-
-	ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
 	changed |= ieee80211_reset_erp_info(sdata);
 
 	ieee80211_led_assoc(local, 0);
 	changed |= BSS_CHANGED_ASSOC;
 	sdata->vif.bss_conf.assoc = false;
 
-	if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
-		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-				sdata->local->hw.conf.channel->center_freq,
-				ifmgd->ssid, ifmgd->ssid_len);
-	}
-
 	ieee80211_set_wmm_default(sdata);
 
 	ieee80211_recalc_idle(local);
@@ -1079,7 +1034,7 @@ static void ieee80211_set_disassoc(struc
 
 	rcu_read_lock();
 
-	sta = sta_info_get(local, ifmgd->bssid);
+	sta = sta_info_get(local, bssid);
 	if (!sta) {
 		rcu_read_unlock();
 		return;
@@ -1092,38 +1047,42 @@ static void ieee80211_set_disassoc(struc
 	sta_info_destroy(sta);
 }
 
-static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
+static enum rx_mgmt_action __must_check
+ieee80211_associate(struct ieee80211_sub_if_data *sdata,
+		    struct ieee80211_mgd_work *wk)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
 
-	ifmgd->assoc_tries++;
-	if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+	wk->tries++;
+	if (wk->tries > IEEE80211_ASSOC_MAX_TRIES) {
 		printk(KERN_DEBUG "%s: association with AP %pM"
 		       " timed out\n",
-		       sdata->dev->name, ifmgd->bssid);
-		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-		ieee80211_recalc_idle(local);
-		cfg80211_send_assoc_timeout(sdata->dev, ifmgd->bssid,
-					    GFP_KERNEL);
-		ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
-				sdata->local->hw.conf.channel->center_freq,
-				ifmgd->ssid, ifmgd->ssid_len);
+		       sdata->dev->name, wk->bss->cbss.bssid);
+
+		/*
+		 * Most likely AP is not in the range so remove the
+		 * bss struct for that AP.
+		 */
+		cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss);
+
 		/*
 		 * We might have a pending scan which had no chance to run yet
-		 * due to state == IEEE80211_STA_MLME_ASSOCIATE.
-		 * Hence, queue the STAs work again
+		 * due to work needing to be done. Hence, queue the STAs work
+		 * again for that.
 		 */
 		queue_work(local->hw.workqueue, &ifmgd->work);
-		return;
+		return RX_MGMT_CFG80211_ASSOC_TO;
 	}
 
-	ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
-	printk(KERN_DEBUG "%s: associate with AP %pM\n",
-	       sdata->dev->name, ifmgd->bssid);
-	ieee80211_send_assoc(sdata);
+	printk(KERN_DEBUG "%s: associate with AP %pM (try %d)\n",
+	       sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
+	ieee80211_send_assoc(sdata, wk);
 
-	mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+	wk->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT;
+	mod_timer(&ifmgd->timer, wk->timeout);
+
+	return RX_MGMT_NONE;
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1148,6 +1107,7 @@ void ieee80211_beacon_loss_work(struct w
 		container_of(work, struct ieee80211_sub_if_data,
 			     u.mgd.beacon_loss_work);
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	const u8 *ssid;
 
 	/*
 	 * The driver has already reported this event and we have
@@ -1160,12 +1120,15 @@ void ieee80211_beacon_loss_work(struct w
 	if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
 		return;
 
+	mutex_lock(&ifmgd->mtx);
+
+	if (!ifmgd->associated)
+		goto out;
+
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	if (net_ratelimit()) {
-		printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
-		       "- sending probe request\n", sdata->dev->name,
-		       sdata->u.mgd.bssid);
-	}
+	if (net_ratelimit())
+		printk(KERN_DEBUG "%s: driver reports beacon loss from AP "
+		       "- sending probe request\n", sdata->dev->name);
 #endif
 
 	ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
@@ -1174,10 +1137,13 @@ void ieee80211_beacon_loss_work(struct w
 	ieee80211_recalc_ps(sdata->local, -1);
 	mutex_unlock(&sdata->local->iflist_mtx);
 
-	ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
-				 ifmgd->ssid_len, NULL, 0);
+	ssid = ieee80211_bss_get_ie(&ifmgd->associated->cbss, WLAN_EID_SSID);
+	ieee80211_send_probe_req(sdata, ifmgd->associated->cbss.bssid,
+				 ssid + 2, ssid[1], NULL, 0);
 
 	mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
+ out:
+	mutex_unlock(&ifmgd->mtx);
 }
 
 void ieee80211_beacon_loss(struct ieee80211_vif *vif)
@@ -1189,102 +1155,16 @@ void ieee80211_beacon_loss(struct ieee80
 }
 EXPORT_SYMBOL(ieee80211_beacon_loss);
 
-static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-	struct sta_info *sta;
-	unsigned long last_rx;
-	bool disassoc = false;
-
-	/* TODO: start monitoring current AP signal quality and number of
-	 * missed beacons. Scan other channels every now and then and search
-	 * for better APs. */
-	/* TODO: remove expired BSSes */
-
-	ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED;
-
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ifmgd->bssid);
-	if (!sta) {
-		printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
-		       sdata->dev->name, ifmgd->bssid);
-		disassoc = true;
-		rcu_read_unlock();
-		goto out;
-	}
-
-	last_rx = sta->last_rx;
-	rcu_read_unlock();
-
-	if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
-	    time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) {
-		printk(KERN_DEBUG "%s: no probe response from AP %pM "
-		       "- disassociating\n",
-		       sdata->dev->name, ifmgd->bssid);
-		disassoc = true;
-		ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
-		goto out;
-	}
-
-	/*
-	 * Beacon filtering is only enabled with power save and then the
-	 * stack should not check for beacon loss.
-	 */
-	if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) &&
-	      (local->hw.conf.flags & IEEE80211_CONF_PS)) &&
-	    time_after(jiffies,
-		       ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "%s: beacon loss from AP %pM "
-			       "- sending probe request\n",
-			       sdata->dev->name, ifmgd->bssid);
-		}
-#endif
-		ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
-		mutex_lock(&local->iflist_mtx);
-		ieee80211_recalc_ps(local, -1);
-		mutex_unlock(&local->iflist_mtx);
-		ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
-					 ifmgd->ssid_len, NULL, 0);
-		mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
-		goto out;
-	}
-
-	if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) {
-		ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
-		mutex_lock(&local->iflist_mtx);
-		ieee80211_recalc_ps(local, -1);
-		mutex_unlock(&local->iflist_mtx);
-		ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
-					 ifmgd->ssid_len, NULL, 0);
-	}
-
- out:
-	if (!disassoc)
-		mod_timer(&ifmgd->timer,
-			  jiffies + IEEE80211_MONITORING_INTERVAL);
-	else
-		ieee80211_set_disassoc(sdata, true, true,
-					WLAN_REASON_PREV_AUTH_NOT_VALID);
-}
-
-
-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_mgd_work *wk)
 {
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
+	wk->state = IEEE80211_MGD_STATE_IDLE;
 	printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
-	ifmgd->flags |= IEEE80211_STA_AUTHENTICATED;
-	/* Wait for SME to request association */
-	ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-	ieee80211_recalc_idle(sdata->local);
 }
 
 
 static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
+				     struct ieee80211_mgd_work *wk,
 				     struct ieee80211_mgmt *mgmt,
 				     size_t len)
 {
@@ -1295,120 +1175,132 @@ static void ieee80211_auth_challenge(str
 	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
 	if (!elems.challenge)
 		return;
-	ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg,
+	ieee80211_send_auth(sdata, 3, wk->auth_alg,
 			    elems.challenge - 2, elems.challenge_len + 2,
-			    sdata->u.mgd.bssid, 1);
-	sdata->u.mgd.auth_transaction = 4;
+			    wk->bss->cbss.bssid, 1);
+	wk->auth_transaction = 4;
 }
 
-static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
-				   struct ieee80211_mgmt *mgmt,
-				   size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
+		       struct ieee80211_mgd_work *wk,
+		       struct ieee80211_mgmt *mgmt, size_t len)
 {
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	u16 auth_alg, auth_transaction, status_code;
 
-	if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE)
-		return;
+	if (wk->state != IEEE80211_MGD_STATE_AUTH)
+		return RX_MGMT_NONE;
 
 	if (len < 24 + 6)
-		return;
+		return RX_MGMT_NONE;
 
-	if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
-		return;
+	if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
+		return RX_MGMT_NONE;
 
-	if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
-		return;
+	if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
+		return RX_MGMT_NONE;
 
 	auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
 	auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
 	status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-	if (auth_alg != ifmgd->auth_alg ||
-	    auth_transaction != ifmgd->auth_transaction)
-		return;
+	if (auth_alg != wk->auth_alg ||
+	    auth_transaction != wk->auth_transaction)
+		return RX_MGMT_NONE;
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
-		cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len,
-				      GFP_KERNEL);
-		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-		ieee80211_recalc_idle(sdata->local);
-		return;
+		list_del(&wk->list);
+		kfree(wk);
+		return RX_MGMT_CFG80211_AUTH;
 	}
 
-	switch (ifmgd->auth_alg) {
+	switch (wk->auth_alg) {
 	case WLAN_AUTH_OPEN:
 	case WLAN_AUTH_LEAP:
 	case WLAN_AUTH_FT:
-		ieee80211_auth_completed(sdata);
-		cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len,
-				      GFP_KERNEL);
-		break;
+		ieee80211_auth_completed(sdata, wk);
+		return RX_MGMT_CFG80211_AUTH;
 	case WLAN_AUTH_SHARED_KEY:
-		if (ifmgd->auth_transaction == 4) {
-			ieee80211_auth_completed(sdata);
-			cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len,
-					      GFP_KERNEL);
+		if (wk->auth_transaction == 4) {
+			ieee80211_auth_completed(sdata, wk);
+			return RX_MGMT_CFG80211_AUTH;
 		} else
-			ieee80211_auth_challenge(sdata, mgmt, len);
+			ieee80211_auth_challenge(sdata, wk, mgmt, len);
 		break;
 	}
+
+	return RX_MGMT_NONE;
 }
 
 
-static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
+			 struct ieee80211_mgd_work *wk,
+			 struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	const u8 *bssid = NULL;
 	u16 reason_code;
 
 	if (len < 24 + 2)
-		return;
+		return RX_MGMT_NONE;
 
-	if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
-		return;
+	ASSERT_MGD_MTX(ifmgd);
+
+	if (wk)
+		bssid = wk->bss->cbss.bssid;
+	else
+		bssid = ifmgd->associated->cbss.bssid;
 
 	reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-	if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED)
-		printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
-				sdata->dev->name, reason_code);
+	printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
+			sdata->dev->name, bssid, reason_code);
+
+	if (!wk) {
+		ieee80211_set_disassoc(sdata, bssid, true);
+	} else {
+		list_del(&wk->list);
+		kfree(wk);
+	}
 
-	ieee80211_set_disassoc(sdata, true, false, 0);
-	ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;
-	cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL);
+	return RX_MGMT_CFG80211_DEAUTH;
 }
 
 
-static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
-				       struct ieee80211_mgmt *mgmt,
-				       size_t len)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
+			   struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	u16 reason_code;
 
 	if (len < 24 + 2)
-		return;
+		return RX_MGMT_NONE;
 
-	if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
-		return;
+	ASSERT_MGD_MTX(ifmgd);
+
+	if (WARN_ON(!ifmgd->associated))
+		return RX_MGMT_NONE;
+
+	if (WARN_ON(memcmp(ifmgd->associated->cbss.bssid, mgmt->sa, ETH_ALEN)))
+		return RX_MGMT_NONE;
 
 	reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-	if (ifmgd->flags & IEEE80211_STA_ASSOCIATED)
-		printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
-				sdata->dev->name, reason_code);
+	printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
+			sdata->dev->name, reason_code);
 
-	ieee80211_set_disassoc(sdata, false, false, reason_code);
-	cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL);
+	ieee80211_set_disassoc(sdata, ifmgd->associated->cbss.bssid, false);
+	return RX_MGMT_CFG80211_DISASSOC;
 }
 
 
-static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
-					 struct ieee80211_mgmt *mgmt,
-					 size_t len,
-					 int reassoc)
+static enum rx_mgmt_action __must_check
+ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+			     struct ieee80211_mgd_work *wk,
+			     struct ieee80211_mgmt *mgmt, size_t len,
+			     bool reassoc)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_local *local = sdata->local;
@@ -1424,17 +1316,16 @@ static void ieee80211_rx_mgmt_assoc_resp
 	bool have_higher_than_11mbit = false, newsta = false;
 	u16 ap_ht_cap_flags;
 
-	/* AssocResp and ReassocResp have identical structure, so process both
-	 * of them in this function. */
-
-	if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
-		return;
+	/*
+	 * AssocResp and ReassocResp have identical structure, so process both
+	 * of them in this function.
+	 */
 
 	if (len < 24 + 6)
-		return;
+		return RX_MGMT_NONE;
 
-	if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
-		return;
+	if (memcmp(wk->bss->cbss.bssid, mgmt->sa, ETH_ALEN) != 0)
+		return RX_MGMT_NONE;
 
 	capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
 	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
@@ -1457,21 +1348,19 @@ static void ieee80211_rx_mgmt_assoc_resp
 		printk(KERN_DEBUG "%s: AP rejected association temporarily; "
 		       "comeback duration %u TU (%u ms)\n",
 		       sdata->dev->name, tu, ms);
+		wk->timeout = jiffies + msecs_to_jiffies(ms);
 		if (ms > IEEE80211_ASSOC_TIMEOUT)
 			mod_timer(&ifmgd->timer,
 				  jiffies + msecs_to_jiffies(ms));
-		return;
+		return RX_MGMT_NONE;
 	}
 
 	if (status_code != WLAN_STATUS_SUCCESS) {
 		printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
 		       sdata->dev->name, status_code);
-		cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len,
-				       GFP_KERNEL);
-		/* Wait for SME to decide what to do next */
-		ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-		ieee80211_recalc_idle(local);
-		return;
+		list_del(&wk->list);
+		kfree(wk);
+		return RX_MGMT_CFG80211_ASSOC;
 	}
 
 	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
@@ -1482,50 +1371,38 @@ static void ieee80211_rx_mgmt_assoc_resp
 	if (!elems.supp_rates) {
 		printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
 		       sdata->dev->name);
-		return;
+		return RX_MGMT_NONE;
 	}
 
 	printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
 	ifmgd->aid = aid;
 
-	kfree(ifmgd->assocresp_ies);
-	ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt);
-	ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL);
-	if (ifmgd->assocresp_ies)
-		memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len);
-
 	rcu_read_lock();
 
 	/* Add STA entry for the AP */
-	sta = sta_info_get(local, ifmgd->bssid);
+	sta = sta_info_get(local, wk->bss->cbss.bssid);
 	if (!sta) {
 		newsta = true;
 
-		sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC);
+		rcu_read_unlock();
+
+		sta = sta_info_alloc(sdata, wk->bss->cbss.bssid, GFP_KERNEL);
 		if (!sta) {
 			printk(KERN_DEBUG "%s: failed to alloc STA entry for"
 			       " the AP\n", sdata->dev->name);
-			rcu_read_unlock();
-			return;
+			return RX_MGMT_NONE;
 		}
 
 		/* update new sta with its last rx activity */
 		sta->last_rx = jiffies;
-	}
 
-	/*
-	 * FIXME: Do we really need to update the sta_info's information here?
-	 *	  We already know about the AP (we found it in our list) so it
-	 *	  should already be filled with the right info, no?
-	 *	  As is stands, all this is racy because typically we assume
-	 *	  the information that is filled in here (except flags) doesn't
-	 *	  change while a STA structure is alive. As such, it should move
-	 *	  to between the sta_info_alloc() and sta_info_insert() above.
-	 */
+		set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC |
+				   WLAN_STA_ASSOC_AP);
+		if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+			set_sta_flags(sta, WLAN_STA_AUTHORIZED);
 
-	set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP);
-	if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-		set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+		rcu_read_lock();
+	}
 
 	rates = 0;
 	basic_rates = 0;
@@ -1595,7 +1472,7 @@ static void ieee80211_rx_mgmt_assoc_resp
 			printk(KERN_DEBUG "%s: failed to insert STA entry for"
 			       " the AP (error %d)\n", sdata->dev->name, err);
 			rcu_read_unlock();
-			return;
+			return RX_MGMT_NONE;
 		}
 	}
 
@@ -1611,13 +1488,14 @@ static void ieee80211_rx_mgmt_assoc_resp
 	    (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
 	    !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
 		changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
+					       wk->bss->cbss.bssid,
 					       ap_ht_cap_flags);
 
 	/* set AID and assoc capability,
 	 * ieee80211_set_associated() will tell the driver */
 	bss_conf->aid = aid;
 	bss_conf->assoc_capability = capab_info;
-	ieee80211_set_associated(sdata, changed);
+	ieee80211_set_associated(sdata, wk->bss, changed);
 
 	/*
 	 * initialise the time of last beacon to be the association time,
@@ -1625,8 +1503,9 @@ static void ieee80211_rx_mgmt_assoc_resp
 	 */
 	ifmgd->last_beacon = jiffies;
 
-	ieee80211_associated(sdata);
-	cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len, GFP_KERNEL);
+	list_del(&wk->list);
+	kfree(wk);
+	return RX_MGMT_CFG80211_ASSOC;
 }
 
 
@@ -1654,23 +1533,25 @@ static void ieee80211_rx_bss_info(struct
 
 	bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
 					channel, beacon);
-	if (!bss)
+	if (bss)
+		ieee80211_rx_bss_put(local, bss);
+
+	if (!sdata->u.mgd.associated)
 		return;
 
 	if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
-	    (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
+	    (memcmp(mgmt->bssid, sdata->u.mgd.associated->cbss.bssid,
+							ETH_ALEN) == 0)) {
 		struct ieee80211_channel_sw_ie *sw_elem =
 			(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
 		ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
 	}
-
-	ieee80211_rx_bss_put(local, bss);
 }
 
 
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
-					 struct ieee80211_mgmt *mgmt,
-					 size_t len,
+					 struct ieee80211_mgd_work *wk,
+					 struct ieee80211_mgmt *mgmt, size_t len,
 					 struct ieee80211_rx_status *rx_status)
 {
 	struct ieee80211_if_managed *ifmgd;
@@ -1679,6 +1560,8 @@ static void ieee80211_rx_mgmt_probe_resp
 
 	ifmgd = &sdata->u.mgd;
 
+	ASSERT_MGD_MTX(ifmgd);
+
 	if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
 		return; /* ignore ProbeResp to foreign address */
 
@@ -1692,13 +1575,17 @@ static void ieee80211_rx_mgmt_probe_resp
 	ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
 
 	/* direct probe may be part of the association flow */
-	if (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE) {
+	if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) {
 		printk(KERN_DEBUG "%s direct probe responded\n",
 		       sdata->dev->name);
-		ieee80211_authenticate(sdata);
+		wk->tries = 0;
+		wk->state = IEEE80211_MGD_STATE_AUTH;
+		WARN_ON(ieee80211_authenticate(sdata, wk) != RX_MGMT_NONE);
 	}
 
-	if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+	if (ifmgd->associated &&
+	    memcmp(mgmt->bssid, ifmgd->associated->cbss.bssid, ETH_ALEN) == 0 &&
+	    ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
 		ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
 		mutex_lock(&sdata->local->iflist_mtx);
 		ieee80211_recalc_ps(sdata->local, -1);
@@ -1740,6 +1627,9 @@ static void ieee80211_rx_mgmt_beacon(str
 	bool erp_valid, directed_tim = false;
 	u8 erp_value = 0;
 	u32 ncrc;
+	u8 *bssid;
+
+	ASSERT_MGD_MTX(ifmgd);
 
 	/* Process beacon from the current BSS */
 	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
@@ -1749,8 +1639,12 @@ static void ieee80211_rx_mgmt_beacon(str
 	if (rx_status->freq != local->hw.conf.channel->center_freq)
 		return;
 
-	if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||
-	    memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
+	if (WARN_ON(!ifmgd->associated))
+		return;
+
+	bssid = ifmgd->associated->cbss.bssid;
+
+	if (WARN_ON(memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0))
 		return;
 
 	if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
@@ -1829,8 +1723,8 @@ static void ieee80211_rx_mgmt_beacon(str
 
 		rcu_read_lock();
 
-		sta = sta_info_get(local, ifmgd->bssid);
-		if (!sta) {
+		sta = sta_info_get(local, bssid);
+		if (WARN_ON(!sta)) {
 			rcu_read_unlock();
 			return;
 		}
@@ -1845,7 +1739,7 @@ static void ieee80211_rx_mgmt_beacon(str
 		rcu_read_unlock();
 
 		changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
-					       ap_ht_cap_flags);
+					       bssid, ap_ht_cap_flags);
 	}
 
 	if (elems.country_elem) {
@@ -1887,6 +1781,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgm
 	case IEEE80211_STYPE_REASSOC_RESP:
 	case IEEE80211_STYPE_DEAUTH:
 	case IEEE80211_STYPE_DISASSOC:
+	case IEEE80211_STYPE_ACTION:
 		skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
 		queue_work(local->hw.workqueue, &sdata->u.mgd.work);
 		return RX_QUEUED;
@@ -1898,40 +1793,118 @@ ieee80211_rx_result ieee80211_sta_rx_mgm
 static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 					 struct sk_buff *skb)
 {
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_rx_status *rx_status;
 	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_mgd_work *wk;
+	enum rx_mgmt_action rma = RX_MGMT_NONE;
 	u16 fc;
 
 	rx_status = (struct ieee80211_rx_status *) skb->cb;
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	fc = le16_to_cpu(mgmt->frame_control);
 
-	switch (fc & IEEE80211_FCTL_STYPE) {
-	case IEEE80211_STYPE_PROBE_RESP:
-		ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
-					     rx_status);
-		break;
-	case IEEE80211_STYPE_BEACON:
-		ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
-					 rx_status);
-		break;
-	case IEEE80211_STYPE_AUTH:
-		ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
-		break;
-	case IEEE80211_STYPE_ASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0);
+	mutex_lock(&ifmgd->mtx);
+
+	if (ifmgd->associated &&
+	    memcmp(ifmgd->associated->cbss.bssid, mgmt->bssid,
+		    					ETH_ALEN) == 0) {
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_BEACON:
+			ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+						 rx_status);
+			break;
+		case IEEE80211_STYPE_PROBE_RESP:
+			ieee80211_rx_mgmt_probe_resp(sdata, NULL, mgmt,
+						     skb->len, rx_status);
+			break;
+		case IEEE80211_STYPE_DEAUTH:
+			rma = ieee80211_rx_mgmt_deauth(sdata, NULL,
+						       mgmt, skb->len);
+			break;
+		case IEEE80211_STYPE_DISASSOC:
+			rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+			break;
+		case IEEE80211_STYPE_ACTION:
+			/* XXX: differentiate, can only happen for CSA now! */
+			ieee80211_sta_process_chanswitch(sdata,
+					&mgmt->u.action.u.chan_switch.sw_elem,
+					ifmgd->associated);
+			break;
+		}
+		mutex_unlock(&ifmgd->mtx);
+
+		switch (rma) {
+		case RX_MGMT_NONE:
+			/* no action */
+			break;
+		case RX_MGMT_CFG80211_DEAUTH:
+			cfg80211_send_deauth(sdata->dev, (u8 *) mgmt,
+					     skb->len, GFP_KERNEL);
+			break;
+		case RX_MGMT_CFG80211_DISASSOC:
+			cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt,
+					       skb->len, GFP_KERNEL);
+			break;
+		default:
+			WARN(1, "unexpected: %d", rma);
+		}
+		goto out;
+	}
+
+	list_for_each_entry(wk, &ifmgd->work_list, list) {
+		if (memcmp(wk->bss->cbss.bssid, mgmt->bssid, ETH_ALEN) != 0)
+			continue;
+
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PROBE_RESP:
+			ieee80211_rx_mgmt_probe_resp(sdata, wk, mgmt, skb->len,
+						     rx_status);
+			break;
+		case IEEE80211_STYPE_AUTH:
+			rma = ieee80211_rx_mgmt_auth(sdata, wk, mgmt, skb->len);
+			break;
+		case IEEE80211_STYPE_ASSOC_RESP:
+			rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
+							   skb->len, false);
+			break;
+		case IEEE80211_STYPE_REASSOC_RESP:
+			rma = ieee80211_rx_mgmt_assoc_resp(sdata, wk, mgmt,
+							   skb->len, true);
+			break;
+		case IEEE80211_STYPE_DEAUTH:
+			rma = ieee80211_rx_mgmt_deauth(sdata, wk, mgmt,
+						       skb->len);
+			break;
+		}
+		/*
+		 * We've processed this frame for that work, so it can't
+		 * belong to another work struct.
+		 * NB: this is also required for correctness because the
+		 * called functions can free 'wk', and for 'rma'!
+		 */
 		break;
-	case IEEE80211_STYPE_REASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1);
+	}
+
+	mutex_unlock(&ifmgd->mtx);
+
+	switch (rma) {
+	case RX_MGMT_NONE:
+		/* no action */
 		break;
-	case IEEE80211_STYPE_DEAUTH:
-		ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
+	case RX_MGMT_CFG80211_AUTH:
+		cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, skb->len,
+				      GFP_KERNEL);
 		break;
-	case IEEE80211_STYPE_DISASSOC:
-		ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+	case RX_MGMT_CFG80211_ASSOC:
+		cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, skb->len,
+				       GFP_KERNEL);
 		break;
+	default:
+		WARN(1, "unexpected: %d", rma);
 	}
 
+ out:
 	kfree_skb(skb);
 }
 
@@ -1947,89 +1920,9 @@ static void ieee80211_sta_timer(unsigned
 		return;
 	}
 
-	set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
 	queue_work(local->hw.workqueue, &ifmgd->work);
 }
 
-static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-
-	/* Reset own TSF to allow time synchronization work. */
-	drv_reset_tsf(local);
-
-	ifmgd->wmm_last_param_set = -1; /* allow any WMM update */
-	ifmgd->auth_transaction = -1;
-	ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
-	ifmgd->assoc_scan_tries = 0;
-	ifmgd->direct_probe_tries = 0;
-	ifmgd->auth_tries = 0;
-	ifmgd->assoc_tries = 0;
-	netif_tx_stop_all_queues(sdata->dev);
-	netif_carrier_off(sdata->dev);
-}
-
-static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
-{
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
-	struct ieee80211_bss *bss;
-	u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid;
-	u8 ssid_len = ifmgd->ssid_len;
-	u16 capa_mask = WLAN_CAPABILITY_ESS;
-	u16 capa_val = WLAN_CAPABILITY_ESS;
-	struct ieee80211_channel *chan = local->oper_channel;
-
-	bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan,
-				       bssid, ssid, ssid_len,
-				       capa_mask, capa_val);
-
-	if (bss) {
-		local->oper_channel = bss->cbss.channel;
-		local->oper_channel_type = NL80211_CHAN_NO_HT;
-		ieee80211_hw_config(local, 0);
-
-		ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len,
-						    bss->supp_rates);
-		if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED)
-			sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
-		else
-			sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
-
-		/* Send out direct probe if no probe resp was received or
-		 * the one we have is outdated
-		 */
-		if (!bss->last_probe_resp ||
-		    time_after(jiffies, bss->last_probe_resp
-					+ IEEE80211_SCAN_RESULT_EXPIRE))
-			ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
-		else
-			ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-
-		ieee80211_rx_bss_put(local, bss);
-		ieee80211_sta_reset_auth(sdata);
-		return 0;
-	} else {
-		if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
-
-			ifmgd->assoc_scan_tries++;
-
-			ieee80211_request_internal_scan(sdata, ifmgd->ssid,
-							ssid_len);
-
-			ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
-			set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
-		} else {
-			ifmgd->assoc_scan_tries = 0;
-			ifmgd->state = IEEE80211_STA_MLME_DISABLED;
-			ieee80211_recalc_idle(local);
-		}
-	}
-	return -1;
-}
-
-
 static void ieee80211_sta_work(struct work_struct *work)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -2037,6 +1930,10 @@ static void ieee80211_sta_work(struct wo
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd;
 	struct sk_buff *skb;
+	struct ieee80211_mgd_work *wk, *tmp;
+	LIST_HEAD(free_work);
+	enum rx_mgmt_action rma;
+	bool anybusy = false;
 
 	if (!netif_running(sdata->dev))
 		return;
@@ -2059,46 +1956,93 @@ static void ieee80211_sta_work(struct wo
 
 	ifmgd = &sdata->u.mgd;
 
+	/* first process frames to avoid timing out while a frame is pending */
 	while ((skb = skb_dequeue(&ifmgd->skb_queue)))
 		ieee80211_sta_rx_queued_mgmt(sdata, skb);
 
-	if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
-	    ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE &&
-	    ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE &&
-	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) {
-		queue_delayed_work(local->hw.workqueue, &local->scan_work,
-				   round_jiffies_relative(0));
-		return;
+	/* then process the rest of the work */
+	mutex_lock(&ifmgd->mtx);
+
+	list_for_each_entry(wk, &ifmgd->work_list, list) {
+		if (wk->state != IEEE80211_MGD_STATE_IDLE) {
+			anybusy = true;
+			break;
+		}
 	}
 
-	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) {
-		if (ieee80211_sta_config_auth(sdata))
-			return;
-		clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
-	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))
+	ieee80211_recalc_idle(local);
+
+	if (!anybusy) {
+		mutex_unlock(&ifmgd->mtx);
+
+		if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
+			queue_delayed_work(local->hw.workqueue,
+					   &local->scan_work,
+					   round_jiffies_relative(0));
 		return;
+	}
 
-	ieee80211_recalc_idle(local);
+	list_for_each_entry_safe(wk, tmp, &ifmgd->work_list, list) {
+		if (time_before(jiffies, wk->timeout))
+			continue;
 
-	switch (ifmgd->state) {
-	case IEEE80211_STA_MLME_DISABLED:
-		break;
-	case IEEE80211_STA_MLME_DIRECT_PROBE:
-		ieee80211_direct_probe(sdata);
-		break;
-	case IEEE80211_STA_MLME_AUTHENTICATE:
-		ieee80211_authenticate(sdata);
-		break;
-	case IEEE80211_STA_MLME_ASSOCIATE:
-		ieee80211_associate(sdata);
-		break;
-	case IEEE80211_STA_MLME_ASSOCIATED:
-		ieee80211_associated(sdata);
-		break;
-	default:
-		WARN_ON(1);
-		break;
+		switch (wk->state) {
+		default:
+			WARN_ON(1);
+			/* fall through */
+		case IEEE80211_MGD_STATE_IDLE:
+			/* nothing */
+			rma = RX_MGMT_NONE;
+			break;
+		case IEEE80211_MGD_STATE_PROBE:
+			rma = ieee80211_direct_probe(sdata, wk);
+			break;
+		case IEEE80211_MGD_STATE_AUTH:
+			rma = ieee80211_authenticate(sdata, wk);
+			break;
+		case IEEE80211_MGD_STATE_ASSOC:
+			rma = ieee80211_associate(sdata, wk);
+			break;
+		}
+
+		switch (rma) {
+		case RX_MGMT_NONE:
+			/* no action required */
+			break;
+		case RX_MGMT_CFG80211_AUTH_TO:
+		case RX_MGMT_CFG80211_ASSOC_TO:
+			list_del(&wk->list);
+			list_add(&wk->list, &free_work);
+			wk->tries = rma; /* small abuse but only local */
+			break;
+		default:
+			WARN(1, "unexpected: %d", rma);
+		}
+	}
+
+	mutex_unlock(&ifmgd->mtx);
+
+	list_for_each_entry_safe(wk, tmp, &free_work, list) {
+		switch (wk->tries) {
+		case RX_MGMT_CFG80211_AUTH_TO:
+			cfg80211_send_auth_timeout(sdata->dev,
+						   wk->bss->cbss.bssid,
+						   GFP_KERNEL);
+			break;
+		case RX_MGMT_CFG80211_ASSOC_TO:
+			cfg80211_send_auth_timeout(sdata->dev,
+						   wk->bss->cbss.bssid,
+						   GFP_KERNEL);
+			break;
+		default:
+			WARN(1, "unexpected: %d", wk->tries);
+		}
+
+		list_del(&wk->list);
+		kfree(wk);
 	}
+
+	ieee80211_recalc_idle(local);
 }
 
 static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
@@ -2110,7 +2054,6 @@ static void ieee80211_restart_sta_timer(
 		 */
 		sdata->u.mgd.last_beacon = jiffies;
 
-
 		queue_work(sdata->local->hw.workqueue,
 			   &sdata->u.mgd.work);
 	}
@@ -2152,7 +2095,6 @@ void ieee80211_sta_restart(struct ieee80
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_if_managed *ifmgd;
-	u32 hw_flags;
 
 	ifmgd = &sdata->u.mgd;
 	INIT_WORK(&ifmgd->work, ieee80211_sta_work);
@@ -2164,113 +2106,239 @@ void ieee80211_sta_setup_sdata(struct ie
 		    (unsigned long) sdata);
 	skb_queue_head_init(&ifmgd->skb_queue);
 
+	INIT_LIST_HEAD(&ifmgd->work_list);
+
 	ifmgd->capab = WLAN_CAPABILITY_ESS;
 	ifmgd->flags = 0;
 	if (sdata->local->hw.queues >= 4)
 		ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
 
-	hw_flags = sdata->local->hw.flags;
+	mutex_init(&ifmgd->mtx);
 }
 
-/* configuration hooks */
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)
+/* scan finished notification */
+void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
 {
-	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
 
-	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
-		return;
+	/* Restart STA timers */
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list)
+		ieee80211_restart_sta_timer(sdata);
+	rcu_read_unlock();
+}
 
-	if (WARN_ON(ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED))
-		ieee80211_set_disassoc(sdata, true, true,
-				       WLAN_REASON_DEAUTH_LEAVING);
+int ieee80211_max_network_latency(struct notifier_block *nb,
+				  unsigned long data, void *dummy)
+{
+	s32 latency_usec = (s32) data;
+	struct ieee80211_local *local =
+		container_of(nb, struct ieee80211_local,
+			     network_latency_notifier);
 
-	if (WARN_ON(ifmgd->ssid_len == 0)) {
-		/*
-		 * Only allow association to be started if a valid SSID
-		 * is configured.
-		 */
-		return;
-	}
+	mutex_lock(&local->iflist_mtx);
+	ieee80211_recalc_ps(local, latency_usec);
+	mutex_unlock(&local->iflist_mtx);
 
-	set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
-	queue_work(local->hw.workqueue, &ifmgd->work);
+	return 0;
 }
 
-int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
-			       const char *ie, size_t len)
+/* config hooks */
+int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+		       struct cfg80211_auth_request *req)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	const u8 *ssid;
+	struct ieee80211_mgd_work *wk;
+	u16 auth_alg;
+
+	switch (req->auth_type) {
+	case NL80211_AUTHTYPE_OPEN_SYSTEM:
+		auth_alg = WLAN_AUTH_OPEN;
+		break;
+	case NL80211_AUTHTYPE_SHARED_KEY:
+		auth_alg = WLAN_AUTH_SHARED_KEY;
+		break;
+	case NL80211_AUTHTYPE_FT:
+		auth_alg = WLAN_AUTH_FT;
+		break;
+	case NL80211_AUTHTYPE_NETWORK_EAP:
+		auth_alg = WLAN_AUTH_LEAP;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
 
-	if (len == 0 && ifmgd->extra_ie_len == 0)
-		return -EALREADY;
+	wk = kzalloc(sizeof(*wk) + req->ie_len, GFP_KERNEL);
+	if (!wk)
+		return -ENOMEM;
 
-	if (len == ifmgd->extra_ie_len && ifmgd->extra_ie &&
-	    memcmp(ifmgd->extra_ie, ie, len) == 0)
-		return -EALREADY;
+	wk->bss = (void *)req->bss;
 
-	kfree(ifmgd->extra_ie);
-	if (len == 0) {
-		ifmgd->extra_ie = NULL;
-		ifmgd->extra_ie_len = 0;
-		return 0;
-	}
-	ifmgd->extra_ie = kmalloc(len, GFP_KERNEL);
-	if (!ifmgd->extra_ie) {
-		ifmgd->extra_ie_len = 0;
-		return -ENOMEM;
+	if (req->ie && req->ie_len) {
+		memcpy(wk->ie, req->ie, req->ie_len);
+		wk->ie_len = req->ie_len;
 	}
-	memcpy(ifmgd->extra_ie, ie, len);
-	ifmgd->extra_ie_len = len;
+
+	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
+	memcpy(wk->ssid, ssid + 2, ssid[1]);
+	wk->ssid_len = ssid[1];
+
+	wk->state = IEEE80211_MGD_STATE_PROBE;
+	wk->auth_alg = auth_alg;
+
+	/*
+	 * XXX: if still associated need to tell AP that we're going
+	 *	to sleep and then change channel etc.
+	 */
+	sdata->local->oper_channel = req->bss->channel;
+	ieee80211_hw_config(sdata->local, 0);
+
+	mutex_lock(&ifmgd->mtx);
+	list_add(&wk->list, &sdata->u.mgd.work_list);
+	mutex_unlock(&ifmgd->mtx);
+
+	queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
 	return 0;
 }
 
-int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason)
+int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+			struct cfg80211_assoc_request *req)
 {
-	printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
-	       sdata->dev->name, reason);
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	struct ieee80211_mgd_work *wk, *found = NULL;
+	int i, err;
 
-	ieee80211_set_disassoc(sdata, true, true, reason);
-	return 0;
+	mutex_lock(&ifmgd->mtx);
+
+	list_for_each_entry(wk, &ifmgd->work_list, list) {
+		if (&wk->bss->cbss == req->bss &&
+		    wk->state == IEEE80211_MGD_STATE_IDLE) {
+			found = wk;
+			break;
+		}
+	}
+
+	if (!found) {
+		err = -ENOLINK;
+		goto out;
+	}
+
+	list_del(&found->list);
+
+	wk = krealloc(found, sizeof(*wk) + req->ie_len, GFP_KERNEL);
+	if (!wk) {
+		list_add(&found->list, &ifmgd->work_list);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	list_add(&wk->list, &ifmgd->work_list);
+
+	ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N;
+
+	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
+		if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
+		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
+		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
+			ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+
+	sdata->local->oper_channel = req->bss->channel;
+	ieee80211_hw_config(sdata->local, 0);
+
+	if (req->ie && req->ie_len) {
+		memcpy(wk->ie, req->ie, req->ie_len);
+		wk->ie_len = req->ie_len;
+	} else
+		wk->ie_len = 0;
+
+	if (req->prev_bssid)
+		memcpy(wk->prev_bssid, req->prev_bssid, ETH_ALEN);
+
+	wk->state = IEEE80211_MGD_STATE_ASSOC;
+	wk->tries = 0;
+
+	if (req->use_mfp) {
+		ifmgd->mfp = IEEE80211_MFP_REQUIRED;
+		ifmgd->flags |= IEEE80211_STA_MFP_ENABLED;
+	} else {
+		ifmgd->mfp = IEEE80211_MFP_DISABLED;
+		ifmgd->flags &= ~IEEE80211_STA_MFP_ENABLED;
+	}
+
+	if (req->crypto.control_port)
+		ifmgd->flags |= IEEE80211_STA_CONTROL_PORT;
+	else
+		ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
+
+	queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+
+	err = 0;
+
+ out:
+	mutex_unlock(&ifmgd->mtx);
+	return err;
 }
 
-int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
+int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
+			 struct cfg80211_deauth_request *req)
 {
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+	struct ieee80211_mgd_work *wk;
+	const u8 *bssid = NULL;
 
-	printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
-	       sdata->dev->name, reason);
+	printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
+	       sdata->dev->name, req->reason_code);
+
+	mutex_lock(&ifmgd->mtx);
 
-	if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED))
+	if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) {
+		bssid = req->bss->bssid;
+		ieee80211_set_disassoc(sdata, bssid, true);
+	} else list_for_each_entry(wk, &ifmgd->work_list, list) {
+		if (&wk->bss->cbss == req->bss) {
+			bssid = req->bss->bssid;
+			list_del(&wk->list);
+			kfree(wk);
+			break;
+		}
+	}
+
+	/* cfg80211 should catch this... */
+	if (WARN_ON(!bssid)) {
+		mutex_unlock(&ifmgd->mtx);
 		return -ENOLINK;
+	}
+
+	mutex_unlock(&ifmgd->mtx);
+
+	ieee80211_send_deauth_disassoc(sdata, bssid,
+			IEEE80211_STYPE_DEAUTH, req->reason_code);
 
-	ieee80211_set_disassoc(sdata, false, true, reason);
 	return 0;
 }
 
-/* scan finished notification */
-void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
+int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
+			   struct cfg80211_disassoc_request *req)
 {
-	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-	/* Restart STA timers */
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list)
-		ieee80211_restart_sta_timer(sdata);
-	rcu_read_unlock();
-}
+	printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
+	       sdata->dev->name, req->reason_code);
 
-int ieee80211_max_network_latency(struct notifier_block *nb,
-				  unsigned long data, void *dummy)
-{
-	s32 latency_usec = (s32) data;
-	struct ieee80211_local *local =
-		container_of(nb, struct ieee80211_local,
-			     network_latency_notifier);
+	mutex_lock(&ifmgd->mtx);
 
-	mutex_lock(&local->iflist_mtx);
-	ieee80211_recalc_ps(local, latency_usec);
-	mutex_unlock(&local->iflist_mtx);
+	/* cfg80211 should catch that */
+	if (WARN_ON(&ifmgd->associated->cbss != req->bss)) {
+		mutex_unlock(&ifmgd->mtx);
+		return -ENOLINK;
+	}
+
+	ieee80211_set_disassoc(sdata, req->bss->bssid, false);
+
+	mutex_unlock(&ifmgd->mtx);
 
+	ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
+			IEEE80211_STYPE_DISASSOC, req->reason_code);
 	return 0;
 }
--- wireless-testing.orig/net/mac80211/scan.c	2009-07-07 03:25:45.000000000 +0200
+++ wireless-testing/net/mac80211/scan.c	2009-07-07 03:37:03.000000000 +0200
@@ -121,19 +121,6 @@ ieee80211_bss_info_update(struct ieee802
 	return bss;
 }
 
-void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
-			     int freq, u8 *ssid, u8 ssid_len)
-{
-	struct ieee80211_bss *bss;
-	struct ieee80211_local *local = sdata->local;
-
-	bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
-	if (bss) {
-		cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
-		ieee80211_rx_bss_put(local, bss);
-	}
-}
-
 ieee80211_rx_result
 ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
@@ -324,7 +311,7 @@ void ieee80211_scan_completed(struct iee
 
 		/* Tell AP we're back */
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
+			if (sdata->u.mgd.associated) {
 				ieee80211_scan_ps_disable(sdata);
 				netif_tx_wake_all_queues(sdata->dev);
 			}
@@ -380,7 +367,7 @@ static int ieee80211_start_sw_scan(struc
 				sdata, BSS_CHANGED_BEACON_ENABLED);
 
 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
+			if (sdata->u.mgd.associated) {
 				netif_tx_stop_all_queues(sdata->dev);
 				ieee80211_scan_ps_enable(sdata);
 			}
@@ -440,10 +427,8 @@ static int __ieee80211_start_scan(struct
 
 	if (req != &local->int_scan_req &&
 	    sdata->vif.type == NL80211_IFTYPE_STATION &&
-	    (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE ||
-	     ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
-	     ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) {
-		/* actually wait for the assoc to finish/time out */
+	    !list_empty(&ifmgd->work_list)) {
+		/* actually wait for the work it's doing to finish/time out */
 		set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
 		return 0;
 	}
--- wireless-testing.orig/net/mac80211/rx.c	2009-07-07 03:29:38.000000000 +0200
+++ wireless-testing/net/mac80211/rx.c	2009-07-07 03:37:03.000000000 +0200
@@ -1647,12 +1647,7 @@ static void ieee80211_process_sa_query_r
 
 	if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
 	    compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
-		/* Not from the current AP. */
-		return;
-	}
-
-	if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
-		/* Association in progress; ignore SA Query */
+		/* Not from the current AP or not associated yet. */
 		return;
 	}
 
@@ -1689,7 +1684,6 @@ ieee80211_rx_h_action(struct ieee80211_r
 	struct ieee80211_local *local = rx->local;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
-	struct ieee80211_bss *bss;
 	int len = rx->skb->len;
 
 	if (!ieee80211_is_action(mgmt->frame_control))
@@ -1767,17 +1761,7 @@ ieee80211_rx_h_action(struct ieee80211_r
 			if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
 				return RX_DROP_MONITOR;
 
-			bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
-					   local->hw.conf.channel->center_freq,
-					   sdata->u.mgd.ssid,
-					   sdata->u.mgd.ssid_len);
-			if (!bss)
-				return RX_DROP_MONITOR;
-
-			ieee80211_sta_process_chanswitch(sdata,
-				     &mgmt->u.action.u.chan_switch.sw_elem, bss);
-			ieee80211_rx_bss_put(local, bss);
-			break;
+			return ieee80211_sta_rx_mgmt(sdata, rx->skb);
 		}
 		break;
 	case WLAN_CATEGORY_SA_QUERY:
@@ -2031,13 +2015,8 @@ static int prepare_for_handlers(struct i
 	case NL80211_IFTYPE_STATION:
 		if (!bssid)
 			return 0;
-		if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) {
-			if (!(rx->flags & IEEE80211_RX_IN_SCAN))
-				return 0;
-			rx->flags &= ~IEEE80211_RX_RA_MATCH;
-		} else if (!multicast &&
-			   compare_ether_addr(sdata->dev->dev_addr,
-					      hdr->addr1) != 0) {
+		if (!multicast &&
+		    compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
 			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
--- wireless-testing.orig/net/mac80211/debugfs_netdev.c	2009-07-07 03:37:02.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_netdev.c	2009-07-07 03:37:03.000000000 +0200
@@ -95,29 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx,
 IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
 
 /* STA attributes */
-IEEE80211_IF_FILE(state, u.mgd.state, DEC);
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
-IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
-IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
 IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
-IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
-IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
-IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC);
-IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC);
-IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC);
-
-static ssize_t ieee80211_if_fmt_flags(
-	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-{
-	return scnprintf(buf, buflen, "%s%s%s%s%s\n",
-		 sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
-		 sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
-		 sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
-		 sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
-		 sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
-}
-__IEEE80211_IF_FILE(flags);
 
 /* AP attributes */
 IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
@@ -180,18 +160,9 @@ static void add_sta_files(struct ieee802
 	DEBUGFS_ADD(force_unicast_rateidx, sta);
 	DEBUGFS_ADD(max_ratectrl_rateidx, sta);
 
-	DEBUGFS_ADD(state, sta);
 	DEBUGFS_ADD(bssid, sta);
-	DEBUGFS_ADD(prev_bssid, sta);
-	DEBUGFS_ADD(ssid_len, sta);
 	DEBUGFS_ADD(aid, sta);
 	DEBUGFS_ADD(capab, sta);
-	DEBUGFS_ADD(extra_ie_len, sta);
-	DEBUGFS_ADD(auth_tries, sta);
-	DEBUGFS_ADD(assoc_tries, sta);
-	DEBUGFS_ADD(auth_alg, sta);
-	DEBUGFS_ADD(auth_transaction, sta);
-	DEBUGFS_ADD(flags, sta);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -311,18 +282,9 @@ static void del_sta_files(struct ieee802
 	DEBUGFS_DEL(force_unicast_rateidx, sta);
 	DEBUGFS_DEL(max_ratectrl_rateidx, sta);
 
-	DEBUGFS_DEL(state, sta);
 	DEBUGFS_DEL(bssid, sta);
-	DEBUGFS_DEL(prev_bssid, sta);
-	DEBUGFS_DEL(ssid_len, sta);
 	DEBUGFS_DEL(aid, sta);
 	DEBUGFS_DEL(capab, sta);
-	DEBUGFS_DEL(extra_ie_len, sta);
-	DEBUGFS_DEL(auth_tries, sta);
-	DEBUGFS_DEL(assoc_tries, sta);
-	DEBUGFS_DEL(auth_alg, sta);
-	DEBUGFS_DEL(auth_transaction, sta);
-	DEBUGFS_DEL(flags, sta);
 }
 
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)

-- 


^ permalink raw reply

* [PATCH 1/3] mac80211: remove dead code from mlme
From: Johannes Berg @ 2009-07-07  1:45 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless
In-Reply-To: <20090707014515.024822579@sipsolutions.net>

The ap_capab and last_probe struct members are unused.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 net/mac80211/debugfs_netdev.c |    3 ---
 net/mac80211/ieee80211_i.h    |    4 +---
 net/mac80211/mlme.c           |    2 --
 3 files changed, 1 insertion(+), 8 deletions(-)

--- wireless-testing.orig/net/mac80211/debugfs_netdev.c	2009-07-07 03:29:38.000000000 +0200
+++ wireless-testing/net/mac80211/debugfs_netdev.c	2009-07-07 03:37:02.000000000 +0200
@@ -100,7 +100,6 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MA
 IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
 IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
-IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX);
 IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
 IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
 IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
@@ -186,7 +185,6 @@ static void add_sta_files(struct ieee802
 	DEBUGFS_ADD(prev_bssid, sta);
 	DEBUGFS_ADD(ssid_len, sta);
 	DEBUGFS_ADD(aid, sta);
-	DEBUGFS_ADD(ap_capab, sta);
 	DEBUGFS_ADD(capab, sta);
 	DEBUGFS_ADD(extra_ie_len, sta);
 	DEBUGFS_ADD(auth_tries, sta);
@@ -318,7 +316,6 @@ static void del_sta_files(struct ieee802
 	DEBUGFS_DEL(prev_bssid, sta);
 	DEBUGFS_DEL(ssid_len, sta);
 	DEBUGFS_DEL(aid, sta);
-	DEBUGFS_DEL(ap_capab, sta);
 	DEBUGFS_DEL(capab, sta);
 	DEBUGFS_DEL(extra_ie_len, sta);
 	DEBUGFS_DEL(auth_tries, sta);
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2009-07-07 03:29:38.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h	2009-07-07 03:37:02.000000000 +0200
@@ -268,7 +268,7 @@ struct ieee80211_if_managed {
 	} state;
 
 	u16 aid;
-	u16 ap_capab, capab;
+	u16 capab;
 	u8 *extra_ie; /* to be added to the end of AssocReq */
 	size_t extra_ie_len;
 
@@ -288,7 +288,6 @@ struct ieee80211_if_managed {
 
 	unsigned long request;
 
-	unsigned long last_probe;
 	unsigned long last_beacon;
 
 	unsigned int flags;
@@ -472,7 +471,6 @@ struct ieee80211_sub_if_data {
 			struct dentry *prev_bssid;
 			struct dentry *ssid_len;
 			struct dentry *aid;
-			struct dentry *ap_capab;
 			struct dentry *capab;
 			struct dentry *extra_ie_len;
 			struct dentry *auth_tries;
--- wireless-testing.orig/net/mac80211/mlme.c	2009-07-07 03:36:58.000000000 +0200
+++ wireless-testing/net/mac80211/mlme.c	2009-07-07 03:37:02.000000000 +0200
@@ -879,7 +879,6 @@ static void ieee80211_set_associated(str
 		ieee80211_rx_bss_put(local, bss);
 	}
 
-	ifmgd->last_probe = jiffies;
 	ieee80211_led_assoc(local, 1);
 
 	sdata->vif.bss_conf.assoc = 1;
@@ -1488,7 +1487,6 @@ static void ieee80211_rx_mgmt_assoc_resp
 
 	printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
 	ifmgd->aid = aid;
-	ifmgd->ap_capab = capab_info;
 
 	kfree(ifmgd->assocresp_ies);
 	ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt);

-- 


^ permalink raw reply

* [PATCH 0/3] mac80211 cleanups and improvements
From: Johannes Berg @ 2009-07-07  1:45 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

Here's something that will possibly get FT-ota almost working,
along with some cleanups.

johannes

^ permalink raw reply

* [PATCH] mac80211_hwsim: avoid NULL access
From: Johannes Berg @ 2009-07-07  1:43 UTC (permalink / raw)
  To: John Linville; +Cc: linux-wireless

There's a race condition -- started can be set to true
before channel is set due to the way mac80211 callbacks
currently work (->start should probably pass the channel
we would like to have initially). For now simply add a
check to hwsim to avoid dereferencing the NULL channel
pointer.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 drivers/net/wireless/mac80211_hwsim.c |    1 +
 1 file changed, 1 insertion(+)

--- wireless-testing.orig/drivers/net/wireless/mac80211_hwsim.c	2009-07-07 03:29:38.000000000 +0200
+++ wireless-testing/drivers/net/wireless/mac80211_hwsim.c	2009-07-07 03:37:02.000000000 +0200
@@ -427,6 +427,7 @@ static bool mac80211_hwsim_tx_frame(stru
 			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;



^ permalink raw reply

* Re: [PATCH v2] Fix regression in mesh forwarding path.
From: Johannes Berg @ 2009-07-07  1:40 UTC (permalink / raw)
  To: javier; +Cc: linux-wireless, devel, Andrey Yurovsky
In-Reply-To: <1246929954-15282-1-git-send-email-javier@cozybit.com>

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

On Mon, 2009-07-06 at 18:25 -0700, javier@cozybit.com wrote:
> 
>         while ((skb = skb_dequeue(&mpath->frame_queue)) &&
>                         (mpath->flags & MESH_PATH_ACTIVE))
> -               dev_queue_xmit(skb);
> +               ieee80211_add_pending_skb(mpath->sdata->local, skb);
>  }

?

Hmm, now I'm confused, why not just do

if (mpath->flags & MESH_PATH_ACTIVE)
	ieee80211_add_pending_skbs(mpath->sdata->local,
				   &mpath->frame_queue);
?

johannes

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

^ permalink raw reply

* Re: [PATCH] Fix regression in mesh forwarding path.
From: Javier Cardona @ 2009-07-07  1:35 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, devel, Andrey Yurovsky
In-Reply-To: <1246928780.4652.10.camel@johannes.local>

On Mon, Jul 6, 2009 at 6:06 PM, Johannes Berg<johannes@sipsolutions.net> wrote:
> That does a lot of locking operations -- can you not select the queue
> earlier, and use ieee80211_add_pending_skbs?

Indeed.  Just submitted v2 of the patch.

Thanks!

Javier


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

^ permalink raw reply

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

I have found the bad commit.

$ git bisect good
1e3e6e8fe2f422f75619b1110f78bb638ae905b9 is first bad commit
commit 1e3e6e8fe2f422f75619b1110f78bb638ae905b9
Author: Nick Kossifidis <mick@madwifi-project.org>
Date:   Mon Feb 9 06:15:42 2009 +0200

    ath5k: Disable BMISS interrupts

     * Don't enable BMISS interrupts as we don't handle them yet

     Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>

    Signed-off-by: John W. Linville <linville@tuxdriver.com>

:040000 040000 4a52fc89878d63cdb5da78e78d1ee17a6b5694c0
ff6f1d15f33d1dd3547e03fa191a779b50ad9ed4 M        drivers

Do you still think it would be wise to file a bug report for this
issue. I have yet to try the latest compat-wireless.

On Sun, Jul 5, 2009 at 8:13 AM, Jasin
Colegrove<j.wholesalesupply@gmail.com> wrote:
> Thanks bob for the reply. I did not mean to shout, but someone else
> told me that I should make it very clear that I was not subscribed.
> But, now I am so it doesn't matter :)
>
> I guess I will just wait to file a bug after I get through the bisect
> process and test out the newest compat-wireless drivers. Then I should
> have a more clear picture of the issue and maybe enough technical
> details to file a proper bug report. Thanks again for your time,
> greatly appreciated.
>
> On Thu, Jul 2, 2009 at 11:36 AM, Bob Copeland<me@bobcopeland.com> wrote:
>> On Tue, Jun 30, 2009 at 6:50 PM, Jasin
>> Colegrove<j.wholesalesupply@gmail.com> wrote:
>>> I AM NOT A SUBSCRIBER. Please reply to me directly at this e-mail
>>> address j.wholesalesupply@gmail.com
>>
>> No need to shout -- also common etiquette on Linux kernel lists is
>> to "reply-all" anyway :)
>>
>>> Then I decided to see if it the card was working, So I tried to iwlist
>>> wlan0 scan, it returned the expected results.
>>
>>> I would be glad to offer up as much
>>> information as I can, but I don't have the slightest on how to debug
>>> this issue?
>>
>> So to summarize:
>>
>> 2.6.29 works, 2.6.30 doesn't, ath9k works, ath5k doesn't, userspace
>> setup is unchanged.  ath5k can get scan results (which means RX is
>> working at least some of the time) but dhcp does not.
>>
>> You said you are comfortable with the command line, in that case the
>> easiest way to debug the change is to just bisect the ath5k changes
>> using git.  There were only 50 or so patches since 2.6.29 so you will
>> likely only need to compile the kernel 5 or 6 times.  You can do
>> something like:
>>
>> $ git bisect start v2.6.30 v2.6.29 -- drivers/net/wireless/ath5k
>>
>>> Any help on that issue is much appreciated. Where can I
>>> file the appropriate bug and what information do I need to post from a
>>> technical standpoint.
>>
>> http://bugzilla.kernel.org/ is where you would file it, the information
>> you've already given here is a good start.
>>
>> --
>> Bob Copeland %% www.bobcopeland.com
>>
>

^ permalink raw reply

* [PATCH v2] Fix regression in mesh forwarding path.
From: javier @ 2009-07-07  1:25 UTC (permalink / raw)
  To: linux-wireless; +Cc: devel, johannes, Javier Cardona, Andrey Yurovsky
In-Reply-To: <1246928780.4652.10.camel@johannes.local>

From: Javier Cardona <javier@cozybit.com>

The removal of the master netdev broke the mesh forwarding path.  This patch
fixes it by using the new internal 'pending' queue.

As a result of this change, mesh forwarding no longer does the inefficient
802.11 -> 802.3 -> 802.11 conversion that was done before.

Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
---
 net/mac80211/mesh_hwmp.c    |    3 ++-
 net/mac80211/mesh_pathtbl.c |    3 ++-
 net/mac80211/rx.c           |   17 +++++++++++++++--
 net/mac80211/tx.c           |    3 ---
 4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f49ef28..c31fe79 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		mesh_path_add(dst_addr, sdata);
 		mpath = mesh_path_lookup(dst_addr, sdata);
 		if (!mpath) {
-			dev_kfree_skb(skb);
 			sdata->u.mesh.mshstats.dropped_frames_no_route++;
 			err = -ENOSPC;
 			goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		memcpy(hdr->addr1, mpath->next_hop->sta.addr,
 				ETH_ALEN);
 	} else {
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
 			/* Start discovery only if it is not running yet */
 			mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 			skb_unlink(skb_to_free, &mpath->frame_queue);
 		}
 
+		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 		skb_queue_tail(&mpath->frame_queue, skb);
 		if (skb_to_free)
 			mesh_path_discard_frame(skb_to_free, sdata);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3c72557..e716e7d 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "wme.h"
 #include "mesh.h"
 
 /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
@@ -482,7 +483,7 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
 
 	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
 			(mpath->flags & MESH_PATH_ACTIVE))
-		dev_queue_xmit(skb);
+		ieee80211_add_pending_skb(mpath->sdata->local, skb);
 }
 
 /**
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 91747be..1a22636 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1485,10 +1485,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 	unsigned int hdrlen;
 	struct sk_buff *skb = rx->skb, *fwd_skb;
 	struct ieee80211_local *local = rx->local;
+	struct ieee80211_sub_if_data *sdata;
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
 	if (!ieee80211_is_data(hdr->frame_control))
 		return RX_CONTINUE;
@@ -1498,10 +1500,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		return RX_DROP_MONITOR;
 
 	if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
-		struct ieee80211_sub_if_data *sdata;
 		struct mesh_path *mppath;
 
-		sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 		rcu_read_lock();
 		mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
 		if (!mppath) {
@@ -1547,6 +1547,19 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 			fwd_skb->iif = rx->dev->ifindex;
 			ieee80211_select_queue(local, fwd_skb);
+			if (is_multicast_ether_addr(fwd_hdr->addr3))
+				memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+						ETH_ALEN);
+			else {
+				int err = mesh_nexthop_lookup(fwd_skb, sdata);
+				/* Failed to immediately resolve next hop:
+				 * fwded frame was dropped or will be added
+				 * later to the pending skb queue.  */
+				if (err)
+					return RX_DROP_MONITOR;
+			}
+			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+						     fwded_frames);
 			ieee80211_add_pending_skb(local, fwd_skb);
 		}
 	}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 66d9a42..969a4b2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1399,9 +1399,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 				dev_put(sdata->dev);
 				return;
 			}
-		if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-						     fwded_frames);
 	} else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
 		int hdrlen;
 		u16 len_rthdr;
-- 
1.5.4.3


^ permalink raw reply related

* Re: 2.6.31-rc2: Reported regressions from 2.6.30
From: Andres Freund @ 2009-07-07  1:25 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Linux Kernel Mailing List, Adrian Bunk, Andrew Morton,
	Linus Torvalds, Natalie Protasevich, Kernel Testers List,
	Network Development, Linux ACPI, Linux PM List, Linux SCSI List,
	Linux Wireless List, DRI
In-Reply-To: <35kKlbXMqWN.A.RXD.D0oUKB@chimera>

Hi Rafael,

On Tuesday 07 July 2009 01:42:09 Rafael J. Wysocki wrote:
> If you know of any other unresolved regressions from 2.6.30, please let me
> know either and I'll add them to the list.  Also, please let me know if any
> of the entries below are invalid.
There is also http://lkml.org/lkml/2009/6/30/398 : Soft-Lockup/Race in 
networking in 2.6.31-rc1+195 (possibly caused by netem)


Andres

^ permalink raw reply

* Re: [PATCH] Fix regression in mesh forwarding path.
From: Johannes Berg @ 2009-07-07  1:06 UTC (permalink / raw)
  To: javier; +Cc: linux-wireless, devel, Andrey Yurovsky
In-Reply-To: <1246927941-27148-1-git-send-email-javier@cozybit.com>

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

On Mon, 2009-07-06 at 17:52 -0700, javier@cozybit.com wrote:
> From: Javier Cardona <javier@cozybit.com>
> 
> The removal of the master netdev broke the mesh forwarding path.  This patch
> fixes it by using the new internal 'pending' queue.

Sorry, never tested mesh recently.

> As a result of this change, mesh forwarding no longer does the inefficient
> 802.11 -> 802.3 -> 802.11 conversion that was done before.

That sounds good!

>  	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
> -			(mpath->flags & MESH_PATH_ACTIVE))
> -		dev_queue_xmit(skb);
> +			(mpath->flags & MESH_PATH_ACTIVE)) {
> +		ieee80211_select_queue(mpath->sdata->local, skb);
> +		ieee80211_add_pending_skb(mpath->sdata->local, skb);
> +	}

That does a lot of locking operations -- can you not select the queue
earlier, and use ieee80211_add_pending_skbs?

johannes

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

^ permalink raw reply

* [PATCH] Fix regression in mesh forwarding path.
From: javier @ 2009-07-07  0:52 UTC (permalink / raw)
  To: linux-wireless; +Cc: devel, johannes, Javier Cardona, Andrey Yurovsky
In-Reply-To: <1246927662-25461-1-git-send-email-javier@cozybit.com>

From: Javier Cardona <javier@cozybit.com>

The removal of the master netdev broke the mesh forwarding path.  This patch
fixes it by using the new internal 'pending' queue.

As a result of this change, mesh forwarding no longer does the inefficient
802.11 -> 802.3 -> 802.11 conversion that was done before.

Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
---
 net/mac80211/mesh_hwmp.c    |    3 ++-
 net/mac80211/mesh_pathtbl.c |    7 +++++--
 net/mac80211/rx.c           |   17 +++++++++++++++--
 net/mac80211/tx.c           |    3 ---
 4 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f49ef28..c31fe79 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		mesh_path_add(dst_addr, sdata);
 		mpath = mesh_path_lookup(dst_addr, sdata);
 		if (!mpath) {
-			dev_kfree_skb(skb);
 			sdata->u.mesh.mshstats.dropped_frames_no_route++;
 			err = -ENOSPC;
 			goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		memcpy(hdr->addr1, mpath->next_hop->sta.addr,
 				ETH_ALEN);
 	} else {
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
 			/* Start discovery only if it is not running yet */
 			mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 			skb_unlink(skb_to_free, &mpath->frame_queue);
 		}
 
+		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 		skb_queue_tail(&mpath->frame_queue, skb);
 		if (skb_to_free)
 			mesh_path_discard_frame(skb_to_free, sdata);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3c72557..ac7d823 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "wme.h"
 #include "mesh.h"
 
 /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
@@ -481,8 +482,10 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
 	struct sk_buff *skb;
 
 	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
-			(mpath->flags & MESH_PATH_ACTIVE))
-		dev_queue_xmit(skb);
+			(mpath->flags & MESH_PATH_ACTIVE)) {
+		ieee80211_select_queue(mpath->sdata->local, skb);
+		ieee80211_add_pending_skb(mpath->sdata->local, skb);
+	}
 }
 
 /**
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 91747be..e3b58a4 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1485,10 +1485,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 	unsigned int hdrlen;
 	struct sk_buff *skb = rx->skb, *fwd_skb;
 	struct ieee80211_local *local = rx->local;
+	struct ieee80211_sub_if_data *sdata;
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
 	if (!ieee80211_is_data(hdr->frame_control))
 		return RX_CONTINUE;
@@ -1498,10 +1500,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		return RX_DROP_MONITOR;
 
 	if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
-		struct ieee80211_sub_if_data *sdata;
 		struct mesh_path *mppath;
 
-		sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 		rcu_read_lock();
 		mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
 		if (!mppath) {
@@ -1546,6 +1546,19 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 			memset(info, 0, sizeof(*info));
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 			fwd_skb->iif = rx->dev->ifindex;
+			if (is_multicast_ether_addr(fwd_hdr->addr3))
+				memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+						ETH_ALEN);
+			else {
+				int err = mesh_nexthop_lookup(fwd_skb, sdata);
+				/* Failed to immediately resolve next hop:
+				 * fwded frame was dropped or will be added
+				 * later to the pending skb queue.  */
+				if (err)
+					return RX_DROP_MONITOR;
+			}
+			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+						     fwded_frames);
 			ieee80211_select_queue(local, fwd_skb);
 			ieee80211_add_pending_skb(local, fwd_skb);
 		}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 66d9a42..969a4b2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1399,9 +1399,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 				dev_put(sdata->dev);
 				return;
 			}
-		if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-						     fwded_frames);
 	} else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
 		int hdrlen;
 		u16 len_rthdr;
-- 
1.5.4.3


^ permalink raw reply related

* [PATCH] Fix regression in mesh forwarding path.
From: javier @ 2009-07-07  0:47 UTC (permalink / raw)
  To: linux-wireless; +Cc: devel, Javier Cardona

From: Javier Cardona <javier@cozybit.com>

The removal of the master netdev broke the mesh forwarding path.  This patch
fixes it by using the new internal 'pending' queue.

As a result of this change, mesh forwarding no longer does the inefficient
802.11 -> 802.3 -> 802.11 conversion that was done before.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh_hwmp.c    |    3 ++-
 net/mac80211/mesh_pathtbl.c |    7 +++++--
 net/mac80211/rx.c           |   17 +++++++++++++++--
 net/mac80211/tx.c           |    3 ---
 4 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index f49ef28..c31fe79 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -784,7 +784,6 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		mesh_path_add(dst_addr, sdata);
 		mpath = mesh_path_lookup(dst_addr, sdata);
 		if (!mpath) {
-			dev_kfree_skb(skb);
 			sdata->u.mesh.mshstats.dropped_frames_no_route++;
 			err = -ENOSPC;
 			goto endlookup;
@@ -804,6 +803,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		memcpy(hdr->addr1, mpath->next_hop->sta.addr,
 				ETH_ALEN);
 	} else {
+		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
 			/* Start discovery only if it is not running yet */
 			mesh_queue_preq(mpath, PREQ_Q_F_START);
@@ -815,6 +815,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 			skb_unlink(skb_to_free, &mpath->frame_queue);
 		}
 
+		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 		skb_queue_tail(&mpath->frame_queue, skb);
 		if (skb_to_free)
 			mesh_path_discard_frame(skb_to_free, sdata);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 3c72557..ac7d823 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -14,6 +14,7 @@
 #include <linux/string.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "wme.h"
 #include "mesh.h"
 
 /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
@@ -481,8 +482,10 @@ void mesh_path_tx_pending(struct mesh_path *mpath)
 	struct sk_buff *skb;
 
 	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
-			(mpath->flags & MESH_PATH_ACTIVE))
-		dev_queue_xmit(skb);
+			(mpath->flags & MESH_PATH_ACTIVE)) {
+		ieee80211_select_queue(mpath->sdata->local, skb);
+		ieee80211_add_pending_skb(mpath->sdata->local, skb);
+	}
 }
 
 /**
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 91747be..e3b58a4 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1485,10 +1485,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 	unsigned int hdrlen;
 	struct sk_buff *skb = rx->skb, *fwd_skb;
 	struct ieee80211_local *local = rx->local;
+	struct ieee80211_sub_if_data *sdata;
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 	mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 
 	if (!ieee80211_is_data(hdr->frame_control))
 		return RX_CONTINUE;
@@ -1498,10 +1500,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		return RX_DROP_MONITOR;
 
 	if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
-		struct ieee80211_sub_if_data *sdata;
 		struct mesh_path *mppath;
 
-		sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 		rcu_read_lock();
 		mppath = mpp_path_lookup(mesh_hdr->eaddr2, sdata);
 		if (!mppath) {
@@ -1546,6 +1546,19 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 			memset(info, 0, sizeof(*info));
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 			fwd_skb->iif = rx->dev->ifindex;
+			if (is_multicast_ether_addr(fwd_hdr->addr3))
+				memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+						ETH_ALEN);
+			else {
+				int err = mesh_nexthop_lookup(fwd_skb, sdata);
+				/* Failed to immediately resolve next hop:
+				 * fwded frame was dropped or will be added
+				 * later to the pending skb queue.  */
+				if (err)
+					return RX_DROP_MONITOR;
+			}
+			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
+						     fwded_frames);
 			ieee80211_select_queue(local, fwd_skb);
 			ieee80211_add_pending_skb(local, fwd_skb);
 		}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 66d9a42..969a4b2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1399,9 +1399,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 				dev_put(sdata->dev);
 				return;
 			}
-		if (memcmp(sdata->dev->dev_addr, hdr->addr4, ETH_ALEN) != 0)
-			IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
-						     fwded_frames);
 	} else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
 		int hdrlen;
 		u16 len_rthdr;
-- 
1.5.4.3


^ permalink raw reply related

* 2.6.31-rc2: Reported regressions 2.6.29 -> 2.6.30
From: Rafael J. Wysocki @ 2009-07-06 23:57 UTC (permalink / raw)
  To: Linux Kernel Mailing List
  Cc: Andrew Morton, Linus Torvalds, Natalie Protasevich,
	Kernel Testers List, Network Development, Linux ACPI,
	Linux PM List, Linux SCSI List, Linux Wireless List, DRI

This message contains a list of some regressions introduced between 2.6.29 and
2.6.30, for which there are no fixes in the mainline I know of.  If any of them
have been fixed already, please let me know.

If you know of any other unresolved regressions introduced between 2.6.29
and 2.6.30, please let me know either and I'll add them to the list.
Also, please let me know if any of the entries below are invalid.

Each entry from the list will be sent additionally in an automatic reply to
this message with CCs to the people involved in reporting and handling the
issue.


Listed regressions statistics:

  Date          Total  Pending  Unresolved
  ----------------------------------------
  2009-07-07      138       50          46
  2009-06-29      133       46          43
  2009-06-07      110       35          31
  2009-05-31      100       32          27
  2009-05-24       92       34          27
  2009-05-16       81       36          33
  2009-04-25       55       36          26
  2009-04-17       37       35          28


Unresolved regressions
----------------------

Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13694
Subject		: i915 phantom TV
Submitter	: Maciek Józiewicz <mjoziew@gmail.com>
Date		: 2009-07-02 12:26 (5 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13682
Subject		: The webcam stopped working when upgrading from 2.6.29 to 2.6.30
Submitter	: Nathanael Schaeffer <nathanael.schaeffer@gmail.com>
Date		: 2009-06-30 13:34 (7 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13681
Subject		: A number of usb Devices causes Oops messages and kernel panics.
Submitter	: Alexander Kaltsas <alexkaltsas@gmail.com>
Date		: 2009-06-30 13:06 (7 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13669
Subject		: Kernel bug with dock driver
Submitter	: Joerg Platte <jplatte@naasa.net>
Date		: 2009-06-14 21:00 (23 days old)
References	: http://lkml.org/lkml/2009/6/14/216
Handled-By	: Henrique de Moraes Holschuh <hmh@hmh.eng.br>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13668
Subject		: Can't boot 2.6.30 powerpc kernel under qemu.
Submitter	: Rob Landley <rob@landley.net>
Date		: 2009-06-27 18:08 (10 days old)
References	: http://lkml.org/lkml/2009/6/27/159


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13660
Subject		: Crashes during boot on 2.6.30 / 2.6.31-rc, random programs
Submitter	: Joao Correia <joaomiguelcorreia@gmail.com>
Date		: 2009-06-27 16:07 (10 days old)
References	: http://lkml.org/lkml/2009/6/27/95


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13651
Subject		: Anyone know what happened with PC speaker in 2.6.30?
Submitter	: Michael Tokarev <mjt@tls.msk.ru>
Date		: 2009-06-15 14:41 (22 days old)
References	: http://marc.info/?l=linux-kernel&m=124507695427817&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13648
Subject		: nfsd: page allocation failure
Submitter	: Justin Piszcz <jpiszcz@lucidpixels.com>
Date		: 2009-06-22 12:08 (15 days old)
References	: http://lkml.org/lkml/2009/6/22/309


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13647
Subject		: fb/mmap lockdep report.
Submitter	: Dave Jones <davej@redhat.com>
Date		: 2009-06-21 13:33 (16 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=513adb58685615b0b1d47a3f0d40f5352beff189
References	: http://lkml.org/lkml/2009/6/21/90
		  http://lkml.org/lkml/2009/6/21/122


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13646
Subject		: warn_on tty_io.c, broken bluetooth
Submitter	: Pavel Machek <pavel@ucw.cz>
Date		: 2009-06-19 17:05 (18 days old)
References	: http://lkml.org/lkml/2009/6/19/187


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13644
Subject		: hibernation/swsusp lockup due to acpi-cpufreq
Submitter	: Johannes Stezenbach <js@sig21.net>
Date		: 2009-06-16 01:27 (21 days old)
References	: http://lkml.org/lkml/2009/6/15/630
		  http://lkml.org/lkml/2009/6/29/504
Handled-By	: Rafael J. Wysocki <rjw@sisk.pl>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13638
Subject		: rt2870 driver is broken for (some) cards
Submitter	: jakob gruber <jakob.gruber@kabelnet.at>
Date		: 2009-06-27 17:33 (10 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13634
Subject		: [drm:drm_wait_vblank] *ERROR* failed to acquire vblank counter, -22
Submitter	: Cijoml Cijomlovic Cijomlov <cijoml@volny.cz>
Date		: 2009-06-27 07:02 (10 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13624
Subject		: usb: wrong autosuspend initialization
Submitter	:  <list@phuk.ath.cx>
Date		: 2009-06-25 18:18 (12 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13621
Subject		: xfs hangs with assertion failed
Submitter	: Johannes Engel <jcnengel@googlemail.com>
Date		: 2009-06-25 10:07 (12 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13620
Subject		: acpi_enforce_resources broken - conflicting i2c module loaded on some EeePCs
Submitter	: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Date		: 2009-06-25 08:31 (12 days old)
References	: <http://lists.alioth.debian.org/pipermail/debian-eeepc-devel/2009-June/002316.html>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13583
Subject		: pdflush uses 5% CPU on otherwise idle system
Submitter	: Paul Martin <pm@debian.org>
Date		: 2009-06-19 13:33 (18 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13581
Subject		: ath9k doesn't work with newer kernels
Submitter	: Matteo <rootkit85@yahoo.it>
Date		: 2009-06-19 12:04 (18 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13564
Subject		: random general protection fault at boot time caused by khubd.
Submitter	: Pauli <suokkos@gmail.com>
Date		: 2009-06-18 12:44 (19 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13558
Subject		: Tracelog during resume
Submitter	: Cijoml Cijomlovic Cijomlov <cijoml@volny.cz>
Date		: 2009-06-17 11:32 (20 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13554
Subject		: linux-image-2.6.30-1-686, KMS enabled: black screen, no X window
Submitter	: Jos van Wolput <wolput@onsneteindhoven.nl>
Date		: 2009-06-17 06:28 (20 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13518
Subject		: slab grows with NFS write activity.
Submitter	: Andrew Randrianasulu <randrik@mail.ru>
Date		: 2009-06-12 09:51 (25 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13514
Subject		: acer_wmi causes stack corruption
Submitter	: Rus <harbour@sfinx.od.ua>
Date		: 2009-06-12 08:13 (25 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13512
Subject		: D43 on 2.6.30 doesn't suspend anymore
Submitter	: Daniel Smolik <marvin@mydatex.cz>
Date		: 2009-06-11 20:12 (26 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13502
Subject		: GPE storm causes polling mode, which causes /proc/acpi/battery read to take 4 seconds - MacBookPro4,1
Submitter	:  <sveina@gmail.com>
Date		: 2009-06-10 20:04 (27 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13472
Subject		: Oops with minicom and USB serial
Submitter	: Peter Chubb <peterc@gelato.unsw.edu.au>
Date		: 2009-06-05 1:37 (32 days old)
References	: http://marc.info/?l=linux-kernel&m=124416901026700&w=4
Handled-By	: Alan Stern <stern@rowland.harvard.edu>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13471
Subject		: Loading parport_pc kills the keyboard if ACPI is enabled
Submitter	: Ozan Çağlayan <ozan@pardus.org.tr>
Date		: 2009-06-04 9:12 (33 days old)
References	: http://marc.info/?l=linux-kernel&m=124410667532558&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13424
Subject		: possible deadlock when doing governor switching
Submitter	: Shaohua Li <shaohua.li@intel.com>
Date		: 2009-05-31 16:36 (37 days old)
References	: http://www.spinics.net/lists/cpufreq/msg00711.html
		  http://lkml.org/lkml/2009/6/28/405
Handled-By	: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13408
Subject		: Performance regression in 2.6.30-rc7
Submitter	: Diego Calleja <diegocg@gmail.com>
Date		: 2009-05-30 18:51 (38 days old)
References	: http://lkml.org/lkml/2009/5/30/146


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13407
Subject		: adb trackpad disappears after suspend to ram
Submitter	: Jan Scholz <scholz@fias.uni-frankfurt.de>
Date		: 2009-05-28 7:59 (40 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=2ed8d2b3a81bdbb0418301628ccdb008ac9f40b7
References	: http://marc.info/?l=linux-kernel&m=124349762314976&w=4
Handled-By	: Rafael J. Wysocki <rjw@sisk.pl>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13401
Subject		: pktcdvd writing is really slow with CFQ scheduler (bisected)
Submitter	: Laurent Riffard <laurent.riffard@free.fr>
Date		: 2009-05-28 18:43 (40 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13374
Subject		: reiserfs blocked for more than 120secs
Submitter	: Harald Dunkel <harald.dunkel@t-online.de>
Date		: 2009-05-23 8:52 (45 days old)
References	: http://marc.info/?l=linux-kernel&m=124306880410811&w=4
		  http://lkml.org/lkml/2009/5/29/389


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13373
Subject		: fbcon, intelfb, i915: INFO: possible circular locking dependency detected
Submitter	: Miles Lane <miles.lane@gmail.com>
Date		: 2009-05-23 5:08 (45 days old)
References	: http://marc.info/?l=linux-kernel&m=124305538130702&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13362
Subject		: rt2x00: slow wifi with correct basic rate bitmap
Submitter	: Alejandro Riveira <ariveira@gmail.com>
Date		: 2009-05-22 13:32 (46 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13351
Subject		: 2.6.30 corrupts my system after suspend resume with readonly mounted hard disk
Submitter	:  <unggnu@googlemail.com>
Date		: 2009-05-20 14:09 (48 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=78a8b35bc7abf8b8333d6f625e08c0f7cc1c3742
Handled-By	: Yinghai Lu <yinghai@kernel.org>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13341
Subject		: Random Oops at boot at loading ip6tables rules
Submitter	:  <patrick@ostenberg.de>
Date		: 2009-05-19 09:08 (49 days old)
Handled-By	: Rusty Russell <rusty@rustcorp.com.au>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13337
Subject		: [post 2.6.29 regression] hang during suspend of b44/b43 modules
Submitter	: Tomas Janousek <tomi@nomi.cz>
Date		: 2009-05-18 10:59 (50 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13328
Subject		: b44: eth0: BUG! Timeout waiting for bit 00000002 of register 42c to clear.
Submitter	: Francis Moreau <francis.moro@gmail.com>
Date		: 2009-05-03 16:22 (65 days old)
References	: http://marc.info/?l=linux-kernel&m=124136778012280&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13319
Subject		: Page allocation failures with b43 and p54usb
Submitter	: Larry Finger <Larry.Finger@lwfinger.net>
Date		: 2009-04-29 21:01 (69 days old)
References	: http://marc.info/?l=linux-kernel&m=124103897101088&w=4
		  http://lkml.org/lkml/2009/6/7/136
Handled-By	: Johannes Berg <johannes@sipsolutions.net>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13318
Subject		: AGP doesn't work anymore on nforce2
Submitter	: Karsten Mehrhoff <kawime@gmx.de>
Date		: 2009-04-30 8:51 (68 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=59de2bebabc5027f93df999d59cc65df591c3e6e
References	: http://marc.info/?l=linux-kernel&m=124108156417560&w=4
Handled-By	: Shaohua Li <shaohua.li@intel.com>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13306
Subject		: hibernate slow on _second_ run
Submitter	: Johannes Berg <johannes@sipsolutions.net>
Date		: 2009-05-14 09:34 (54 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13277
Subject		: 2.6.30 regression - hang on 2nd resume - bisected - Thinkpad X40
Submitter	: Daniel Vetter <daniel@ffwll.ch>
Date		: 2009-05-11 10:08 (57 days old)
Handled-By	: Len Brown <len.brown@intel.com>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13219
Subject		: Intel 440GX: Since kernel 2.6.30-rc1, computers hangs randomly but not with kernel <= 2.6.29.4
Submitter	: David Hill <hilld@binarystorm.net>
Date		: 2009-05-01 16:57 (67 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13179
Subject		: CD-R: wodim intermittent failures
Submitter	: Andy Isaacson <adi@hexapodia.org>
Date		: 2009-04-21 1:52 (77 days old)
References	: http://marc.info/?l=linux-kernel&m=124027879214231&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13119
Subject		: Trouble with make-install from a NFS mount
Submitter	: Gregory Haskins <ghaskins@novell.com>
Date		: 2009-04-14 21:32 (84 days old)
References	: http://marc.info/?l=linux-kernel&m=123974482327044&w=4
Handled-By	: H. Peter Anvin <hpa@zytor.com>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13109
Subject		: High latency on /sys/class/thermal
Submitter	: Tiago Simões Batista <tiagosbatista@gmail.com>
Date		: 2009-04-11 14:56 (87 days old)
References	: http://marc.info/?l=linux-kernel&m=123946182301248&w=4
Handled-By	: Zhang Rui <rui.zhang@intel.com>
		  Alexey Starikovskiy <astarikovskiy@suse.de>


Regressions with patches
------------------------

Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13663
Subject		: suspend to ram regression (IDE related)
Submitter	: Etienne Basset <etienne.basset@numericable.fr>
Date		: 2009-06-26 17:40 (11 days old)
References	: http://lkml.org/lkml/2009/6/26/242
		  http://lkml.org/lkml/2009/6/29/126
Handled-By	: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Patch		: http://patchwork.kernel.org/patch/32719/


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13649
Subject		: Bad page state in process with various applications
Submitter	: Maxim Levitsky <maximlevitsky@gmail.com>
Date		: 2009-06-20 15:27 (17 days old)
References	: http://marc.info/?l=linux-mm&m=124551168828090&w=4
Handled-By	: Mel Gorman <mel@csn.ul.ie>
Patch		: http://patchwork.kernel.org/patch/33130/


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13475
Subject		: suspend/hibernate lockdep warning
Submitter	: Dave Young <hidave.darkstar@gmail.com>
Date		: 2009-06-02 10:00 (35 days old)
References	: http://marc.info/?l=linux-kernel&m=124393723321241&w=4
Handled-By	: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Patch		: http://patchwork.kernel.org/patch/28660/


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13389
Subject		: Warning 'Invalid throttling state, reset' gets displayed when it should not be
Submitter	: Frans Pop <elendil@planet.nl>
Date		: 2009-05-26 15:24 (42 days old)
Handled-By	: Frans Pop <elendil@planet.nl>
Patch		: http://bugzilla.kernel.org/attachment.cgi?id=21671
		  http://bugzilla.kernel.org/attachment.cgi?id=21672


For details, please visit the bug entries and follow the links given in
references.

As you can see, there is a Bugzilla entry for each of the listed regressions.
There also is a Bugzilla entry used for tracking the regressions introduced
between 2.6.29 and 2.6.30, unresolved as well as resolved, at:

http://bugzilla.kernel.org/show_bug.cgi?id=13070

Please let me know if there are any Bugzilla entries that should be added to
the list in there.

Thanks,
Rafael


^ permalink raw reply

* 2.6.31-rc2: Reported regressions from 2.6.30
From: Rafael J. Wysocki @ 2009-07-06 23:42 UTC (permalink / raw)
  To: Linux Kernel Mailing List
  Cc: Adrian Bunk, Andrew Morton, Linus Torvalds, Natalie Protasevich,
	Kernel Testers List, Network Development, Linux ACPI,
	Linux PM List, Linux SCSI List, Linux Wireless List, DRI

[NOTE: I'll be traveling next week, so there won't be a summary report.]

This message contains a list of some regressions from 2.6.30, for which there
are no fixes in the mainline I know of.  If any of them have been fixed already,
please let me know.

If you know of any other unresolved regressions from 2.6.30, please let me know
either and I'll add them to the list.  Also, please let me know if any of the
entries below are invalid.

Each entry from the list will be sent additionally in an automatic reply to
this message with CCs to the people involved in reporting and handling the
issue.


Listed regressions statistics:

  Date          Total  Pending  Unresolved
  ----------------------------------------
  2009-07-07       35       25          21
  2009-06-29       22       22          15


Unresolved regressions
----------------------

Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13733
Subject		: 2.6.31-rc2: irq 16: nobody cared
Submitter	: Niel Lambrechts <niel.lambrechts@gmail.com>
Date		: 2009-07-06 18:32 (1 days old)
References	: http://marc.info/?l=linux-kernel&m=124690524027166&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13732
Subject		: tty layer instabilities
Submitter	: Mikael Pettersson <mikpe@it.uu.se>
Date		: 2009-07-06 13:43 (1 days old)
References	: http://marc.info/?l=linux-kernel&m=124688781732419&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13731
Subject		: Inconsistent {IN-RECLAIM_FS-W} -> {RECLAIM_FS-ON-W} usage.
Submitter	: Miles Lane <miles.lane@gmail.com>
Date		: 2009-07-06 4:22 (1 days old)
References	: http://marc.info/?l=linux-kernel&m=124685417325348&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13730
Subject		: hitting lockdep limits...
Submitter	: Daniel J Blueman <daniel.blueman@gmail.com>
Date		: 2009-07-05 18:19 (2 days old)
References	: http://marc.info/?l=linux-kernel&m=124681799023782&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13729
Subject		: kernel BUG at fs/notify/notification.c:93!
Submitter	: Mikko C. <mikko.cal@gmail.com>
Date		: 2009-06-04 10:16 (33 days old)
References	: http://lkml.org/lkml/2009/7/4/12
Handled-By	: Eric Paris <eparis@redhat.com>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13728
Subject		: 2.6.31-rc2 soft lockups, RPC-related
Submitter	: Paul Collins <paul@burly.ondioline.org>
Date		: 2009-07-05 7:17 (2 days old)
References	: http://marc.info/?l=linux-kernel&m=124677884816794&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13727
Subject		: Cannot Recognize Empty DVD Media
Submitter	: Tarkan Erimer <tarkan.erimer@turknet.net.tr>
Date		: 2009-07-02 16:23 (5 days old)
References	: http://lkml.org/lkml/2009/7/2/178


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13726
Subject		: fio sync read 4k block size 35% regression
Submitter	: Zhang, Yanmin <yanmin_zhang@linux.intel.com>
Date		: 2009-07-01 11:25 (6 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=51daa88ebd8e0d437289f589af29d4b39379ea76
References	: http://lkml.org/lkml/2009/6/30/679
Handled-By	: Wu Fengguang <fengguang.wu@intel.com>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13716
Subject		: The AIC-7892P controller does not work any more
Submitter	: Andrej Podzimek <andrej@podzimek.org>
Date		: 2009-07-05 19:23 (2 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13700
Subject		: usb error flood in dmesg, makes kde use plenty of cpu - bisected
Submitter	: jouni susiluoto <jouni.susiluoto@helsinki.fi>
Date		: 2009-07-03 21:13 (4 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13690
Subject		: nodes_clear cause hugepage unusable on non-NUMA machine
Submitter	: alexs <alex.shi@intel.com>
Date		: 2009-07-02 01:22 (5 days old)


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13673
Subject		: HIGHMEM64G causes hang in PCI init on 32-bit x86
Submitter	: Mikael Pettersson <mikpe@it.uu.se>
Date		: 2009-06-26 15:59 (11 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=95ee14e4379c5e19c0897c872350570402014742
References	: http://marc.info/?l=linux-pci&m=124615181602643&w=4
Handled-By	: H. Peter Anvin <hpa@zytor.com>


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13667
Subject		: drm: display arifacts when X.Org is stopped
Submitter	: Frans Pop <elendil@planet.nl>
Date		: 2009-06-27 18:52 (10 days old)
References	: http://lkml.org/lkml/2009/6/27/105


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13666
Subject		: WARNING: at mm/page_alloc.c:1743 __alloc_pages_nodemask
Submitter	: Thomas Meyer <thomas@m3y3r.de>
Date		: 2009-06-27 16:15 (10 days old)
References	: http://lkml.org/lkml/2009/6/27/75


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13661
Subject		: warning in smp_call_function_single while S2R
Submitter	: Thomas Meyer <thomas@m3y3r.de>
Date		: 2009-06-27 17:12 (10 days old)
References	: http://lkml.org/lkml/2009/6/27/80


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13657
Subject		: Linux-2.6.31-rc1 Fails To Recognize Some USB Disks
Submitter	: Tarkan Erimer <tarkan.erimer@turknet.net.tr>
Date		: 2009-06-26 10:03 (11 days old)
References	: http://lkml.org/lkml/2009/6/26/34


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13656
Subject		: 2.6.31-rc1 crashes randomly on my Machine.
Submitter	: Zeno Davatz <zdavatz@gmail.com>
Date		: 2009-06-26 08:56 (11 days old)
References	: http://lkml.org/lkml/2009/6/26/27


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13652
Subject		: scheduling while atomic: pptpgw
Submitter	: Sergey Senozhatsky <sergey.senozhatsky@mail.by>
Date		: 2009-06-19 21:15 (18 days old)
References	: http://lkml.org/lkml/2009/6/19/237


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13650
Subject		: Problem with alloc_arch_preferred_bootmem() on powerpc
Submitter	: Sean MacLennan <smaclennan@pikatech.com>
Date		: 2009-06-20 19:48 (17 days old)
References	: http://marc.info/?l=linuxppc-embedded&m=124552732411775&w=4


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13645
Subject		: NULL pointer dereference at (null) (level2_spare_pgt)
Submitter	: poornima nayak <mpnayak@linux.vnet.ibm.com>
Date		: 2009-06-17 17:56 (20 days old)
References	: http://lkml.org/lkml/2009/6/17/194


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13522
Subject		: BUG: scheduling while atomic
Submitter	: Sergey Senozhatsky <sergey.senozhatsky@mail.by>
Date		: 2009-06-12 19:29 (25 days old)
References	: http://lkml.org/lkml/2009/6/29/237


Regressions with patches
------------------------

Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13734
Subject		: regression in 2.6.31-rcX since commit a1091aa
Submitter	: Larry Finger <Larry.Finger@lwfinger.net>
Date		: 2009-07-06 19:07 (1 days old)
References	: http://marc.info/?l=linux-kernel&m=124690725130645&w=4
Handled-By	: David Miller <davem@davemloft.net>
Patch		: http://patchwork.kernel.org/patch/34292/


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13665
Subject		: commit 69c854817566 causes OOMs
Submitter	: David Howells <dhowells@redhat.com>
Date		: 2009-06-27 08:12 (10 days old)
First-Bad-Commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=69c854817566db82c362797b4a6521d0b00fe1d8
References	: http://lkml.org/lkml/2009/6/27/28
Handled-By	: Wu Fengguang <fengguang.wu@intel.com>
Patch		: http://patchwork.kernel.org/patch/32740/


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13659
Subject		: iwlagn (4965): no wireless due to RFKILL problem
Submitter	: Frans Pop <elendil@planet.nl>
Date		: 2009-06-26 13:36 (11 days old)
References	: http://lkml.org/lkml/2009/6/26/127
Handled-By	: Johannes Berg <johannes@sipsolutions.net>
Patch		: http://lkml.org/lkml/2009/6/27/35


Bug-Entry	: http://bugzilla.kernel.org/show_bug.cgi?id=13643
Subject		: Touchpad lost synchronization after resume from suspend to RAM
Submitter	: Cijoml Cijomlovic Cijomlov <cijoml@volny.cz>
Date		: 2009-06-28 10:42 (9 days old)
References	: http://lkml.org/lkml/2009/6/23/365
		  2.6.30-rc1: touchpad disabled
		  http://lkml.org/lkml/2009/6/25/256
Handled-By	: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
Patch		: http://patchwork.kernel.org/patch/34075/


For details, please visit the bug entries and follow the links given in
references.

As you can see, there is a Bugzilla entry for each of the listed regressions.
There also is a Bugzilla entry used for tracking the regressions from 2.6.30,
unresolved as well as resolved, at:

http://bugzilla.kernel.org/show_bug.cgi?id=13615

Please let me know if there are any Bugzilla entries that should be added to
the list in there.

Thanks,
Rafael


^ permalink raw reply

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: David Miller @ 2009-07-06 21:36 UTC (permalink / raw)
  To: Larry.Finger; +Cc: chunkeey, linux-wireless, linux-kernel
In-Reply-To: <4A5261AE.1010500@lwfinger.net>

From: Larry Finger <Larry.Finger@lwfinger.net>
Date: Mon, 06 Jul 2009 15:42:22 -0500

> This patch fixes my USB device.

Thanks for testing.

> Please push to Linus.

Will do.

^ permalink raw reply

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: David Miller @ 2009-07-06 21:36 UTC (permalink / raw)
  To: gurligebis; +Cc: Larry.Finger, chunkeey, linux-wireless, linux-kernel
In-Reply-To: <9c30dffe0907061326n77823e03lf87f4feb616c8f7b@mail.gmail.com>

From: Bjarke Istrup Pedersen <gurligebis@gmail.com>
Date: Mon, 6 Jul 2009 22:26:09 +0200

> I can confirm that the patch fixes the problem with my PCMCIA card :-)

Thanks for testing :)

^ permalink raw reply

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: Larry Finger @ 2009-07-06 20:42 UTC (permalink / raw)
  To: David Miller; +Cc: chunkeey, linux-wireless, linux-kernel
In-Reply-To: <20090706.125011.56653570.davem@davemloft.net>

David Miller wrote:
> From: Larry Finger <Larry.Finger@lwfinger.net>
> Date: Mon, 06 Jul 2009 14:43:45 -0500
> 
>> I'm available for testing.
> 
> I just committed the following to my net-2.6 tree, give
> it a spin:
> 
>>From 0ca1b08eba627b4245efd0f71b55a062bf163777 Mon Sep 17 00:00:00 2001
> From: David S. Miller <davem@davemloft.net>
> Date: Mon, 6 Jul 2009 12:49:18 -0700
> Subject: [PATCH] Revert "p54: Use SKB list handling helpers instead of by-hand code."
> 
> This reverts commit a1091aae19b1d9c85d91c86915a611387f67a26b.
> ---
>  drivers/net/wireless/p54/p54common.c |   46 ++++++++++++++++++++--------------
>  1 files changed, 27 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
> index b618bd1..48d81d9 100644
> --- a/drivers/net/wireless/p54/p54common.c
> +++ b/drivers/net/wireless/p54/p54common.c
> @@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
>  	struct p54_tx_info *range;
>  	unsigned long flags;
>  
> -	if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue)))
> +	if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
>  		return;
>  
> -	/* There used to be a check here to see if the SKB was on the
> -	 * TX queue or not.  This can never happen because all SKBs we
> -	 * see here successfully went through p54_assign_address()
> -	 * which means the SKB is on the ->tx_queue.
> +	/*
> +	 * don't try to free an already unlinked skb
>  	 */
> +	if (unlikely((!skb->next) || (!skb->prev)))
> +		return;
>  
>  	spin_lock_irqsave(&priv->tx_queue.lock, flags);
>  	info = IEEE80211_SKB_CB(skb);
>  	range = (void *)info->rate_driver_data;
> -	if (!skb_queue_is_first(&priv->tx_queue, skb)) {
> +	if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
>  		struct ieee80211_tx_info *ni;
>  		struct p54_tx_info *mr;
>  
> -		ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb));
> +		ni = IEEE80211_SKB_CB(skb->prev);
>  		mr = (struct p54_tx_info *)ni->rate_driver_data;
>  	}
> -	if (!skb_queue_is_last(&priv->tx_queue, skb)) {
> +	if (skb->next != (struct sk_buff *)&priv->tx_queue) {
>  		struct ieee80211_tx_info *ni;
>  		struct p54_tx_info *mr;
>  
> -		ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb));
> +		ni = IEEE80211_SKB_CB(skb->next);
>  		mr = (struct p54_tx_info *)ni->rate_driver_data;
>  	}
>  	__skb_unlink(skb, &priv->tx_queue);
> @@ -864,13 +864,15 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
>  	unsigned long flags;
>  
>  	spin_lock_irqsave(&priv->tx_queue.lock, flags);
> -	skb_queue_walk(&priv->tx_queue, entry) {
> +	entry = priv->tx_queue.next;
> +	while (entry != (struct sk_buff *)&priv->tx_queue) {
>  		struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
>  
>  		if (hdr->req_id == req_id) {
>  			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
>  			return entry;
>  		}
> +		entry = entry->next;
>  	}
>  	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
>  	return NULL;
> @@ -888,22 +890,24 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
>  	int count, idx;
>  
>  	spin_lock_irqsave(&priv->tx_queue.lock, flags);
> -	skb_queue_walk(&priv->tx_queue, entry) {
> +	entry = (struct sk_buff *) priv->tx_queue.next;
> +	while (entry != (struct sk_buff *)&priv->tx_queue) {
>  		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
>  		struct p54_hdr *entry_hdr;
>  		struct p54_tx_data *entry_data;
>  		unsigned int pad = 0, frame_len;
>  
>  		range = (void *)info->rate_driver_data;
> -		if (range->start_addr != addr)
> +		if (range->start_addr != addr) {
> +			entry = entry->next;
>  			continue;
> +		}
>  
> -		if (!skb_queue_is_last(&priv->tx_queue, entry)) {
> +		if (entry->next != (struct sk_buff *)&priv->tx_queue) {
>  			struct ieee80211_tx_info *ni;
>  			struct p54_tx_info *mr;
>  
> -			ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue,
> -							     entry));
> +			ni = IEEE80211_SKB_CB(entry->next);
>  			mr = (struct p54_tx_info *)ni->rate_driver_data;
>  		}
>  
> @@ -1164,21 +1168,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
>  		}
>  	}
>  
> -	skb_queue_walk(&priv->tx_queue, entry) {
> +	entry = priv->tx_queue.next;
> +	while (left--) {
>  		u32 hole_size;
>  		info = IEEE80211_SKB_CB(entry);
>  		range = (void *)info->rate_driver_data;
>  		hole_size = range->start_addr - last_addr;
>  		if (!target_skb && hole_size >= len) {
> -			target_skb = skb_queue_prev(&priv->tx_queue, entry);
> +			target_skb = entry->prev;
>  			hole_size -= len;
>  			target_addr = last_addr;
>  		}
>  		largest_hole = max(largest_hole, hole_size);
>  		last_addr = range->end_addr;
> +		entry = entry->next;
>  	}
>  	if (!target_skb && priv->rx_end - last_addr >= len) {
> -		target_skb = skb_peek_tail(&priv->tx_queue);
> +		target_skb = priv->tx_queue.prev;
>  		largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
>  		if (!skb_queue_empty(&priv->tx_queue)) {
>  			info = IEEE80211_SKB_CB(target_skb);
> @@ -2084,6 +2090,7 @@ out:
>  static void p54_stop(struct ieee80211_hw *dev)
>  {
>  	struct p54_common *priv = dev->priv;
> +	struct sk_buff *skb;
>  
>  	mutex_lock(&priv->conf_mutex);
>  	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
> @@ -2098,7 +2105,8 @@ static void p54_stop(struct ieee80211_hw *dev)
>  		p54_tx_cancel(dev, priv->cached_beacon);
>  
>  	priv->stop(dev);
> -	skb_queue_purge(&priv->tx_queue);
> +	while ((skb = skb_dequeue(&priv->tx_queue)))
> +		kfree_skb(skb);
>  	priv->cached_beacon = NULL;
>  	priv->tsf_high32 = priv->tsf_low32 = 0;
>  	mutex_unlock(&priv->conf_mutex);

This patch fixes my USB device.

Please push to Linus.

Thanks,

Larry


^ permalink raw reply

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: Bjarke Istrup Pedersen @ 2009-07-06 20:26 UTC (permalink / raw)
  To: David Miller; +Cc: Larry.Finger, chunkeey, linux-wireless, linux-kernel
In-Reply-To: <20090706.125011.56653570.davem@davemloft.net>

2009/7/6 David Miller <davem@davemloft.net>:
> From: Larry Finger <Larry.Finger@lwfinger.net>
> Date: Mon, 06 Jul 2009 14:43:45 -0500
>
>> I'm available for testing.
>
> I just committed the following to my net-2.6 tree, give
> it a spin:
>
> From 0ca1b08eba627b4245efd0f71b55a062bf163777 Mon Sep 17 00:00:00 2001
> From: David S. Miller <davem@davemloft.net>
> Date: Mon, 6 Jul 2009 12:49:18 -0700
> Subject: [PATCH] Revert "p54: Use SKB list handling helpers instead of by-hand code."
>
> This reverts commit a1091aae19b1d9c85d91c86915a611387f67a26b.
> ---
>  drivers/net/wireless/p54/p54common.c |   46 ++++++++++++++++++++--------------
>  1 files changed, 27 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
> index b618bd1..48d81d9 100644
> --- a/drivers/net/wireless/p54/p54common.c
> +++ b/drivers/net/wireless/p54/p54common.c
> @@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
>        struct p54_tx_info *range;
>        unsigned long flags;
>
> -       if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue)))
> +       if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
>                return;
>
> -       /* There used to be a check here to see if the SKB was on the
> -        * TX queue or not.  This can never happen because all SKBs we
> -        * see here successfully went through p54_assign_address()
> -        * which means the SKB is on the ->tx_queue.
> +       /*
> +        * don't try to free an already unlinked skb
>         */
> +       if (unlikely((!skb->next) || (!skb->prev)))
> +               return;
>
>        spin_lock_irqsave(&priv->tx_queue.lock, flags);
>        info = IEEE80211_SKB_CB(skb);
>        range = (void *)info->rate_driver_data;
> -       if (!skb_queue_is_first(&priv->tx_queue, skb)) {
> +       if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
>                struct ieee80211_tx_info *ni;
>                struct p54_tx_info *mr;
>
> -               ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb));
> +               ni = IEEE80211_SKB_CB(skb->prev);
>                mr = (struct p54_tx_info *)ni->rate_driver_data;
>        }
> -       if (!skb_queue_is_last(&priv->tx_queue, skb)) {
> +       if (skb->next != (struct sk_buff *)&priv->tx_queue) {
>                struct ieee80211_tx_info *ni;
>                struct p54_tx_info *mr;
>
> -               ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb));
> +               ni = IEEE80211_SKB_CB(skb->next);
>                mr = (struct p54_tx_info *)ni->rate_driver_data;
>        }
>        __skb_unlink(skb, &priv->tx_queue);
> @@ -864,13 +864,15 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
>        unsigned long flags;
>
>        spin_lock_irqsave(&priv->tx_queue.lock, flags);
> -       skb_queue_walk(&priv->tx_queue, entry) {
> +       entry = priv->tx_queue.next;
> +       while (entry != (struct sk_buff *)&priv->tx_queue) {
>                struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
>
>                if (hdr->req_id == req_id) {
>                        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
>                        return entry;
>                }
> +               entry = entry->next;
>        }
>        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
>        return NULL;
> @@ -888,22 +890,24 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
>        int count, idx;
>
>        spin_lock_irqsave(&priv->tx_queue.lock, flags);
> -       skb_queue_walk(&priv->tx_queue, entry) {
> +       entry = (struct sk_buff *) priv->tx_queue.next;
> +       while (entry != (struct sk_buff *)&priv->tx_queue) {
>                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
>                struct p54_hdr *entry_hdr;
>                struct p54_tx_data *entry_data;
>                unsigned int pad = 0, frame_len;
>
>                range = (void *)info->rate_driver_data;
> -               if (range->start_addr != addr)
> +               if (range->start_addr != addr) {
> +                       entry = entry->next;
>                        continue;
> +               }
>
> -               if (!skb_queue_is_last(&priv->tx_queue, entry)) {
> +               if (entry->next != (struct sk_buff *)&priv->tx_queue) {
>                        struct ieee80211_tx_info *ni;
>                        struct p54_tx_info *mr;
>
> -                       ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue,
> -                                                            entry));
> +                       ni = IEEE80211_SKB_CB(entry->next);
>                        mr = (struct p54_tx_info *)ni->rate_driver_data;
>                }
>
> @@ -1164,21 +1168,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
>                }
>        }
>
> -       skb_queue_walk(&priv->tx_queue, entry) {
> +       entry = priv->tx_queue.next;
> +       while (left--) {
>                u32 hole_size;
>                info = IEEE80211_SKB_CB(entry);
>                range = (void *)info->rate_driver_data;
>                hole_size = range->start_addr - last_addr;
>                if (!target_skb && hole_size >= len) {
> -                       target_skb = skb_queue_prev(&priv->tx_queue, entry);
> +                       target_skb = entry->prev;
>                        hole_size -= len;
>                        target_addr = last_addr;
>                }
>                largest_hole = max(largest_hole, hole_size);
>                last_addr = range->end_addr;
> +               entry = entry->next;
>        }
>        if (!target_skb && priv->rx_end - last_addr >= len) {
> -               target_skb = skb_peek_tail(&priv->tx_queue);
> +               target_skb = priv->tx_queue.prev;
>                largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
>                if (!skb_queue_empty(&priv->tx_queue)) {
>                        info = IEEE80211_SKB_CB(target_skb);
> @@ -2084,6 +2090,7 @@ out:
>  static void p54_stop(struct ieee80211_hw *dev)
>  {
>        struct p54_common *priv = dev->priv;
> +       struct sk_buff *skb;
>
>        mutex_lock(&priv->conf_mutex);
>        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
> @@ -2098,7 +2105,8 @@ static void p54_stop(struct ieee80211_hw *dev)
>                p54_tx_cancel(dev, priv->cached_beacon);
>
>        priv->stop(dev);
> -       skb_queue_purge(&priv->tx_queue);
> +       while ((skb = skb_dequeue(&priv->tx_queue)))
> +               kfree_skb(skb);
>        priv->cached_beacon = NULL;
>        priv->tsf_high32 = priv->tsf_low32 = 0;
>        mutex_unlock(&priv->conf_mutex);
> --
> 1.6.3.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

I can confirm that the patch fixes the problem with my PCMCIA card :-)

Best regards,
Bjarke Istrup Pedersen

^ permalink raw reply

* Re: rt73 in AP mode: PS frames buffered but missing TIM bit?
From: Stefan Steuerwald @ 2009-07-06 20:20 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <1246900337.20908.15.camel@johannes.local>

2009/7/6 Johannes Berg <johannes@sipsolutions.net>
>
> On Mon, 2009-07-06 at 19:06 +0200, Stefan Steuerwald wrote:
> >
> > Summary:
> > - I suspect a missing TIM bit when using rt73 in AP mode with my
> > powersaving iPod Touch.
> > - Despite frames being buffered no TIM bit is getting set (I thought
> > it should), station stays asleep.
>
> Sounds like a driver problem, it must not be reacting to set_tim()
> properly.
>
> johannes

Looking at rt73usb.c:2242, there isn't any initializer for .set_tim .
Plausible explanation.
It may be totally beyond me to just implement it. Let me find someone
to ask nicely ;-) ...

^ permalink raw reply

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: Bjarke Istrup Pedersen @ 2009-07-06 20:01 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <4a524b55.wIWqgs5uHs2CpdJy%Larry.Finger@lwfinger.net>

2009/7/6 Larry Finger <Larry.Finger@lwfinger.net>:
> Beginning with commit a1091aae19b1d9c85d91c86915a611387f67a26b entitled
> "p54: Use SKB list handling helpers instead of by-hand code.", the following
> appears in my logs whenever I try to use my p54usb wireless device:
>
> BUG: sleeping function called from invalid context at arch/x86/mm/fault.c:1085
>  in_atomic(): 0, irqs_disabled(): 1, pid: 8538, name: modprobe
>  2 locks held by modprobe/8538:
>  #0:  (&local->queue_stop_reason_lock){-.-...}, at: [<ffffffffa023b99f>]
>        ieee80211_stop_queues_by_reason+0x28/0x5e [mac80211]
>  #1:  (&mm->mmap_sem){++++++}, at: [<ffffffff80225a4f>] do_page_fault+0xd2/0x1fe
>  irq event stamp: 25212
>  hardirqs last  enabled at (25211): [<ffffffff80451f28>] _spin_unlock_irqrestore+0x3f/0x47
>  hardirqs last disabled at (25212): [<ffffffff804520e3>] _spin_lock_irqsave+0x17/0x4b
>  softirqs last  enabled at (24064): [<ffffffff803e9997>] sk_filter+0xba/0xc3
>  softirqs last disabled at (24062): [<ffffffff803e98f3>] sk_filter+0x16/0xc3
>  Pid: 8538, comm: modprobe Not tainted 2.6.30-rc6-Linus-00905-g46c3767-dirty #180
>  Call Trace:
>  [<ffffffff8025af90>] ? print_irqtrace_events+0xd0/0xd4
>  [<ffffffff80233384>] __might_sleep+0xf4/0xf6
>  [<ffffffff80225a99>] do_page_fault+0x11c/0x1fe
>  [<ffffffff80451f28>] ? _spin_unlock_irqrestore+0x3f/0x47
>  [<ffffffff804525cf>] page_fault+0x1f/0x30
>  [<ffffffff80451f28>] ? _spin_unlock_irqrestore+0x3f/0x47
>  [<ffffffffa023b99f>] ? ieee80211_stop_queues_by_reason+0x28/0x5e [mac80211]
>  [<ffffffffa023b92b>] ? __ieee80211_stop_queue+0x36/0x82 [mac80211]
>  [<ffffffff8045210b>] ? _spin_lock_irqsave+0x3f/0x4b
>  [<ffffffffa023b9b3>] ieee80211_stop_queues_by_reason+0x3c/0x5e [mac80211]
>  [<ffffffffa023b9e0>] ieee80211_stop_queues+0xb/0xd [mac80211]
>  [<ffffffffa047c35c>] p54_assign_address+0x164/0x1ec [p54common]
>  [<ffffffffa047c49a>] p54_alloc_skb+0xb6/0xd3 [p54common]
> ...
>
> Reverting the hunk that affects p54_assign_address() fixes the problem. When I
> tried to determine which change(s) caused the problem, the skb_peek_tail()
> seemed to be the problem; however, the system would freeze. I was not able to
> recover any log information.
>
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> ---
>
> diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
> index b618bd1..c5bc55a 100644
> --- a/drivers/net/wireless/p54/p54common.c
> +++ b/drivers/net/wireless/p54/p54common.c
> @@ -1164,21 +1164,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
>                }
>        }
>
> -       skb_queue_walk(&priv->tx_queue, entry) {
> +       entry = priv->tx_queue.next;
> +       while (left--) {
>                u32 hole_size;
>                info = IEEE80211_SKB_CB(entry);
>                range = (void *)info->rate_driver_data;
>                hole_size = range->start_addr - last_addr;
>                if (!target_skb && hole_size >= len) {
> -                       target_skb = skb_queue_prev(&priv->tx_queue, entry);
> +                       target_skb = entry->prev;
>                        hole_size -= len;
>                        target_addr = last_addr;
>                }
>                largest_hole = max(largest_hole, hole_size);
>                last_addr = range->end_addr;
> +               entry = entry->next;
>        }
>        if (!target_skb && priv->rx_end - last_addr >= len) {
> -               target_skb = skb_peek_tail(&priv->tx_queue);
> +               target_skb = priv->tx_queue.prev;
>                largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
>                if (!skb_queue_empty(&priv->tx_queue)) {
>                        info = IEEE80211_SKB_CB(target_skb);
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

I've been having this problem too.
Just completed a bisect to track the commit causing the problem when
this mail hit my inbox :-)

The oops of it is logged it kerneloops here:
http://kerneloops.org/guilty.php?guilty=__ieee80211_stop_queue&version=2.6.31-rc&start=2031616&end=2064383&class=oops

Best regards,
Bjarke Istrup Pedersen

^ permalink raw reply

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: David Miller @ 2009-07-06 19:50 UTC (permalink / raw)
  To: Larry.Finger; +Cc: chunkeey, linux-wireless, linux-kernel
In-Reply-To: <4A5253F1.50504@lwfinger.net>

From: Larry Finger <Larry.Finger@lwfinger.net>
Date: Mon, 06 Jul 2009 14:43:45 -0500

> I'm available for testing.

I just committed the following to my net-2.6 tree, give
it a spin:

>From 0ca1b08eba627b4245efd0f71b55a062bf163777 Mon Sep 17 00:00:00 2001
From: David S. Miller <davem@davemloft.net>
Date: Mon, 6 Jul 2009 12:49:18 -0700
Subject: [PATCH] Revert "p54: Use SKB list handling helpers instead of by-hand code."

This reverts commit a1091aae19b1d9c85d91c86915a611387f67a26b.
---
 drivers/net/wireless/p54/p54common.c |   46 ++++++++++++++++++++--------------
 1 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index b618bd1..48d81d9 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -823,30 +823,30 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
 	struct p54_tx_info *range;
 	unsigned long flags;
 
-	if (unlikely(!skb || !dev || skb_queue_empty(&priv->tx_queue)))
+	if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
 		return;
 
-	/* There used to be a check here to see if the SKB was on the
-	 * TX queue or not.  This can never happen because all SKBs we
-	 * see here successfully went through p54_assign_address()
-	 * which means the SKB is on the ->tx_queue.
+	/*
+	 * don't try to free an already unlinked skb
 	 */
+	if (unlikely((!skb->next) || (!skb->prev)))
+		return;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
 	info = IEEE80211_SKB_CB(skb);
 	range = (void *)info->rate_driver_data;
-	if (!skb_queue_is_first(&priv->tx_queue, skb)) {
+	if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
 		struct ieee80211_tx_info *ni;
 		struct p54_tx_info *mr;
 
-		ni = IEEE80211_SKB_CB(skb_queue_prev(&priv->tx_queue, skb));
+		ni = IEEE80211_SKB_CB(skb->prev);
 		mr = (struct p54_tx_info *)ni->rate_driver_data;
 	}
-	if (!skb_queue_is_last(&priv->tx_queue, skb)) {
+	if (skb->next != (struct sk_buff *)&priv->tx_queue) {
 		struct ieee80211_tx_info *ni;
 		struct p54_tx_info *mr;
 
-		ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue, skb));
+		ni = IEEE80211_SKB_CB(skb->next);
 		mr = (struct p54_tx_info *)ni->rate_driver_data;
 	}
 	__skb_unlink(skb, &priv->tx_queue);
@@ -864,13 +864,15 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
-	skb_queue_walk(&priv->tx_queue, entry) {
+	entry = priv->tx_queue.next;
+	while (entry != (struct sk_buff *)&priv->tx_queue) {
 		struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
 
 		if (hdr->req_id == req_id) {
 			spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 			return entry;
 		}
+		entry = entry->next;
 	}
 	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 	return NULL;
@@ -888,22 +890,24 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
 	int count, idx;
 
 	spin_lock_irqsave(&priv->tx_queue.lock, flags);
-	skb_queue_walk(&priv->tx_queue, entry) {
+	entry = (struct sk_buff *) priv->tx_queue.next;
+	while (entry != (struct sk_buff *)&priv->tx_queue) {
 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
 		struct p54_hdr *entry_hdr;
 		struct p54_tx_data *entry_data;
 		unsigned int pad = 0, frame_len;
 
 		range = (void *)info->rate_driver_data;
-		if (range->start_addr != addr)
+		if (range->start_addr != addr) {
+			entry = entry->next;
 			continue;
+		}
 
-		if (!skb_queue_is_last(&priv->tx_queue, entry)) {
+		if (entry->next != (struct sk_buff *)&priv->tx_queue) {
 			struct ieee80211_tx_info *ni;
 			struct p54_tx_info *mr;
 
-			ni = IEEE80211_SKB_CB(skb_queue_next(&priv->tx_queue,
-							     entry));
+			ni = IEEE80211_SKB_CB(entry->next);
 			mr = (struct p54_tx_info *)ni->rate_driver_data;
 		}
 
@@ -1164,21 +1168,23 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
 		}
 	}
 
-	skb_queue_walk(&priv->tx_queue, entry) {
+	entry = priv->tx_queue.next;
+	while (left--) {
 		u32 hole_size;
 		info = IEEE80211_SKB_CB(entry);
 		range = (void *)info->rate_driver_data;
 		hole_size = range->start_addr - last_addr;
 		if (!target_skb && hole_size >= len) {
-			target_skb = skb_queue_prev(&priv->tx_queue, entry);
+			target_skb = entry->prev;
 			hole_size -= len;
 			target_addr = last_addr;
 		}
 		largest_hole = max(largest_hole, hole_size);
 		last_addr = range->end_addr;
+		entry = entry->next;
 	}
 	if (!target_skb && priv->rx_end - last_addr >= len) {
-		target_skb = skb_peek_tail(&priv->tx_queue);
+		target_skb = priv->tx_queue.prev;
 		largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
 		if (!skb_queue_empty(&priv->tx_queue)) {
 			info = IEEE80211_SKB_CB(target_skb);
@@ -2084,6 +2090,7 @@ out:
 static void p54_stop(struct ieee80211_hw *dev)
 {
 	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
 
 	mutex_lock(&priv->conf_mutex);
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -2098,7 +2105,8 @@ static void p54_stop(struct ieee80211_hw *dev)
 		p54_tx_cancel(dev, priv->cached_beacon);
 
 	priv->stop(dev);
-	skb_queue_purge(&priv->tx_queue);
+	while ((skb = skb_dequeue(&priv->tx_queue)))
+		kfree_skb(skb);
 	priv->cached_beacon = NULL;
 	priv->tsf_high32 = priv->tsf_low32 = 0;
 	mutex_unlock(&priv->conf_mutex);
-- 
1.6.3.3


^ permalink raw reply related

* Re: [PATCH] p54: Fix regression in 2.6.31-rcX since commit a1091aa - sleeping function called from invalid context
From: Larry Finger @ 2009-07-06 19:43 UTC (permalink / raw)
  To: David Miller; +Cc: chunkeey, linux-wireless, linux-kernel
In-Reply-To: <20090706.123441.246532764.davem@davemloft.net>

David Miller wrote:
> From: Christian Lamparter <chunkeey@web.de>
> Date: Mon, 6 Jul 2009 21:19:25 +0200
> 
>> On Monday 06 July 2009 21:14:29 David Miller wrote:
>>> If I can't figure it out quickly I'll just simply revert.
>> hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
>> [2.6.31] p54: band-aid to restore driver functionality
>> http://patchwork.ozlabs.org/patch/28918/
>>
>> in case someone missed it.
> 
> It is so much cleaner to not do multiple things in one patch.
> 
> It's also better to completely revert the SKB list handling
> changes first, then add whatever other fixes you want make
> on top.
> 
> Partial revert really makes no sense here and is only asking
> for even more potential regressions.
> 
> So, like I said, I'm reverting this wholesale unless I can figure
> out a fix quickly.

I'm available for testing.

Larry

^ 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