summary refs log tree commit diff
path: root/net/mac80211
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-11-24 15:01:29 -0800
committerDavid S. Miller <davem@davemloft.net>2009-11-24 15:01:29 -0800
commit4ba3eb034fb6fd1990ccc5a6d71d5abcda37b905 (patch)
tree0789ba36d96dba330416a1e6a9a68e891a78802a /net/mac80211
parent35700212b45ea9f98fa682cfc1bc1a67c9ccc34b (diff)
parent18b6c9a2213d3b6e0212e8b225abf95f7564206a (diff)
downloadlinux-4ba3eb034fb6fd1990ccc5a6d71d5abcda37b905.tar.gz
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Makefile2
-rw-r--r--net/mac80211/agg-rx.c8
-rw-r--r--net/mac80211/agg-tx.c103
-rw-r--r--net/mac80211/cfg.c29
-rw-r--r--net/mac80211/debugfs.c2
-rw-r--r--net/mac80211/debugfs_sta.c29
-rw-r--r--net/mac80211/driver-ops.h5
-rw-r--r--net/mac80211/driver-trace.h9
-rw-r--r--net/mac80211/ht.c5
-rw-r--r--net/mac80211/ibss.c3
-rw-r--r--net/mac80211/ieee80211_i.h30
-rw-r--r--net/mac80211/iface.c12
-rw-r--r--net/mac80211/main.c343
-rw-r--r--net/mac80211/mesh.c28
-rw-r--r--net/mac80211/mesh.h4
-rw-r--r--net/mac80211/mesh_hwmp.c24
-rw-r--r--net/mac80211/mesh_pathtbl.c7
-rw-r--r--net/mac80211/mesh_plink.c2
-rw-r--r--net/mac80211/mlme.c30
-rw-r--r--net/mac80211/rate.c12
-rw-r--r--net/mac80211/rate.h9
-rw-r--r--net/mac80211/rx.c334
-rw-r--r--net/mac80211/spectmgmt.c2
-rw-r--r--net/mac80211/sta_info.c36
-rw-r--r--net/mac80211/sta_info.h6
-rw-r--r--net/mac80211/status.c337
-rw-r--r--net/mac80211/tkip.c4
-rw-r--r--net/mac80211/tx.c45
-rw-r--r--net/mac80211/util.c10
-rw-r--r--net/mac80211/wep.c8
-rw-r--r--net/mac80211/wpa.c25
31 files changed, 797 insertions, 706 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 9f3cf7129324..298cfcc1bf8d 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o
 
 # mac80211 objects
 mac80211-y := \
-	main.o \
+	main.o status.o \
 	sta_info.o \
 	wep.o \
 	wpa.o \
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index bc064d7933ff..7ed5fe664732 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -41,7 +41,8 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
 	       sta->sta.addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-	if (drv_ampdu_action(local, IEEE80211_AMPDU_RX_STOP,
+	if (drv_ampdu_action(local, &sta->sdata->vif,
+			     IEEE80211_AMPDU_RX_STOP,
 			     &sta->sta, tid, NULL))
 		printk(KERN_DEBUG "HW problem - can not stop rx "
 				"aggregation for tid %d\n", tid);
@@ -170,7 +171,7 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
 	mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout);
 	mgmt->u.action.u.addba_resp.status = cpu_to_le16(status);
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_addba_request(struct ieee80211_local *local,
@@ -284,7 +285,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 		goto end;
 	}
 
-	ret = drv_ampdu_action(local, IEEE80211_AMPDU_RX_START,
+	ret = drv_ampdu_action(local, &sta->sdata->vif,
+			       IEEE80211_AMPDU_RX_START,
 			       &sta->sta, tid, &start_seq_num);
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index b09948ceec4a..b50b2bc3b8c5 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -91,7 +91,7 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
 	mgmt->u.action.u.addba_req.start_seq_num =
 					cpu_to_le16(start_seq_num << 4);
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
@@ -120,7 +120,8 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
 	bar->control = cpu_to_le16(bar_control);
 	bar->start_seq_num = cpu_to_le16(ssn);
 
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
@@ -138,7 +139,8 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
 		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
-	ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_STOP,
+	ret = drv_ampdu_action(local, &sta->sdata->vif,
+			       IEEE80211_AMPDU_TX_STOP,
 			       &sta->sta, tid, NULL);
 
 	/* HW shall not deny going back to legacy */
@@ -196,11 +198,11 @@ static inline int ieee80211_ac_from_tid(int tid)
 	return ieee802_1d_to_ac[tid & 7];
 }
 
-int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct ieee80211_local *local = sdata->local;
 	u8 *state;
 	int ret = 0;
 	u16 start_seq_num;
@@ -208,52 +210,37 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 	if (WARN_ON(!local->ops->ampdu_action))
 		return -EINVAL;
 
-	if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+	if ((tid >= STA_TID_NUM) ||
+	    !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION))
 		return -EINVAL;
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n",
-	       ra, tid);
+	       pubsta->addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-	rcu_read_lock();
-
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-		printk(KERN_DEBUG "Could not find the station\n");
-#endif
-		ret = -ENOENT;
-		goto unlock;
-	}
-
 	/*
 	 * The aggregation code is not prepared to handle
 	 * anything but STA/AP due to the BSSID handling.
 	 * IBSS could work in the code but isn't supported
 	 * by drivers or the standard.
 	 */
-	if (sta->sdata->vif.type != NL80211_IFTYPE_STATION &&
-	    sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
-	    sta->sdata->vif.type != NL80211_IFTYPE_AP) {
-		ret = -EINVAL;
-		goto unlock;
-	}
+	if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+	    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+	    sdata->vif.type != NL80211_IFTYPE_AP)
+		return -EINVAL;
 
 	if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "Suspend in progress. "
 		       "Denying BA session request\n");
 #endif
-		ret = -EINVAL;
-		goto unlock;
+		return -EINVAL;
 	}
 
 	spin_lock_bh(&sta->lock);
 	spin_lock(&local->ampdu_lock);
 
-	sdata = sta->sdata;
-
 	/* we have tried too many times, receiver does not want A-MPDU */
 	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
 		ret = -EBUSY;
@@ -310,8 +297,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 
 	start_seq_num = sta->tid_seq[tid];
 
-	ret = drv_ampdu_action(local, IEEE80211_AMPDU_TX_START,
-			       &sta->sta, tid, &start_seq_num);
+	ret = drv_ampdu_action(local, &sdata->vif,
+			       IEEE80211_AMPDU_TX_START,
+			       pubsta, tid, &start_seq_num);
 
 	if (ret) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -336,7 +324,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 			sta->ampdu_mlme.dialog_token_allocator;
 	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
 
-	ieee80211_send_addba_request(sta->sdata, ra, tid,
+	ieee80211_send_addba_request(sdata, pubsta->addr, tid,
 			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
 			 sta->ampdu_mlme.tid_tx[tid]->ssn,
 			 0x40, 5000);
@@ -348,7 +336,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
 #endif
-	goto unlock;
+	return 0;
 
  err_free:
 	kfree(sta->ampdu_mlme.tid_tx[tid]);
@@ -360,8 +348,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
  err_unlock_sta:
 	spin_unlock(&local->ampdu_lock);
 	spin_unlock_bh(&sta->lock);
- unlock:
-	rcu_read_unlock();
 	return ret;
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
@@ -428,13 +414,15 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
 	ieee80211_agg_splice_finish(local, sta, tid);
 	spin_unlock(&local->ampdu_lock);
 
-	drv_ampdu_action(local, IEEE80211_AMPDU_TX_OPERATIONAL,
+	drv_ampdu_action(local, &sta->sdata->vif,
+			 IEEE80211_AMPDU_TX_OPERATIONAL,
 			 &sta->sta, tid, NULL);
 }
 
-void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	u8 *state;
 
@@ -483,10 +471,11 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 }
 EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
 
-void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 				      const u8 *ra, u16 tid)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_ra_tid *ra_tid;
 	struct sk_buff *skb = dev_alloc_skb(0);
 
@@ -501,6 +490,7 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
 	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
 	memcpy(&ra_tid->ra, ra, ETH_ALEN);
 	ra_tid->tid = tid;
+	ra_tid->vif = vif;
 
 	skb->pkt_type = IEEE80211_ADDBA_MSG;
 	skb_queue_tail(&local->skb_queue, skb);
@@ -535,13 +525,12 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 	return ret;
 }
 
-int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
-				 u8 *ra, u16 tid,
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
 				 enum ieee80211_back_parties initiator)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct sta_info *sta;
-	int ret = 0;
+	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	struct ieee80211_local *local = sdata->local;
 
 	if (WARN_ON(!local->ops->ampdu_action))
 		return -EINVAL;
@@ -549,22 +538,14 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
 	if (tid >= STA_TID_NUM)
 		return -EINVAL;
 
-	rcu_read_lock();
-	sta = sta_info_get(local, ra);
-	if (!sta) {
-		rcu_read_unlock();
-		return -ENOENT;
-	}
-
-	ret = __ieee80211_stop_tx_ba_session(sta, tid, initiator);
-	rcu_read_unlock();
-	return ret;
+	return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
 }
 EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
 
-void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	u8 *state;
 
@@ -627,10 +608,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
 }
 EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
 
-void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
 				     const u8 *ra, u16 tid)
 {
-	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_ra_tid *ra_tid;
 	struct sk_buff *skb = dev_alloc_skb(0);
 
@@ -645,6 +627,7 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
 	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
 	memcpy(&ra_tid->ra, ra, ETH_ALEN);
 	ra_tid->tid = tid;
+	ra_tid->vif = vif;
 
 	skb->pkt_type = IEEE80211_DELBA_MSG;
 	skb_queue_tail(&local->skb_queue, skb);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7f18c8fa1880..93ee1fd5c08d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -42,15 +42,6 @@ static bool nl80211_params_check(enum nl80211_iftype type,
 	if (!nl80211_type_check(type))
 		return false;
 
-	if (params->use_4addr > 0) {
-		switch(type) {
-		case NL80211_IFTYPE_AP_VLAN:
-		case NL80211_IFTYPE_STATION:
-			break;
-		default:
-			return false;
-		}
-	}
 	return true;
 }
 
@@ -107,12 +98,16 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 					    params->mesh_id_len,
 					    params->mesh_id);
 
-	if (params->use_4addr >= 0)
-		sdata->use_4addr = !!params->use_4addr;
-
 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
 		return 0;
 
+	if (type == NL80211_IFTYPE_AP_VLAN &&
+	    params && params->use_4addr == 0)
+		rcu_assign_pointer(sdata->u.vlan.sta, NULL);
+	else if (type == NL80211_IFTYPE_STATION &&
+		 params && params->use_4addr >= 0)
+		sdata->u.mgd.use_4addr = params->use_4addr;
+
 	sdata->u.mntr_flags = *flags;
 	return 0;
 }
@@ -398,13 +393,13 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
 				 int idx, u8 *mac, struct station_info *sinfo)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct sta_info *sta;
 	int ret = -ENOENT;
 
 	rcu_read_lock();
 
-	sta = sta_info_get_by_idx(local, idx, dev);
+	sta = sta_info_get_by_idx(sdata, idx);
 	if (sta) {
 		ret = 0;
 		memcpy(mac, sta->sta.addr, ETH_ALEN);
@@ -827,9 +822,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 			return -EINVAL;
 		}
 
-		if (vlansdata->use_4addr) {
-			if (vlansdata->u.vlan.sta)
+		if (params->vlan->ieee80211_ptr->use_4addr) {
+			if (vlansdata->u.vlan.sta) {
+				rcu_read_unlock();
 				return -EBUSY;
+			}
 
 			rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
 		}
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 82c807723b6f..e4b54093d41b 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -52,7 +52,7 @@ DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
 		      local->wep_iv & 0xffffff);
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
-		      local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
+	local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
 
 static ssize_t tsf_read(struct file *file, char __user *user_buf,
 			     size_t count, loff_t *ppos)
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index f043c29070d7..3f41608c8081 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -157,6 +157,34 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 }
 STA_OPS(agg_status);
 
+static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	char buf[200], *p = buf;
+	int i;
+	struct sta_info *sta = file->private_data;
+	struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap;
+
+	p += scnprintf(p, sizeof(buf) + buf - p, "ht %ssupported\n",
+			htc->ht_supported ? "" : "not ");
+	if (htc->ht_supported) {
+		p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.2x\n", htc->cap);
+		p += scnprintf(p, sizeof(buf)+buf-p, "ampdu factor/density: %d/%d\n",
+				htc->ampdu_factor, htc->ampdu_density);
+		p += scnprintf(p, sizeof(buf)+buf-p, "MCS mask:");
+		for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
+			p += scnprintf(p, sizeof(buf)+buf-p, " %.2x",
+					htc->mcs.rx_mask[i]);
+		p += scnprintf(p, sizeof(buf)+buf-p, "\nMCS rx highest: %d\n",
+				le16_to_cpu(htc->mcs.rx_highest));
+		p += scnprintf(p, sizeof(buf)+buf-p, "MCS tx params: %x\n",
+				htc->mcs.tx_params);
+	}
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(ht_capa);
+
 #define DEBUGFS_ADD(name) \
 	debugfs_create_file(#name, 0400, \
 		sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -207,6 +235,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
 	DEBUGFS_ADD(last_signal);
 	DEBUGFS_ADD(last_noise);
 	DEBUGFS_ADD(wep_weak_iv_count);
+	DEBUGFS_ADD(ht_capa);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 020a94a31106..921dd9c9ff62 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -239,15 +239,16 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
 }
 
 static inline int drv_ampdu_action(struct ieee80211_local *local,
+				   struct ieee80211_vif *vif,
 				   enum ieee80211_ampdu_mlme_action action,
 				   struct ieee80211_sta *sta, u16 tid,
 				   u16 *ssn)
 {
 	int ret = -EOPNOTSUPP;
 	if (local->ops->ampdu_action)
-		ret = local->ops->ampdu_action(&local->hw, action,
+		ret = local->ops->ampdu_action(&local->hw, vif, action,
 					       sta, tid, ssn);
-	trace_drv_ampdu_action(local, action, sta, tid, ssn, ret);
+	trace_drv_ampdu_action(local, vif, action, sta, tid, ssn, ret);
 	return ret;
 }
 
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 37b9051afcf3..b8fef1d11369 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -634,11 +634,12 @@ TRACE_EVENT(drv_tx_last_beacon,
 
 TRACE_EVENT(drv_ampdu_action,
 	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_vif *vif,
 		 enum ieee80211_ampdu_mlme_action action,
 		 struct ieee80211_sta *sta, u16 tid,
 		 u16 *ssn, int ret),
 
-	TP_ARGS(local, action, sta, tid, ssn, ret),
+	TP_ARGS(local, vif, action, sta, tid, ssn, ret),
 
 	TP_STRUCT__entry(
 		LOCAL_ENTRY
@@ -647,10 +648,12 @@ TRACE_EVENT(drv_ampdu_action,
 		__field(u16, tid)
 		__field(u16, ssn)
 		__field(int, ret)
+		VIF_ENTRY
 	),
 
 	TP_fast_assign(
 		LOCAL_ASSIGN;
+		VIF_ASSIGN;
 		STA_ASSIGN;
 		__entry->ret = ret;
 		__entry->action = action;
@@ -659,8 +662,8 @@ TRACE_EVENT(drv_ampdu_action,
 	),
 
 	TP_printk(
-		LOCAL_PR_FMT  STA_PR_FMT " action:%d tid:%d ret:%d",
-		LOCAL_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
+		LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d ret:%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
 	)
 );
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 48ef1a282b91..15c9d4f94cee 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -134,14 +134,13 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
 	mgmt->u.action.u.delba.params = cpu_to_le16(params);
 	mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code);
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 			     struct sta_info *sta,
 			     struct ieee80211_mgmt *mgmt, size_t len)
 {
-	struct ieee80211_local *local = sdata->local;
 	u16 tid, params;
 	u16 initiator;
 
@@ -164,7 +163,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 		sta->ampdu_mlme.tid_state_tx[tid] =
 				HT_AGG_STATE_OPERATIONAL;
 		spin_unlock_bh(&sta->lock);
-		ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid,
+		ieee80211_stop_tx_ba_session(&sta->sta, tid,
 					     WLAN_BACK_RECIPIENT);
 	}
 }
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index fbffce90edbc..10d13856f86c 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -659,7 +659,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
 	printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
 	       sdata->dev->name, resp->da);
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index b63b99fb2fd3..04093e84ebd7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -23,6 +23,7 @@
 #include <linux/types.h>
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
+#include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
 #include "key.h"
@@ -167,13 +168,10 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
 
 struct ieee80211_rx_data {
 	struct sk_buff *skb;
-	struct net_device *dev;
 	struct ieee80211_local *local;
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
 	struct ieee80211_key *key;
-	struct ieee80211_rx_status *status;
-	struct ieee80211_rate *rate;
 
 	unsigned int flags;
 	int queue;
@@ -314,6 +312,8 @@ struct ieee80211_if_managed {
 	} mfp; /* management frame protection */
 
 	int wmm_last_param_set;
+
+	u8 use_4addr;
 };
 
 enum ieee80211_ibss_request {
@@ -461,8 +461,6 @@ struct ieee80211_sub_if_data {
 	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
 	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
 
-	bool use_4addr; /* use 4-address frames */
-
 	union {
 		struct ieee80211_if_ap ap;
 		struct ieee80211_if_wds wds;
@@ -581,7 +579,6 @@ struct ieee80211_local {
 	/* number of interfaces with corresponding FIF_ flags */
 	int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
 	unsigned int filter_flags; /* FIF_* */
-	struct iw_statistics wstats;
 
 	/* protects the aggregated multicast list and filter calls */
 	spinlock_t filter_lock;
@@ -771,8 +768,9 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
 	return netdev_priv(dev);
 }
 
-/* this struct represents 802.11n's RA/TID combination */
+/* this struct represents 802.11n's RA/TID combination along with our vif */
 struct ieee80211_ra_tid {
+	struct ieee80211_vif *vif;
 	u8 ra[ETH_ALEN];
 	u16 tid;
 };
@@ -799,7 +797,7 @@ struct ieee802_11_elems {
 	u8 *wmm_param;
 	struct ieee80211_ht_cap *ht_cap_elem;
 	struct ieee80211_ht_info *ht_info_elem;
-	u8 *mesh_config;
+	struct ieee80211_meshconf_ie *mesh_config;
 	u8 *mesh_id;
 	u8 *peer_link;
 	u8 *preq;
@@ -827,7 +825,6 @@ struct ieee802_11_elems {
 	u8 ext_supp_rates_len;
 	u8 wmm_info_len;
 	u8 wmm_param_len;
-	u8 mesh_config_len;
 	u8 mesh_id_len;
 	u8 peer_link_len;
 	u8 preq_len;
@@ -950,6 +947,18 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
 netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 				       struct net_device *dev);
 
+/*
+ * radiotap header for status frames
+ */
+struct ieee80211_tx_status_rtap_hdr {
+	struct ieee80211_radiotap_header hdr;
+	u8 rate;
+	u8 padding_for_rate;
+	__le16 tx_flags;
+	u8 data_retries;
+} __attribute__ ((packed));
+
+
 /* HT */
 void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
 				       struct ieee80211_ht_cap *ht_cap_ie,
@@ -1017,8 +1026,7 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke
 				     struct ieee80211_hdr *hdr, const u8 *tsc,
 				     gfp_t gfp);
 void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata);
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-		      int encrypt);
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
 void ieee802_11_parse_elems(u8 *start, size_t len,
 			    struct ieee802_11_elems *elems);
 u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1f02b0610e82..1bf12a26b45e 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -752,7 +752,8 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
 		ieee80211_mandatory_rates(sdata->local,
 			sdata->local->hw.conf.channel->band);
 	sdata->drop_unencrypted = 0;
-	sdata->use_4addr = 0;
+	if (type == NL80211_IFTYPE_STATION)
+		sdata->u.mgd.use_4addr = false;
 
 	return 0;
 }
@@ -810,6 +811,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 	/* setup type-dependent data */
 	ieee80211_setup_sdata(sdata, type);
 
+	if (params) {
+		ndev->ieee80211_ptr->use_4addr = params->use_4addr;
+		if (type == NL80211_IFTYPE_STATION)
+			sdata->u.mgd.use_4addr = params->use_4addr;
+	}
+
 	ret = register_netdevice(ndev);
 	if (ret)
 		goto fail;
@@ -820,9 +827,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 					    params->mesh_id_len,
 					    params->mesh_id);
 
-	if (params && params->use_4addr >= 0)
-		sdata->use_4addr = !!params->use_4addr;
-
 	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
 	mutex_unlock(&local->iflist_mtx);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index beb8718d905e..dd8ec8d5e8b2 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -9,7 +9,6 @@
  */
 
 #include <net/mac80211.h>
-#include <net/ieee80211_radiotap.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -30,26 +29,11 @@
 #include "rate.h"
 #include "mesh.h"
 #include "wep.h"
-#include "wme.h"
-#include "aes_ccm.h"
 #include "led.h"
 #include "cfg.h"
 #include "debugfs.h"
 #include "debugfs_netdev.h"
 
-/*
- * For seeing transmitted packets on monitor interfaces
- * we have a radiotap header too.
- */
-struct ieee80211_tx_status_rtap_hdr {
-	struct ieee80211_radiotap_header hdr;
-	u8 rate;
-	u8 padding_for_rate;
-	__le16 tx_flags;
-	u8 data_retries;
-} __attribute__ ((packed));
-
-
 void ieee80211_configure_filter(struct ieee80211_local *local)
 {
 	u64 mc;
@@ -253,28 +237,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
 	       BSS_CHANGED_ERP_SLOT;
 }
 
-void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
-				 struct sk_buff *skb)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	int tmp;
-
-	skb->pkt_type = IEEE80211_TX_STATUS_MSG;
-	skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
-		       &local->skb_queue : &local->skb_queue_unreliable, skb);
-	tmp = skb_queue_len(&local->skb_queue) +
-		skb_queue_len(&local->skb_queue_unreliable);
-	while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
-	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
-		dev_kfree_skb_irq(skb);
-		tmp--;
-		I802_DEBUG_INC(local->tx_status_drop);
-	}
-	tasklet_schedule(&local->tasklet);
-}
-EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
-
 static void ieee80211_tasklet_handler(unsigned long data)
 {
 	struct ieee80211_local *local = (struct ieee80211_local *) data;
@@ -296,14 +258,14 @@ static void ieee80211_tasklet_handler(unsigned long data)
 			break;
 		case IEEE80211_DELBA_MSG:
 			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-			ieee80211_stop_tx_ba_cb(local_to_hw(local),
-						ra_tid->ra, ra_tid->tid);
+			ieee80211_stop_tx_ba_cb(ra_tid->vif, ra_tid->ra,
+						ra_tid->tid);
 			dev_kfree_skb(skb);
 			break;
 		case IEEE80211_ADDBA_MSG:
 			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
-			ieee80211_start_tx_ba_cb(local_to_hw(local),
-						 ra_tid->ra, ra_tid->tid);
+			ieee80211_start_tx_ba_cb(ra_tid->vif, ra_tid->ra,
+						 ra_tid->tid);
 			dev_kfree_skb(skb);
 			break ;
 		default:
@@ -315,299 +277,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
 	}
 }
 
-static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
-					    struct sta_info *sta,
-					    struct sk_buff *skb)
-{
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
-	/*
-	 * XXX: This is temporary!
-	 *
-	 *	The problem here is that when we get here, the driver will
-	 *	quite likely have pretty much overwritten info->control by
-	 *	using info->driver_data or info->rate_driver_data. Thus,
-	 *	when passing out the frame to the driver again, we would be
-	 *	passing completely bogus data since the driver would then
-	 *	expect a properly filled info->control. In mac80211 itself
-	 *	the same problem occurs, since we need info->control.vif
-	 *	internally.
-	 *
-	 *	To fix this, we should send the frame through TX processing
-	 *	again. However, it's not that simple, since the frame will
-	 *	have been software-encrypted (if applicable) already, and
-	 *	encrypting it again doesn't do much good. So to properly do
-	 *	that, we not only have to skip the actual 'raw' encryption
-	 *	(key selection etc. still has to be done!) but also the
-	 *	sequence number assignment since that impacts the crypto
-	 *	encapsulation, of course.
-	 *
-	 *	Hence, for now, fix the bug by just dropping the frame.
-	 */
-	goto drop;
-
-	sta->tx_filtered_count++;
-
-	/*
-	 * Clear the TX filter mask for this STA when sending the next
-	 * packet. If the STA went to power save mode, this will happen
-	 * when it wakes up for the next time.
-	 */
-	set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
-
-	/*
-	 * This code races in the following way:
-	 *
-	 *  (1) STA sends frame indicating it will go to sleep and does so
-	 *  (2) hardware/firmware adds STA to filter list, passes frame up
-	 *  (3) hardware/firmware processes TX fifo and suppresses a frame
-	 *  (4) we get TX status before having processed the frame and
-	 *	knowing that the STA has gone to sleep.
-	 *
-	 * This is actually quite unlikely even when both those events are
-	 * processed from interrupts coming in quickly after one another or
-	 * even at the same time because we queue both TX status events and
-	 * RX frames to be processed by a tasklet and process them in the
-	 * same order that they were received or TX status last. Hence, there
-	 * is no race as long as the frame RX is processed before the next TX
-	 * status, which drivers can ensure, see below.
-	 *
-	 * Note that this can only happen if the hardware or firmware can
-	 * actually add STAs to the filter list, if this is done by the
-	 * driver in response to set_tim() (which will only reduce the race
-	 * this whole filtering tries to solve, not completely solve it)
-	 * this situation cannot happen.
-	 *
-	 * To completely solve this race drivers need to make sure that they
-	 *  (a) don't mix the irq-safe/not irq-safe TX status/RX processing
-	 *	functions and
-	 *  (b) always process RX events before TX status events if ordering
-	 *      can be unknown, for example with different interrupt status
-	 *	bits.
-	 */
-	if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
-	    skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
-		skb_queue_tail(&sta->tx_filtered, skb);
-		return;
-	}
-
-	if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
-	    !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
-		/* Software retry the packet once */
-		info->flags |= IEEE80211_TX_INTFL_RETRIED;
-		ieee80211_add_pending_skb(local, skb);
-		return;
-	}
-
- drop:
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	if (net_ratelimit())
-		printk(KERN_DEBUG "%s: dropped TX filtered frame, "
-		       "queue_len=%d PS=%d @%lu\n",
-		       wiphy_name(local->hw.wiphy),
-		       skb_queue_len(&sta->tx_filtered),
-		       !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
-#endif
-	dev_kfree_skb(skb);
-}
-
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-	struct sk_buff *skb2;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-	u16 frag, type;
-	__le16 fc;
-	struct ieee80211_supported_band *sband;
-	struct ieee80211_tx_status_rtap_hdr *rthdr;
-	struct ieee80211_sub_if_data *sdata;
-	struct net_device *prev_dev = NULL;
-	struct sta_info *sta;
-	int retry_count = -1, i;
-
-	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
-		/* the HW cannot have attempted that rate */
-		if (i >= hw->max_rates) {
-			info->status.rates[i].idx = -1;
-			info->status.rates[i].count = 0;
-		}
-
-		retry_count += info->status.rates[i].count;
-	}
-	if (retry_count < 0)
-		retry_count = 0;
-
-	rcu_read_lock();
-
-	sband = local->hw.wiphy->bands[info->band];
-
-	sta = sta_info_get(local, hdr->addr1);
-
-	if (sta) {
-		if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-		    test_sta_flags(sta, WLAN_STA_PS_STA)) {
-			/*
-			 * The STA is in power save mode, so assume
-			 * that this TX packet failed because of that.
-			 */
-			ieee80211_handle_filtered_frame(local, sta, skb);
-			rcu_read_unlock();
-			return;
-		}
-
-		fc = hdr->frame_control;
-
-		if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
-		    (ieee80211_is_data_qos(fc))) {
-			u16 tid, ssn;
-			u8 *qc;
-
-			qc = ieee80211_get_qos_ctl(hdr);
-			tid = qc[0] & 0xf;
-			ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
-						& IEEE80211_SCTL_SEQ);
-			ieee80211_send_bar(sta->sdata, hdr->addr1,
-					   tid, ssn);
-		}
-
-		if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-			ieee80211_handle_filtered_frame(local, sta, skb);
-			rcu_read_unlock();
-			return;
-		} else {
-			if (!(info->flags & IEEE80211_TX_STAT_ACK))
-				sta->tx_retry_failed++;
-			sta->tx_retry_count += retry_count;
-		}
-
-		rate_control_tx_status(local, sband, sta, skb);
-		if (ieee80211_vif_is_mesh(&sta->sdata->vif))
-			ieee80211s_update_metric(local, sta, skb);
-	}
-
-	rcu_read_unlock();
-
-	ieee80211_led_tx(local, 0);
-
-	/* SNMP counters
-	 * Fragments are passed to low-level drivers as separate skbs, so these
-	 * are actually fragments, not frames. Update frame counters only for
-	 * the first fragment of the frame. */
-
-	frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
-	type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
-
-	if (info->flags & IEEE80211_TX_STAT_ACK) {
-		if (frag == 0) {
-			local->dot11TransmittedFrameCount++;
-			if (is_multicast_ether_addr(hdr->addr1))
-				local->dot11MulticastTransmittedFrameCount++;
-			if (retry_count > 0)
-				local->dot11RetryCount++;
-			if (retry_count > 1)
-				local->dot11MultipleRetryCount++;
-		}
-
-		/* This counter shall be incremented for an acknowledged MPDU
-		 * with an individual address in the address 1 field or an MPDU
-		 * with a multicast address in the address 1 field of type Data
-		 * or Management. */
-		if (!is_multicast_ether_addr(hdr->addr1) ||
-		    type == IEEE80211_FTYPE_DATA ||
-		    type == IEEE80211_FTYPE_MGMT)
-			local->dot11TransmittedFragmentCount++;
-	} else {
-		if (frag == 0)
-			local->dot11FailedCount++;
-	}
-
-	/* this was a transmitted frame, but now we want to reuse it */
-	skb_orphan(skb);
-
-	/*
-	 * This is a bit racy but we can avoid a lot of work
-	 * with this test...
-	 */
-	if (!local->monitors && !local->cooked_mntrs) {
-		dev_kfree_skb(skb);
-		return;
-	}
-
-	/* send frame to monitor interfaces now */
-
-	if (skb_headroom(skb) < sizeof(*rthdr)) {
-		printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-
-	rthdr = (struct ieee80211_tx_status_rtap_hdr *)
-				skb_push(skb, sizeof(*rthdr));
-
-	memset(rthdr, 0, sizeof(*rthdr));
-	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
-	rthdr->hdr.it_present =
-		cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
-			    (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
-			    (1 << IEEE80211_RADIOTAP_RATE));
-
-	if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
-	    !is_multicast_ether_addr(hdr->addr1))
-		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
-
-	/*
-	 * XXX: Once radiotap gets the bitmap reset thing the vendor
-	 *	extensions proposal contains, we can actually report
-	 *	the whole set of tries we did.
-	 */
-	if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
-	    (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
-		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
-	else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
-	if (info->status.rates[0].idx >= 0 &&
-	    !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
-		rthdr->rate = sband->bitrates[
-				info->status.rates[0].idx].bitrate / 5;
-
-	/* for now report the total retry_count */
-	rthdr->data_retries = retry_count;
-
-	/* XXX: is this sufficient for BPF? */
-	skb_set_mac_header(skb, 0);
-	skb->ip_summed = CHECKSUM_UNNECESSARY;
-	skb->pkt_type = PACKET_OTHERHOST;
-	skb->protocol = htons(ETH_P_802_2);
-	memset(skb->cb, 0, sizeof(skb->cb));
-
-	rcu_read_lock();
-	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
-			if (!netif_running(sdata->dev))
-				continue;
-
-			if (prev_dev) {
-				skb2 = skb_clone(skb, GFP_ATOMIC);
-				if (skb2) {
-					skb2->dev = prev_dev;
-					netif_rx(skb2);
-				}
-			}
-
-			prev_dev = sdata->dev;
-		}
-	}
-	if (prev_dev) {
-		skb->dev = prev_dev;
-		netif_rx(skb);
-		skb = NULL;
-	}
-	rcu_read_unlock();
-	dev_kfree_skb(skb);
-}
-EXPORT_SYMBOL(ieee80211_tx_status);
-
 static void ieee80211_restart_work(struct work_struct *work)
 {
 	struct ieee80211_local *local =
@@ -659,7 +328,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	if (!wiphy)
 		return NULL;
 
-	wiphy->netnsok = true;
+	wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+			WIPHY_FLAG_4ADDR_AP |
+			WIPHY_FLAG_4ADDR_STATION;
 	wiphy->privid = mac80211_wiphy_privid;
 
 	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index bbd56b087899..51adb1115215 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -16,12 +16,6 @@
 #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 #define IEEE80211_MESH_RANN_INTERVAL	     (1 * HZ)
 
-#define MESHCONF_PP_OFFSET 	0		/* Path Selection Protocol */
-#define MESHCONF_PM_OFFSET	1		/* Path Selection Metric   */
-#define MESHCONF_CC_OFFSET	2		/* Congestion Control Mode */
-#define MESHCONF_SP_OFFSET	3		/* Synchronization Protocol */
-#define MESHCONF_AUTH_OFFSET	4		/* Authentication Protocol */
-#define MESHCONF_CAPAB_OFFSET 	6
 #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
 #define MESHCONF_CAPAB_FORWARDING    0x08
 
@@ -87,12 +81,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
 	 */
 	if (ifmsh->mesh_id_len == ie->mesh_id_len &&
 		memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-		(ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&&
-		(ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&&
-		(ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&&
-		(ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&&
-		(ifmsh->mesh_auth_id == *(ie->mesh_config +
-		    MESHCONF_AUTH_OFFSET)))
+		(ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
+		(ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
+		(ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
+		(ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
+		(ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
 		return true;
 
 	return false;
@@ -105,7 +98,7 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
  */
 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
 {
-	return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) &
+	return (ie->mesh_config->meshconf_cap &
 	    MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
 }
 
@@ -262,9 +255,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
 	if (sdata->u.mesh.mesh_id_len)
 		memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
 
-	pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN);
+	pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
 	*pos++ = WLAN_EID_MESH_CONFIG;
-	*pos++ = IEEE80211_MESH_CONFIG_LEN;
+	*pos++ = sizeof(struct ieee80211_meshconf_ie);
 
 	/* Active path selection protocol ID */
 	*pos++ = sdata->u.mesh.mesh_pp_id;
@@ -394,8 +387,9 @@ void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
  *
  * Return the length of the 802.11 (does not include a mesh control header)
  */
-int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
-		*meshda, char *meshsa) {
+int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
+				  const u8 *meshda, const u8 *meshsa)
+{
 	if (is_multicast_ether_addr(meshda)) {
 		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 		/* DA TA SA */
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index bd0e1cbb9a1e..31e102541869 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -220,7 +220,7 @@ struct mesh_rmc {
 /* Public interfaces */
 /* Various */
 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
-		char *da, char *sa);
+				  const u8 *da, const u8 *sa);
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
 		struct ieee80211_sub_if_data *sdata, char *addr4,
 		char *addr5, char *addr6);
@@ -284,7 +284,7 @@ u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
 		struct mesh_table *tbl);
 /* Mesh paths */
 int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode,
-		u8 *ra, struct ieee80211_sub_if_data *sdata);
+		       const u8 *ra, struct ieee80211_sub_if_data *sdata);
 void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
 void mesh_path_flush_pending(struct mesh_path *mpath);
 void mesh_path_tx_pending(struct mesh_path *mpath);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 5c67e7b8790f..9aecf0207afc 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -101,10 +101,12 @@ enum mpath_frame_type {
 	MPATH_RANN
 };
 
+static const u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
 static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 		u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target,
-		__le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime,
-		__le32 metric, __le32 preq_id,
+		__le32 target_sn, const u8 *da, u8 hop_count, u8 ttl,
+		__le32 lifetime, __le32 metric, __le32 preq_id,
 		struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
@@ -185,7 +187,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
 		memcpy(pos, &target_sn, 4);
 	}
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 	return 0;
 }
 
@@ -198,8 +200,8 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
  * @ra: node this frame is addressed to
  */
 int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
-		__le16 target_rcode, u8 *ra,
-		struct ieee80211_sub_if_data *sdata)
+		       __le16 target_rcode, const u8 *ra,
+		       struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_local *local = sdata->local;
 	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
@@ -248,7 +250,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 	pos += 4;
 	memcpy(pos, &target_rcode, 2);
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 	return 0;
 }
 
@@ -548,7 +550,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
 		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
 		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
 				cpu_to_le32(orig_sn), target_flags, target_addr,
-				cpu_to_le32(target_sn), sdata->dev->broadcast,
+				cpu_to_le32(target_sn), broadcast_addr,
 				hopcount, ttl, cpu_to_le32(lifetime),
 				cpu_to_le32(metric), cpu_to_le32(preq_id),
 				sdata);
@@ -660,7 +662,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
 			spin_unlock_bh(&mpath->state_lock);
 			mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn),
 					   cpu_to_le16(target_rcode),
-					   sdata->dev->broadcast, sdata);
+					   broadcast_addr, sdata);
 		} else
 			spin_unlock_bh(&mpath->state_lock);
 	}
@@ -709,7 +711,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
 	if (mpath->sn < orig_sn) {
 		mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
 				       cpu_to_le32(orig_sn),
-				       0, NULL, 0, sdata->dev->broadcast,
+				       0, NULL, 0, broadcast_addr,
 				       hopcount, ttl, 0,
 				       cpu_to_le32(metric + mpath->metric),
 				       0, sdata);
@@ -890,7 +892,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
 	spin_unlock_bh(&mpath->state_lock);
 	mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr,
 			cpu_to_le32(ifmsh->sn), target_flags, mpath->dst,
-			cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0,
+			cpu_to_le32(mpath->sn), broadcast_addr, 0,
 			ttl, cpu_to_le32(lifetime), 0,
 			cpu_to_le32(ifmsh->preq_id++), sdata);
 	mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
@@ -1011,6 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata)
 
 	mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr,
 			       cpu_to_le32(++ifmsh->sn),
-			       0, NULL, 0, sdata->dev->broadcast,
+			       0, NULL, 0, broadcast_addr,
 			       0, MESH_TTL, 0, 0, 0, sdata);
 }
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 5399e7a9ec6e..a8da23905c70 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -449,6 +449,7 @@ err_path_alloc:
  */
 void mesh_plink_broken(struct sta_info *sta)
 {
+	static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 	struct mesh_path *mpath;
 	struct mpath_node *node;
 	struct hlist_node *p;
@@ -467,8 +468,8 @@ void mesh_plink_broken(struct sta_info *sta)
 			spin_unlock_bh(&mpath->state_lock);
 			mesh_path_error_tx(MESH_TTL, mpath->dst,
 					cpu_to_le32(mpath->sn),
-					PERR_RCODE_DEST_UNREACH,
-					sdata->dev->broadcast, sdata);
+					cpu_to_le16(PERR_RCODE_DEST_UNREACH),
+					bcast, sdata);
 		} else
 		spin_unlock_bh(&mpath->state_lock);
 	}
@@ -613,7 +614,7 @@ void mesh_path_discard_frame(struct sk_buff *skb,
 		if (mpath)
 			sn = ++mpath->sn;
 		mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn),
-				   PERR_RCODE_NO_ROUTE, ra, sdata);
+				   cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
 	}
 
 	kfree_skb(skb);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index f21329afdae3..0f7c6e6a4248 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -222,7 +222,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 		memcpy(pos, &reason, 2);
 	}
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 	return 0;
 }
 
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 2af306f67d78..6dc7b5ad9a41 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -426,7 +426,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 		memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
 	}
 
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 
@@ -467,7 +468,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 			__cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
 		else
 			cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
-	ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
+	if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
+		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -498,7 +501,8 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
 	memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
 	memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
 
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_send_nullfunc(struct ieee80211_local *local,
@@ -531,7 +535,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
 	memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
 	memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
 
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 /* spectrum management related things */
@@ -2503,6 +2508,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 	struct ieee80211_mgd_work *wk;
 	const u8 *bssid = NULL;
+	bool not_auth_yet = false;
 
 	mutex_lock(&ifmgd->mtx);
 
@@ -2512,6 +2518,8 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 	} else list_for_each_entry(wk, &ifmgd->work_list, list) {
 		if (&wk->bss->cbss == req->bss) {
 			bssid = req->bss->bssid;
+			if (wk->state == IEEE80211_MGD_STATE_PROBE)
+				not_auth_yet = true;
 			list_del(&wk->list);
 			kfree(wk);
 			break;
@@ -2519,6 +2527,20 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 	}
 
 	/*
+	 * If somebody requests authentication and we haven't
+	 * sent out an auth frame yet there's no need to send
+	 * out a deauth frame either. If the state was PROBE,
+	 * then this is the case. If it's AUTH we have sent a
+	 * frame, and if it's IDLE we have completed the auth
+	 * process already.
+	 */
+	if (not_auth_yet) {
+		mutex_unlock(&ifmgd->mtx);
+		__cfg80211_auth_canceled(sdata->dev, bssid);
+		return 0;
+	}
+
+	/*
 	 * cfg80211 should catch this ... but it's racy since
 	 * we can receive a deauth frame, process it, hand it
 	 * to cfg80211 while that's in a locked section already
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index ccda7454fb17..b9007f80cb92 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -284,9 +284,16 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
 	struct rate_control_ref *ref, *old;
 
 	ASSERT_RTNL();
+
 	if (local->open_count)
 		return -EBUSY;
 
+	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+		if (WARN_ON(!local->ops->set_rts_threshold))
+			return -EINVAL;
+		return 0;
+	}
+
 	ref = rate_control_alloc(name, local);
 	if (!ref) {
 		printk(KERN_WARNING "%s: Failed to select rate control "
@@ -305,7 +312,6 @@ int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
 	       "algorithm '%s'\n", wiphy_name(local->hw.wiphy),
 	       ref->ops->name);
 
-
 	return 0;
 }
 
@@ -314,6 +320,10 @@ void rate_control_deinitialize(struct ieee80211_local *local)
 	struct rate_control_ref *ref;
 
 	ref = local->rate_ctrl;
+
+	if (!ref)
+		return;
+
 	local->rate_ctrl = NULL;
 	rate_control_put(ref);
 }
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 2ab5ad9e71ce..cb9bd1f65e27 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -59,6 +59,9 @@ static inline void rate_control_rate_init(struct sta_info *sta)
 	void *priv_sta = sta->rate_ctrl_priv;
 	struct ieee80211_supported_band *sband;
 
+	if (!ref)
+		return;
+
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
@@ -72,7 +75,7 @@ static inline void rate_control_rate_update(struct ieee80211_local *local,
 	struct ieee80211_sta *ista = &sta->sta;
 	void *priv_sta = sta->rate_ctrl_priv;
 
-	if (ref->ops->rate_update)
+	if (ref && ref->ops->rate_update)
 		ref->ops->rate_update(ref->priv, sband, ista,
 				      priv_sta, changed);
 }
@@ -97,7 +100,7 @@ static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
 {
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct rate_control_ref *ref = sta->rate_ctrl;
-	if (sta->debugfs.dir && ref->ops->add_sta_debugfs)
+	if (ref && sta->debugfs.dir && ref->ops->add_sta_debugfs)
 		ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv,
 					  sta->debugfs.dir);
 #endif
@@ -107,7 +110,7 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 {
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct rate_control_ref *ref = sta->rate_ctrl;
-	if (ref->ops->remove_sta_debugfs)
+	if (ref && ref->ops->remove_sta_debugfs)
 		ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv);
 #endif
 }
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6bce97ee2534..96f13ad05d3c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -27,11 +27,10 @@
 #include "tkip.h"
 #include "wme.h"
 
-static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-					   struct tid_ampdu_rx *tid_agg_rx,
-					   struct sk_buff *skb,
-					   u16 mpdu_seq_num,
-					   int bar_req);
+static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
+					     struct tid_ampdu_rx *tid_agg_rx,
+					     u16 head_seq_num);
+
 /*
  * monitor mode reception
  *
@@ -164,6 +163,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
 	if (status->band == IEEE80211_BAND_5GHZ)
 		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
 				   pos);
+	else if (status->flag & RX_FLAG_HT)
+		put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
+				   pos);
 	else if (rate->flags & IEEE80211_RATE_ERP_G)
 		put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
 				   pos);
@@ -478,7 +480,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 	unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
-	char *dev_addr = rx->dev->dev_addr;
+	char *dev_addr = rx->sdata->dev->dev_addr;
 
 	if (ieee80211_is_data(hdr->frame_control)) {
 		if (is_multicast_ether_addr(hdr->addr1)) {
@@ -592,7 +594,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	int keyidx;
 	int hdrlen;
 	ieee80211_rx_result result = RX_DROP_UNUSABLE;
@@ -646,8 +650,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 			return RX_CONTINUE;
 	} else if (mmie_keyidx >= 0) {
 		/* Broadcast/multicast robust management frame / BIP */
-		if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-		    (rx->status->flag & RX_FLAG_IV_STRIPPED))
+		if ((status->flag & RX_FLAG_DECRYPTED) &&
+		    (status->flag & RX_FLAG_IV_STRIPPED))
 			return RX_CONTINUE;
 
 		if (mmie_keyidx < NUM_DEFAULT_KEYS ||
@@ -679,8 +683,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 		 * we somehow allow the driver to tell us which key
 		 * the hardware used if this flag is set?
 		 */
-		if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-		    (rx->status->flag & RX_FLAG_IV_STRIPPED))
+		if ((status->flag & RX_FLAG_DECRYPTED) &&
+		    (status->flag & RX_FLAG_IV_STRIPPED))
 			return RX_CONTINUE;
 
 		hdrlen = ieee80211_hdrlen(hdr->frame_control);
@@ -716,8 +720,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 	/* Check for weak IVs if possible */
 	if (rx->sta && rx->key->conf.alg == ALG_WEP &&
 	    ieee80211_is_data(hdr->frame_control) &&
-	    (!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
-	     !(rx->status->flag & RX_FLAG_DECRYPTED)) &&
+	    (!(status->flag & RX_FLAG_IV_STRIPPED) ||
+	     !(status->flag & RX_FLAG_DECRYPTED)) &&
 	    ieee80211_wep_is_weak_iv(rx->skb, rx->key))
 		rx->sta->wep_weak_iv_count++;
 
@@ -737,7 +741,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 	}
 
 	/* either the frame has been decrypted or will be dropped */
-	rx->status->flag |= RX_FLAG_DECRYPTED;
+	status->flag |= RX_FLAG_DECRYPTED;
 
 	return result;
 }
@@ -817,7 +821,9 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
 	struct sta_info *sta = rx->sta;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (!sta)
 		return RX_CONTINUE;
@@ -848,8 +854,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
 	sta->rx_fragments++;
 	sta->rx_bytes += rx->skb->len;
-	sta->last_signal = rx->status->signal;
-	sta->last_noise = rx->status->noise;
+	sta->last_signal = status->signal;
+	sta->last_noise = status->noise;
 
 	/*
 	 * Change STA power saving mode only at the end of a frame
@@ -1141,11 +1147,14 @@ ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 static int
 ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 {
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
 	/*
 	 * Pass through unencrypted frames if the hardware has
 	 * decrypted them already.
 	 */
-	if (rx->status->flag & RX_FLAG_DECRYPTED)
+	if (status->flag & RX_FLAG_DECRYPTED)
 		return 0;
 
 	/* Drop unencrypted frames if key is set. */
@@ -1179,14 +1188,17 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 static int
 __ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
-	struct net_device *dev = rx->dev;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
+	struct net_device *dev = sdata->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr &&
-	    ieee80211_has_a4(hdr->frame_control))
+	if (ieee80211_has_a4(hdr->frame_control) &&
+	    sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->u.vlan.sta)
 		return -1;
-	if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
+
+	if (is_multicast_ether_addr(hdr->addr1) &&
+	    ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN && sdata->u.vlan.sta) ||
+	     (sdata->vif.type == NL80211_IFTYPE_STATION && sdata->u.mgd.use_4addr)))
 		return -1;
 
 	return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
@@ -1206,7 +1218,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
 	 * of whether the frame was encrypted or not.
 	 */
 	if (ehdr->h_proto == htons(ETH_P_PAE) &&
-	    (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
+	    (compare_ether_addr(ehdr->h_dest, rx->sdata->dev->dev_addr) == 0 ||
 	     compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
 		return true;
 
@@ -1223,10 +1235,10 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
 static void
 ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 {
-	struct net_device *dev = rx->dev;
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
+	struct net_device *dev = sdata->dev;
 	struct ieee80211_local *local = rx->local;
 	struct sk_buff *skb, *xmit_skb;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
 	struct sta_info *dsta;
 
@@ -1236,7 +1248,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 	if ((sdata->vif.type == NL80211_IFTYPE_AP ||
 	     sdata->vif.type == NL80211_IFTYPE_AP_VLAN) &&
 	    !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) &&
-	    (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) {
+	    (rx->flags & IEEE80211_RX_RA_MATCH) &&
+	    (sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->u.vlan.sta)) {
 		if (is_multicast_ether_addr(ehdr->h_dest)) {
 			/*
 			 * send multicast frames both to higher layers in
@@ -1307,7 +1320,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
-	struct net_device *dev = rx->dev;
+	struct net_device *dev = rx->sdata->dev;
 	struct ieee80211_local *local = rx->local;
 	u16 ethertype;
 	u8 *payload;
@@ -1432,12 +1445,11 @@ 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;
+	struct ieee80211_sub_if_data *sdata = rx->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;
@@ -1475,7 +1487,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
 	/* Frame has reached destination.  Don't forward */
 	if (!is_multicast_ether_addr(hdr->addr1) &&
-			compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+	    compare_ether_addr(sdata->dev->dev_addr, hdr->addr3) == 0)
 		return RX_CONTINUE;
 
 	mesh_hdr->ttl--;
@@ -1492,10 +1504,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 
 			if (!fwd_skb && net_ratelimit())
 				printk(KERN_DEBUG "%s: failed to clone mesh frame\n",
-						   rx->dev->name);
+						   sdata->dev->name);
 
 			fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-			memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
+			memcpy(fwd_hdr->addr2, sdata->dev->dev_addr, ETH_ALEN);
 			info = IEEE80211_SKB_CB(fwd_skb);
 			memset(info, 0, sizeof(*info));
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
@@ -1529,7 +1541,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 	}
 
 	if (is_multicast_ether_addr(hdr->addr1) ||
-	    rx->dev->flags & IFF_PROMISC)
+	    sdata->dev->flags & IFF_PROMISC)
 		return RX_CONTINUE;
 	else
 		return RX_DROP_MONITOR;
@@ -1539,9 +1551,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 {
-	struct net_device *dev = rx->dev;
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
+	struct net_device *dev = sdata->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	__le16 fc = hdr->frame_control;
 	int err;
 
@@ -1592,11 +1604,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 
 	if (ieee80211_is_back_req(bar->frame_control)) {
 		if (!rx->sta)
-			return RX_CONTINUE;
+			return RX_DROP_MONITOR;
 		tid = le16_to_cpu(bar->control) >> 12;
 		if (rx->sta->ampdu_mlme.tid_state_rx[tid]
 					!= HT_AGG_STATE_OPERATIONAL)
-			return RX_CONTINUE;
+			return RX_DROP_MONITOR;
 		tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
 		start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
@@ -1606,13 +1618,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 			mod_timer(&tid_agg_rx->session_timer,
 				  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
-		/* manage reordering buffer according to requested */
-		/* sequence number */
-		rcu_read_lock();
-		ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
-						 start_seq_num, 1);
-		rcu_read_unlock();
-		return RX_DROP_UNUSABLE;
+		/* release stored frames up to start of BAR */
+		ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num);
+		kfree_skb(skb);
+		return RX_QUEUED;
 	}
 
 	return RX_CONTINUE;
@@ -1661,14 +1670,14 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
 	       mgmt->u.action.u.sa_query.trans_id,
 	       WLAN_SA_QUERY_TR_ID_LEN);
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 }
 
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_local *local = rx->local;
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
 	int len = rx->skb->len;
 
@@ -1780,7 +1789,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+	struct ieee80211_sub_if_data *sdata = rx->sdata;
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
 
 	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
@@ -1818,11 +1827,11 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
 		 * Some hardware seem to generate incorrect Michael MIC
 		 * reports; ignore them to avoid triggering countermeasures.
 		 */
-		goto ignore;
+		return;
 	}
 
 	if (!ieee80211_has_protected(hdr->frame_control))
-		goto ignore;
+		return;
 
 	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
 		/*
@@ -1831,35 +1840,33 @@ static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
 		 * group keys and only the AP is sending real multicast
 		 * frames in the BSS.
 		 */
-		goto ignore;
+		return;
 	}
 
 	if (!ieee80211_is_data(hdr->frame_control) &&
 	    !ieee80211_is_auth(hdr->frame_control))
-		goto ignore;
+		return;
 
 	mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
 					GFP_ATOMIC);
- ignore:
-	dev_kfree_skb(rx->skb);
-	rx->skb = NULL;
 }
 
 /* TODO: use IEEE80211_RX_FRAGMENTED */
-static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
+static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
+					struct ieee80211_rate *rate)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local = rx->local;
 	struct ieee80211_rtap_hdr {
 		struct ieee80211_radiotap_header hdr;
 		u8 flags;
-		u8 rate;
+		u8 rate_or_pad;
 		__le16 chan_freq;
 		__le16 chan_flags;
 	} __attribute__ ((packed)) *rthdr;
 	struct sk_buff *skb = rx->skb, *skb2;
 	struct net_device *prev_dev = NULL;
-	struct ieee80211_rx_status *status = rx->status;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
 	if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
 		goto out_free_skb;
@@ -1873,10 +1880,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
 	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
 	rthdr->hdr.it_present =
 		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
-			    (1 << IEEE80211_RADIOTAP_RATE) |
 			    (1 << IEEE80211_RADIOTAP_CHANNEL));
 
-	rthdr->rate = rx->rate->bitrate / 5;
+	if (rate) {
+		rthdr->rate_or_pad = rate->bitrate / 5;
+		rthdr->hdr.it_present |=
+			cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE);
+	}
 	rthdr->chan_freq = cpu_to_le16(status->freq);
 
 	if (status->band == IEEE80211_BAND_5GHZ)
@@ -1929,13 +1939,13 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
 
 static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
 					 struct ieee80211_rx_data *rx,
-					 struct sk_buff *skb)
+					 struct sk_buff *skb,
+					 struct ieee80211_rate *rate)
 {
 	ieee80211_rx_result res = RX_DROP_MONITOR;
 
 	rx->skb = skb;
 	rx->sdata = sdata;
-	rx->dev = sdata->dev;
 
 #define CALL_RXH(rxh)			\
 	do {				\
@@ -1974,7 +1984,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
 			rx->sta->rx_dropped++;
 		/* fall through */
 	case RX_CONTINUE:
-		ieee80211_rx_cooked_monitor(rx);
+		ieee80211_rx_cooked_monitor(rx, rate);
 		break;
 	case RX_DROP_UNUSABLE:
 		I802_DEBUG_INC(sdata->local->rx_handlers_drop);
@@ -1994,12 +2004,14 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 				struct ieee80211_rx_data *rx,
 				struct ieee80211_hdr *hdr)
 {
-	u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, sdata->vif.type);
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	u8 *bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
 	int multicast = is_multicast_ether_addr(hdr->addr1);
 
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_STATION:
-		if (!bssid && !sdata->use_4addr)
+		if (!bssid && !sdata->u.mgd.use_4addr)
 			return 0;
 		if (!multicast &&
 		    compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
@@ -2026,10 +2038,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		} else if (!rx->sta) {
 			int rate_idx;
-			if (rx->status->flag & RX_FLAG_HT)
+			if (status->flag & RX_FLAG_HT)
 				rate_idx = 0; /* TODO: HT rates */
 			else
-				rate_idx = rx->status->rate_idx;
+				rate_idx = status->rate_idx;
 			rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2,
 				BIT(rate_idx));
 		}
@@ -2064,8 +2076,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 			return 0;
 		break;
 	case NL80211_IFTYPE_MONITOR:
-		/* take everything */
-		break;
 	case NL80211_IFTYPE_UNSPECIFIED:
 	case __NL80211_IFTYPE_AFTER_LAST:
 		/* should never get here */
@@ -2098,23 +2108,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	rx.skb = skb;
 	rx.local = local;
 
-	rx.status = status;
-	rx.rate = rate;
-
 	if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control))
 		local->dot11ReceivedFragmentCount++;
 
-	rx.sta = sta_info_get(local, hdr->addr2);
-	if (rx.sta) {
-		rx.sdata = rx.sta->sdata;
-		rx.dev = rx.sta->sdata->dev;
-	}
-
-	if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-		ieee80211_rx_michael_mic_report(hdr, &rx);
-		return;
-	}
-
 	if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
 		     test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
 		rx.flags |= IEEE80211_RX_IN_SCAN;
@@ -2122,13 +2118,20 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	ieee80211_parse_qos(&rx);
 	ieee80211_verify_alignment(&rx);
 
-	skb = rx.skb;
+	rx.sta = sta_info_get(local, hdr->addr2);
+	if (rx.sta)
+		rx.sdata = rx.sta->sdata;
 
 	if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
 		rx.flags |= IEEE80211_RX_RA_MATCH;
 		prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
-		if (prepares)
-			prev = rx.sdata;
+		if (prepares) {
+			if (status->flag & RX_FLAG_MMIC_ERROR) {
+				if (rx.flags & IEEE80211_RX_RA_MATCH)
+					ieee80211_rx_michael_mic_report(hdr, &rx);
+			} else
+				prev = rx.sdata;
+		}
 	} else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (!netif_running(sdata->dev))
 			continue;
@@ -2143,6 +2146,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 		if (!prepares)
 			continue;
 
+		if (status->flag & RX_FLAG_MMIC_ERROR) {
+			rx.sdata = sdata;
+			if (rx.flags & IEEE80211_RX_RA_MATCH)
+				ieee80211_rx_michael_mic_report(hdr, &rx);
+			continue;
+		}
+
 		/*
 		 * frame is destined for this interface, but if it's not
 		 * also for the previous one we handle that after the
@@ -2168,11 +2178,11 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 				       prev->dev->name);
 			continue;
 		}
-		ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
+		ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate);
 		prev = sdata;
 	}
 	if (prev)
-		ieee80211_invoke_rx_handlers(prev, &rx, skb);
+		ieee80211_invoke_rx_handlers(prev, &rx, skb, rate);
 	else
 		dev_kfree_skb(skb);
 }
@@ -2201,7 +2211,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
 					    int index)
 {
 	struct ieee80211_supported_band *sband;
-	struct ieee80211_rate *rate;
+	struct ieee80211_rate *rate = NULL;
 	struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
 	struct ieee80211_rx_status *status;
 
@@ -2212,9 +2222,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
 
 	/* release the reordered frames to stack */
 	sband = hw->wiphy->bands[status->band];
-	if (status->flag & RX_FLAG_HT)
-		rate = sband->bitrates; /* TODO: HT rates */
-	else
+	if (!(status->flag & RX_FLAG_HT))
 		rate = &sband->bitrates[status->rate_idx];
 	__ieee80211_rx_handle_packet(hw, skb, rate);
 	tid_agg_rx->stored_mpdu_num--;
@@ -2224,6 +2232,18 @@ no_frame:
 	tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
 }
 
+static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
+					     struct tid_ampdu_rx *tid_agg_rx,
+					     u16 head_seq_num)
+{
+	int index;
+
+	while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+		index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+							tid_agg_rx->buf_size;
+		ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
+	}
+}
 
 /*
  * Timeout (in jiffies) for skb's that are waiting in the RX reorder buffer. If
@@ -2235,15 +2255,17 @@ no_frame:
 #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10)
 
 /*
- * As it function blongs to Rx path it must be called with
- * the proper rcu_read_lock protection for its flow.
+ * As this function belongs to the RX path it must be under
+ * rcu_read_lock protection. It returns false if the frame
+ * can be processed immediately, true if it was consumed.
  */
-static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
-					   struct tid_ampdu_rx *tid_agg_rx,
-					   struct sk_buff *skb,
-					   u16 mpdu_seq_num,
-					   int bar_req)
+static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
+					     struct tid_ampdu_rx *tid_agg_rx,
+					     struct sk_buff *skb)
 {
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u16 sc = le16_to_cpu(hdr->seq_ctrl);
+	u16 mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
 	u16 head_seq_num, buf_size;
 	int index;
 
@@ -2253,47 +2275,37 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 	/* frame with out of date sequence number */
 	if (seq_less(mpdu_seq_num, head_seq_num)) {
 		dev_kfree_skb(skb);
-		return 1;
+		return true;
 	}
 
-	/* if frame sequence number exceeds our buffering window size or
-	 * block Ack Request arrived - release stored frames */
-	if ((!seq_less(mpdu_seq_num, head_seq_num + buf_size)) || (bar_req)) {
-		/* new head to the ordering buffer */
-		if (bar_req)
-			head_seq_num = mpdu_seq_num;
-		else
-			head_seq_num =
-				seq_inc(seq_sub(mpdu_seq_num, buf_size));
+	/*
+	 * If frame the sequence number exceeds our buffering window
+	 * size release some previous frames to make room for this one.
+	 */
+	if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
+		head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
 		/* release stored frames up to new head to stack */
-		while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
-			index = seq_sub(tid_agg_rx->head_seq_num,
-				tid_agg_rx->ssn)
-				% tid_agg_rx->buf_size;
-			ieee80211_release_reorder_frame(hw, tid_agg_rx,
-							index);
-		}
-		if (bar_req)
-			return 1;
+		ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num);
 	}
 
-	/* now the new frame is always in the range of the reordering */
-	/* buffer window */
-	index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn)
-				% tid_agg_rx->buf_size;
+	/* Now the new frame is always in the range of the reordering buffer */
+
+	index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+
 	/* check if we already stored this frame */
 	if (tid_agg_rx->reorder_buf[index]) {
 		dev_kfree_skb(skb);
-		return 1;
+		return true;
 	}
 
-	/* if arrived mpdu is in the right order and nothing else stored */
-	/* release it immediately */
+	/*
+	 * If the current MPDU is in the right order and nothing else
+	 * is stored we can process it directly, no need to buffer it.
+	 */
 	if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
-			tid_agg_rx->stored_mpdu_num == 0) {
-		tid_agg_rx->head_seq_num =
-			seq_inc(tid_agg_rx->head_seq_num);
-		return 0;
+	    tid_agg_rx->stored_mpdu_num == 0) {
+		tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+		return false;
 	}
 
 	/* put the frame in the reordering buffer */
@@ -2301,8 +2313,8 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 	tid_agg_rx->reorder_time[index] = jiffies;
 	tid_agg_rx->stored_mpdu_num++;
 	/* release the buffer until next missing frame */
-	index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn)
-						% tid_agg_rx->buf_size;
+	index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+						tid_agg_rx->buf_size;
 	if (!tid_agg_rx->reorder_buf[index] &&
 	    tid_agg_rx->stored_mpdu_num > 1) {
 		/*
@@ -2313,12 +2325,12 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 		int skipped = 1;
 		for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
 		     j = (j + 1) % tid_agg_rx->buf_size) {
-			if (tid_agg_rx->reorder_buf[j] == NULL) {
+			if (!tid_agg_rx->reorder_buf[j]) {
 				skipped++;
 				continue;
 			}
 			if (!time_after(jiffies, tid_agg_rx->reorder_time[j] +
-					HZ / 10))
+					HT_RX_REORDER_BUF_TIMEOUT))
 				break;
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -2334,51 +2346,56 @@ static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 			 * Increment the head seq# also for the skipped slots.
 			 */
 			tid_agg_rx->head_seq_num =
-				(tid_agg_rx->head_seq_num + skipped) &
-				SEQ_MASK;
+				(tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
 			skipped = 0;
 		}
 	} else while (tid_agg_rx->reorder_buf[index]) {
 		ieee80211_release_reorder_frame(hw, tid_agg_rx, index);
-		index =	seq_sub(tid_agg_rx->head_seq_num,
-			tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+		index =	seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+							tid_agg_rx->buf_size;
 	}
-	return 1;
+
+	return true;
 }
 
-static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
-				     struct sk_buff *skb)
+/*
+ * Reorder MPDUs from A-MPDUs, keeping them on a buffer. Returns
+ * true if the MPDU was buffered, false if it should be processed.
+ */
+static bool ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
+				       struct sk_buff *skb)
 {
 	struct ieee80211_hw *hw = &local->hw;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct sta_info *sta;
 	struct tid_ampdu_rx *tid_agg_rx;
 	u16 sc;
-	u16 mpdu_seq_num;
-	u8 ret = 0;
 	int tid;
 
+	if (!ieee80211_is_data_qos(hdr->frame_control))
+		return false;
+
+	/*
+	 * filter the QoS data rx stream according to
+	 * STA/TID and check if this STA/TID is on aggregation
+	 */
+
 	sta = sta_info_get(local, hdr->addr2);
 	if (!sta)
-		return ret;
-
-	/* filter the QoS data rx stream according to
-	 * STA/TID and check if this STA/TID is on aggregation */
-	if (!ieee80211_is_data_qos(hdr->frame_control))
-		goto end_reorder;
+		return false;
 
 	tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
 	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
-		goto end_reorder;
+		return false;
 
 	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
 
 	/* qos null data frames are excluded */
 	if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
-		goto end_reorder;
+		return false;
 
-	/* new un-ordered ampdu frame - process it */
+	/* new, potentially un-ordered, ampdu frame - process it */
 
 	/* reset session timer */
 	if (tid_agg_rx->timeout)
@@ -2390,16 +2407,11 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 	if (sc & IEEE80211_SCTL_FRAG) {
 		ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
 			tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
-		ret = 1;
-		goto end_reorder;
+		dev_kfree_skb(skb);
+		return true;
 	}
 
-	/* according to mpdu sequence number deal with reordering buffer */
-	mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
-	ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
-						mpdu_seq_num, 0);
- end_reorder:
-	return ret;
+	return ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb);
 }
 
 /*
@@ -2457,10 +2469,6 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
 			 status->rate_idx,
 			 status->rate_idx))
 			goto drop;
-		/* HT rates are not in the table - use the highest legacy rate
-		 * for now since other parts of mac80211 may not yet be fully
-		 * MCS aware. */
-		rate = &sband->bitrates[sband->n_bitrates - 1];
 	} else {
 		if (WARN_ON(status->rate_idx < 0 ||
 			    status->rate_idx >= sband->n_bitrates))
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index 68953033403d..aa743a895cf9 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -65,7 +65,7 @@ static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_da
 			IEEE80211_SPCT_MSR_RPRT_MODE_REFUSED;
 	msr_report->u.action.u.measurement.msr_elem.type = request_ie->type;
 
-	ieee80211_tx_skb(sdata, skb, 1);
+	ieee80211_tx_skb(sdata, skb);
 }
 
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 396a94806de9..71f370dd24bc 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -116,14 +116,15 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr)
 	return sta;
 }
 
-struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
-				     struct net_device *dev)
+struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
+				     int idx)
 {
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int i = 0;
 
 	list_for_each_entry_rcu(sta, &local->sta_list, list) {
-		if (dev && dev != sta->sdata->dev)
+		if (sdata != sta->sdata)
 			continue;
 		if (i < idx) {
 			++i;
@@ -147,8 +148,10 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
 static void __sta_info_free(struct ieee80211_local *local,
 			    struct sta_info *sta)
 {
-	rate_control_free_sta(sta);
-	rate_control_put(sta->rate_ctrl);
+	if (sta->rate_ctrl) {
+		rate_control_free_sta(sta);
+		rate_control_put(sta->rate_ctrl);
+	}
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	printk(KERN_DEBUG "%s: Destroyed STA %pM\n",
@@ -276,6 +279,23 @@ static void sta_unblock(struct work_struct *wk)
 		ieee80211_sta_ps_deliver_poll_response(sta);
 }
 
+static int sta_prepare_rate_control(struct ieee80211_local *local,
+				    struct sta_info *sta, gfp_t gfp)
+{
+	if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+		return 0;
+
+	sta->rate_ctrl = rate_control_get(local->rate_ctrl);
+	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
+						     &sta->sta, gfp);
+	if (!sta->rate_ctrl_priv) {
+		rate_control_put(sta->rate_ctrl);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 				u8 *addr, gfp_t gfp)
 {
@@ -295,11 +315,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 	sta->local = local;
 	sta->sdata = sdata;
 
-	sta->rate_ctrl = rate_control_get(local->rate_ctrl);
-	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
-						     &sta->sta, gfp);
-	if (!sta->rate_ctrl_priv) {
-		rate_control_put(sta->rate_ctrl);
+	if (sta_prepare_rate_control(local, sta, gfp)) {
 		kfree(sta);
 		return NULL;
 	}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 4673454176ed..b4810f6aa94f 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -185,6 +185,7 @@ struct sta_ampdu_mlme {
  * @lock: used for locking all fields that require locking, see comments
  *	in the header file.
  * @flaglock: spinlock for flags accesses
+ * @drv_unblock_wk: used for driver PS unblocking
  * @listen_interval: listen interval of this station, when we're acting as AP
  * @pin_status: used internally for pinning a STA struct into memory
  * @flags: STA flags, see &enum ieee80211_sta_info_flags
@@ -225,7 +226,6 @@ struct sta_ampdu_mlme {
  * @debugfs: debug filesystem info
  * @sta: station information we share with the driver
  * @dead: set to true when sta is unlinked
- * @drv_unblock_wk used for driver PS unblocking
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -409,8 +409,8 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, const u8 *addr);
 /*
  * Get STA info by index, BROKEN!
  */
-struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
-				      struct net_device *dev);
+struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
+				     int idx);
 /*
  * Create a new STA info, caller owns returned structure
  * until sta_info_insert().
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
new file mode 100644
index 000000000000..9f91fd8e6efb
--- /dev/null
+++ b/net/mac80211/status.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
+ * Copyright 2008-2009	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "rate.h"
+#include "mesh.h"
+#include "led.h"
+
+
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+				 struct sk_buff *skb)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	int tmp;
+
+	skb->pkt_type = IEEE80211_TX_STATUS_MSG;
+	skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
+		       &local->skb_queue : &local->skb_queue_unreliable, skb);
+	tmp = skb_queue_len(&local->skb_queue) +
+		skb_queue_len(&local->skb_queue_unreliable);
+	while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
+	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+		dev_kfree_skb_irq(skb);
+		tmp--;
+		I802_DEBUG_INC(local->tx_status_drop);
+	}
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
+
+static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
+					    struct sta_info *sta,
+					    struct sk_buff *skb)
+{
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	/*
+	 * XXX: This is temporary!
+	 *
+	 *	The problem here is that when we get here, the driver will
+	 *	quite likely have pretty much overwritten info->control by
+	 *	using info->driver_data or info->rate_driver_data. Thus,
+	 *	when passing out the frame to the driver again, we would be
+	 *	passing completely bogus data since the driver would then
+	 *	expect a properly filled info->control. In mac80211 itself
+	 *	the same problem occurs, since we need info->control.vif
+	 *	internally.
+	 *
+	 *	To fix this, we should send the frame through TX processing
+	 *	again. However, it's not that simple, since the frame will
+	 *	have been software-encrypted (if applicable) already, and
+	 *	encrypting it again doesn't do much good. So to properly do
+	 *	that, we not only have to skip the actual 'raw' encryption
+	 *	(key selection etc. still has to be done!) but also the
+	 *	sequence number assignment since that impacts the crypto
+	 *	encapsulation, of course.
+	 *
+	 *	Hence, for now, fix the bug by just dropping the frame.
+	 */
+	goto drop;
+
+	sta->tx_filtered_count++;
+
+	/*
+	 * Clear the TX filter mask for this STA when sending the next
+	 * packet. If the STA went to power save mode, this will happen
+	 * when it wakes up for the next time.
+	 */
+	set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
+
+	/*
+	 * This code races in the following way:
+	 *
+	 *  (1) STA sends frame indicating it will go to sleep and does so
+	 *  (2) hardware/firmware adds STA to filter list, passes frame up
+	 *  (3) hardware/firmware processes TX fifo and suppresses a frame
+	 *  (4) we get TX status before having processed the frame and
+	 *	knowing that the STA has gone to sleep.
+	 *
+	 * This is actually quite unlikely even when both those events are
+	 * processed from interrupts coming in quickly after one another or
+	 * even at the same time because we queue both TX status events and
+	 * RX frames to be processed by a tasklet and process them in the
+	 * same order that they were received or TX status last. Hence, there
+	 * is no race as long as the frame RX is processed before the next TX
+	 * status, which drivers can ensure, see below.
+	 *
+	 * Note that this can only happen if the hardware or firmware can
+	 * actually add STAs to the filter list, if this is done by the
+	 * driver in response to set_tim() (which will only reduce the race
+	 * this whole filtering tries to solve, not completely solve it)
+	 * this situation cannot happen.
+	 *
+	 * To completely solve this race drivers need to make sure that they
+	 *  (a) don't mix the irq-safe/not irq-safe TX status/RX processing
+	 *	functions and
+	 *  (b) always process RX events before TX status events if ordering
+	 *      can be unknown, for example with different interrupt status
+	 *	bits.
+	 */
+	if (test_sta_flags(sta, WLAN_STA_PS_STA) &&
+	    skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
+		skb_queue_tail(&sta->tx_filtered, skb);
+		return;
+	}
+
+	if (!test_sta_flags(sta, WLAN_STA_PS_STA) &&
+	    !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
+		/* Software retry the packet once */
+		info->flags |= IEEE80211_TX_INTFL_RETRIED;
+		ieee80211_add_pending_skb(local, skb);
+		return;
+	}
+
+ drop:
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	if (net_ratelimit())
+		printk(KERN_DEBUG "%s: dropped TX filtered frame, "
+		       "queue_len=%d PS=%d @%lu\n",
+		       wiphy_name(local->hw.wiphy),
+		       skb_queue_len(&sta->tx_filtered),
+		       !!test_sta_flags(sta, WLAN_STA_PS_STA), jiffies);
+#endif
+	dev_kfree_skb(skb);
+}
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct sk_buff *skb2;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	u16 frag, type;
+	__le16 fc;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_tx_status_rtap_hdr *rthdr;
+	struct ieee80211_sub_if_data *sdata;
+	struct net_device *prev_dev = NULL;
+	struct sta_info *sta;
+	int retry_count = -1, i;
+
+	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+		/* the HW cannot have attempted that rate */
+		if (i >= hw->max_rates) {
+			info->status.rates[i].idx = -1;
+			info->status.rates[i].count = 0;
+		}
+
+		retry_count += info->status.rates[i].count;
+	}
+	if (retry_count < 0)
+		retry_count = 0;
+
+	rcu_read_lock();
+
+	sband = local->hw.wiphy->bands[info->band];
+
+	sta = sta_info_get(local, hdr->addr1);
+
+	if (sta) {
+		if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+		    test_sta_flags(sta, WLAN_STA_PS_STA)) {
+			/*
+			 * The STA is in power save mode, so assume
+			 * that this TX packet failed because of that.
+			 */
+			ieee80211_handle_filtered_frame(local, sta, skb);
+			rcu_read_unlock();
+			return;
+		}
+
+		fc = hdr->frame_control;
+
+		if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
+		    (ieee80211_is_data_qos(fc))) {
+			u16 tid, ssn;
+			u8 *qc;
+
+			qc = ieee80211_get_qos_ctl(hdr);
+			tid = qc[0] & 0xf;
+			ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
+						& IEEE80211_SCTL_SEQ);
+			ieee80211_send_bar(sta->sdata, hdr->addr1,
+					   tid, ssn);
+		}
+
+		if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+			ieee80211_handle_filtered_frame(local, sta, skb);
+			rcu_read_unlock();
+			return;
+		} else {
+			if (!(info->flags & IEEE80211_TX_STAT_ACK))
+				sta->tx_retry_failed++;
+			sta->tx_retry_count += retry_count;
+		}
+
+		rate_control_tx_status(local, sband, sta, skb);
+		if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+			ieee80211s_update_metric(local, sta, skb);
+	}
+
+	rcu_read_unlock();
+
+	ieee80211_led_tx(local, 0);
+
+	/* SNMP counters
+	 * Fragments are passed to low-level drivers as separate skbs, so these
+	 * are actually fragments, not frames. Update frame counters only for
+	 * the first fragment of the frame. */
+
+	frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+	type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
+
+	if (info->flags & IEEE80211_TX_STAT_ACK) {
+		if (frag == 0) {
+			local->dot11TransmittedFrameCount++;
+			if (is_multicast_ether_addr(hdr->addr1))
+				local->dot11MulticastTransmittedFrameCount++;
+			if (retry_count > 0)
+				local->dot11RetryCount++;
+			if (retry_count > 1)
+				local->dot11MultipleRetryCount++;
+		}
+
+		/* This counter shall be incremented for an acknowledged MPDU
+		 * with an individual address in the address 1 field or an MPDU
+		 * with a multicast address in the address 1 field of type Data
+		 * or Management. */
+		if (!is_multicast_ether_addr(hdr->addr1) ||
+		    type == IEEE80211_FTYPE_DATA ||
+		    type == IEEE80211_FTYPE_MGMT)
+			local->dot11TransmittedFragmentCount++;
+	} else {
+		if (frag == 0)
+			local->dot11FailedCount++;
+	}
+
+	/* this was a transmitted frame, but now we want to reuse it */
+	skb_orphan(skb);
+
+	/*
+	 * This is a bit racy but we can avoid a lot of work
+	 * with this test...
+	 */
+	if (!local->monitors && !local->cooked_mntrs) {
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	/* send frame to monitor interfaces now */
+
+	if (skb_headroom(skb) < sizeof(*rthdr)) {
+		printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	rthdr = (struct ieee80211_tx_status_rtap_hdr *)
+				skb_push(skb, sizeof(*rthdr));
+
+	memset(rthdr, 0, sizeof(*rthdr));
+	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+	rthdr->hdr.it_present =
+		cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+			    (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
+			    (1 << IEEE80211_RADIOTAP_RATE));
+
+	if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
+	    !is_multicast_ether_addr(hdr->addr1))
+		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+
+	/*
+	 * XXX: Once radiotap gets the bitmap reset thing the vendor
+	 *	extensions proposal contains, we can actually report
+	 *	the whole set of tries we did.
+	 */
+	if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+	    (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+	else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+		rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+	if (info->status.rates[0].idx >= 0 &&
+	    !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
+		rthdr->rate = sband->bitrates[
+				info->status.rates[0].idx].bitrate / 5;
+
+	/* for now report the total retry_count */
+	rthdr->data_retries = retry_count;
+
+	/* XXX: is this sufficient for BPF? */
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+	memset(skb->cb, 0, sizeof(skb->cb));
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			if (!netif_running(sdata->dev))
+				continue;
+
+			if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
+			    !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
+			    (type == IEEE80211_FTYPE_DATA))
+				continue;
+
+			if (prev_dev) {
+				skb2 = skb_clone(skb, GFP_ATOMIC);
+				if (skb2) {
+					skb2->dev = prev_dev;
+					netif_rx(skb2);
+				}
+			}
+
+			prev_dev = sdata->dev;
+		}
+	}
+	if (prev_dev) {
+		skb->dev = prev_dev;
+		netif_rx(skb);
+		skb = NULL;
+	}
+	rcu_read_unlock();
+	dev_kfree_skb(skb);
+}
+EXPORT_SYMBOL(ieee80211_tx_status);
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 964b7faa7f17..4921d724b6c7 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -301,9 +301,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 #endif
 		if (key->local->ops->update_tkip_key &&
 			key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
-			u8 bcast[ETH_ALEN] =
+			static const u8 bcast[ETH_ALEN] =
 				{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-			u8 *sta_addr = key->sta->sta.addr;
+			const u8 *sta_addr = key->sta->sta.addr;
 
 			if (is_multicast_ether_addr(ra))
 				sta_addr = bcast;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 3ad053f6de12..943def2b07df 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1051,7 +1051,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
 	hdr = (struct ieee80211_hdr *) skb->data;
 
-	if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
+	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
 		tx->sta = rcu_dereference(sdata->u.vlan.sta);
 	if (!tx->sta)
 		tx->sta = sta_info_get(local, hdr->addr1);
@@ -1219,7 +1219,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
 	CALL_TXH(ieee80211_tx_h_ps_buf);
 	CALL_TXH(ieee80211_tx_h_select_key);
 	CALL_TXH(ieee80211_tx_h_michael_mic_add);
-	CALL_TXH(ieee80211_tx_h_rate_ctrl);
+	if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL))
+		CALL_TXH(ieee80211_tx_h_rate_ctrl);
 	CALL_TXH(ieee80211_tx_h_misc);
 	CALL_TXH(ieee80211_tx_h_sequence);
 	CALL_TXH(ieee80211_tx_h_fragment);
@@ -1430,8 +1431,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 	int headroom;
 	bool may_encrypt;
 
-	dev_hold(sdata->dev);
-
 	if (need_dynamic_ps(local)) {
 		if (local->hw.conf.flags & IEEE80211_CONF_PS) {
 			ieee80211_stop_queues_by_reason(&local->hw,
@@ -1444,7 +1443,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 		        msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
 	}
 
-	info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+	rcu_read_lock();
 
 	if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR)) {
 		int hdrlen;
@@ -1468,7 +1467,6 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 			 * support we will need a different mechanism.
 			 */
 
-			rcu_read_lock();
 			list_for_each_entry_rcu(tmp_sdata, &local->interfaces,
 						list) {
 				if (!netif_running(tmp_sdata->dev))
@@ -1477,13 +1475,10 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 					continue;
 				if (compare_ether_addr(tmp_sdata->dev->dev_addr,
 						       hdr->addr2) == 0) {
-					dev_hold(tmp_sdata->dev);
-					dev_put(sdata->dev);
 					sdata = tmp_sdata;
 					break;
 				}
 			}
-			rcu_read_unlock();
 		}
 	}
 
@@ -1497,7 +1492,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
 	if (ieee80211_skb_resize(local, skb, headroom, may_encrypt)) {
 		dev_kfree_skb(skb);
-		dev_put(sdata->dev);
+		rcu_read_unlock();
 		return;
 	}
 
@@ -1508,13 +1503,13 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 		!is_multicast_ether_addr(hdr->addr1))
 			if (mesh_nexthop_lookup(skb, sdata)) {
 				/* skb queued: don't free */
-				dev_put(sdata->dev);
+				rcu_read_unlock();
 				return;
 			}
 
 	ieee80211_select_queue(local, skb);
 	ieee80211_tx(sdata, skb, false);
-	dev_put(sdata->dev);
+	rcu_read_unlock();
 }
 
 netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
@@ -1578,6 +1573,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
 
 	memset(info, 0, sizeof(*info));
 
+	info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+
 	/* pass the radiotap header up to xmit */
 	ieee80211_xmit(IEEE80211_DEV_TO_SUB_IF(dev), skb);
 	return NETDEV_TX_OK;
@@ -1635,8 +1632,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 	switch (sdata->vif.type) {
 	case NL80211_IFTYPE_AP_VLAN:
 		rcu_read_lock();
-		if (sdata->use_4addr)
-			sta = rcu_dereference(sdata->u.vlan.sta);
+		sta = rcu_dereference(sdata->u.vlan.sta);
 		if (sta) {
 			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 			/* RA TA DA SA */
@@ -1687,21 +1683,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 			/* packet from other interface */
 			struct mesh_path *mppath;
 			int is_mesh_mcast = 1;
-			char *mesh_da;
+			const u8 *mesh_da;
 
 			rcu_read_lock();
 			if (is_multicast_ether_addr(skb->data))
 				/* DA TA mSA AE:SA */
 				mesh_da = skb->data;
 			else {
+				static const u8 bcast[ETH_ALEN] =
+					{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
 				mppath = mpp_path_lookup(skb->data, sdata);
 				if (mppath) {
 					/* RA TA mDA mSA AE:DA SA */
 					mesh_da = mppath->mpp;
 					is_mesh_mcast = 0;
-				} else
+				} else {
 					/* DA TA mSA AE:SA */
-					mesh_da = dev->broadcast;
+					mesh_da = bcast;
+				}
 			}
 			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
 					mesh_da, dev->dev_addr);
@@ -1726,7 +1726,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
 #endif
 	case NL80211_IFTYPE_STATION:
 		memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-		if (sdata->use_4addr && ethertype != ETH_P_PAE) {
+		if (sdata->u.mgd.use_4addr && ethertype != ETH_P_PAE) {
 			fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 			/* RA TA DA SA */
 			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
@@ -1964,12 +1964,10 @@ void ieee80211_tx_pending(unsigned long data)
 			}
 
 			sdata = vif_to_sdata(info->control.vif);
-			dev_hold(sdata->dev);
 			spin_unlock_irqrestore(&local->queue_stop_reason_lock,
 						flags);
 
 			txok = ieee80211_tx_pending_skb(local, skb);
-			dev_put(sdata->dev);
 			if (!txok)
 				__skb_queue_head(&local->pending[i], skb);
 			spin_lock_irqsave(&local->queue_stop_reason_lock,
@@ -2282,17 +2280,12 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_get_buffered_bc);
 
-void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-		      int encrypt)
+void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
 {
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	skb_set_mac_header(skb, 0);
 	skb_set_network_header(skb, 0);
 	skb_set_transport_header(skb, 0);
 
-	if (!encrypt)
-		info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-
 	/*
 	 * The other path calling ieee80211_xmit is from the tasklet,
 	 * and while we can handle concurrent transmissions locking
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index da86e1592f8c..2fb0432ac830 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -666,8 +666,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
 			elems->mesh_id_len = elen;
 			break;
 		case WLAN_EID_MESH_CONFIG:
-			elems->mesh_config = pos;
-			elems->mesh_config_len = elen;
+			if (elen >= sizeof(struct ieee80211_meshconf_ie))
+				elems->mesh_config = (void *)pos;
 			break;
 		case WLAN_EID_PEER_LINK:
 			elems->peer_link = pos;
@@ -872,7 +872,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 		WARN_ON(err);
 	}
 
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
@@ -974,7 +975,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
 	skb_put(skb, ieee80211_build_preq_ies(local, pos, ie, ie_len,
 					      local->hw.conf.channel->band));
 
-	ieee80211_tx_skb(sdata, skb, 0);
+	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
+	ieee80211_tx_skb(sdata, skb);
 }
 
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 8a980f136941..247123fe1a7a 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -281,16 +281,18 @@ bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 ieee80211_rx_result
 ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 
 	if (!ieee80211_is_data(hdr->frame_control) &&
 	    !ieee80211_is_auth(hdr->frame_control))
 		return RX_CONTINUE;
 
-	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+	if (!(status->flag & RX_FLAG_DECRYPTED)) {
 		if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key))
 			return RX_DROP_UNUSABLE;
-	} else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) {
+	} else if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
 		ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
 		/* remove ICV */
 		skb_trim(rx->skb, rx->skb->len - WEP_ICV_LEN);
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 70778694877b..5332014cb229 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -85,16 +85,16 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 	u8 *data, *key = NULL, key_offset;
 	size_t data_len;
 	unsigned int hdrlen;
-	struct ieee80211_hdr *hdr;
 	u8 mic[MICHAEL_MIC_LEN];
 	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	int authenticator = 1, wpa_test = 0;
 
 	/* No way to verify the MIC if the hardware stripped it */
-	if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
+	if (status->flag & RX_FLAG_MMIC_STRIPPED)
 		return RX_CONTINUE;
 
-	hdr = (struct ieee80211_hdr *)skb->data;
 	if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
 	    !ieee80211_has_protected(hdr->frame_control) ||
 	    !ieee80211_is_data_present(hdr->frame_control))
@@ -216,6 +216,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
 	int hdrlen, res, hwaccel = 0, wpa_test = 0;
 	struct ieee80211_key *key = rx->key;
 	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 
 	hdrlen = ieee80211_hdrlen(hdr->frame_control);
 
@@ -225,8 +226,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
 	if (!rx->sta || skb->len - hdrlen < 12)
 		return RX_DROP_UNUSABLE;
 
-	if (rx->status->flag & RX_FLAG_DECRYPTED) {
-		if (rx->status->flag & RX_FLAG_IV_STRIPPED) {
+	if (status->flag & RX_FLAG_DECRYPTED) {
+		if (status->flag & RX_FLAG_IV_STRIPPED) {
 			/*
 			 * Hardware took care of all processing, including
 			 * replay protection, and stripped the ICV/IV so
@@ -442,6 +443,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
 	int hdrlen;
 	struct ieee80211_key *key = rx->key;
 	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	u8 pn[CCMP_PN_LEN];
 	int data_len;
 
@@ -455,8 +457,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
 	if (!rx->sta || data_len < 0)
 		return RX_DROP_UNUSABLE;
 
-	if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-	    (rx->status->flag & RX_FLAG_IV_STRIPPED))
+	if ((status->flag & RX_FLAG_DECRYPTED) &&
+	    (status->flag & RX_FLAG_IV_STRIPPED))
 		return RX_CONTINUE;
 
 	ccmp_hdr2pn(pn, skb->data + hdrlen);
@@ -466,7 +468,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
 		return RX_DROP_UNUSABLE;
 	}
 
-	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+	if (!(status->flag & RX_FLAG_DECRYPTED)) {
 		/* hardware didn't decrypt/verify MIC */
 		ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
 
@@ -563,6 +565,7 @@ ieee80211_rx_result
 ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
 {
 	struct sk_buff *skb = rx->skb;
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	struct ieee80211_key *key = rx->key;
 	struct ieee80211_mmie *mmie;
 	u8 aad[20], mic[8], ipn[6];
@@ -571,8 +574,8 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
 	if (!ieee80211_is_mgmt(hdr->frame_control))
 		return RX_CONTINUE;
 
-	if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
-	    (rx->status->flag & RX_FLAG_IV_STRIPPED))
+	if ((status->flag & RX_FLAG_DECRYPTED) &&
+	    (status->flag & RX_FLAG_IV_STRIPPED))
 		return RX_CONTINUE;
 
 	if (skb->len < 24 + sizeof(*mmie))
@@ -591,7 +594,7 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
 		return RX_DROP_UNUSABLE;
 	}
 
-	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
+	if (!(status->flag & RX_FLAG_DECRYPTED)) {
 		/* hardware didn't decrypt/verify MIC */
 		bip_aad(skb, aad);
 		ieee80211_aes_cmac(key->u.aes_cmac.tfm,