aboutsummaryrefslogtreecommitdiffstats
path: root/package/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211')
-rw-r--r--package/mac80211/Makefile9
-rw-r--r--package/mac80211/patches/002-disable_rfkill.patch21
-rw-r--r--package/mac80211/patches/009-remove_mac80211_module_dependence.patch2
-rw-r--r--package/mac80211/patches/010-b43_config.patch4
-rw-r--r--package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch4
-rw-r--r--package/mac80211/patches/405-b43_locking_fix.patch23
-rw-r--r--package/mac80211/patches/500-4addr_bcast_fix.patch11
-rw-r--r--package/mac80211/patches/500-nl80211_4addr.patch69
-rw-r--r--package/mac80211/patches/510-mac80211_4addr_vlan.patch269
-rw-r--r--package/mac80211/patches/510-nl80211_vlan_add_fix.patch (renamed from package/mac80211/patches/520-nl80211_vlan_add_fix.patch)0
-rw-r--r--package/mac80211/patches/520-driver_flags.patch27
-rw-r--r--package/mac80211/patches/530-ath9k_cleanup.patch460
-rw-r--r--package/mac80211/patches/540-monitor_tx_status.patch14
13 files changed, 528 insertions, 385 deletions
diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile
index 13d1670a3e..e4e9b7b546 100644
--- a/package/mac80211/Makefile
+++ b/package/mac80211/Makefile
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
-PKG_VERSION:=2009-11-03
-PKG_RELEASE:=2
+PKG_VERSION:=2009-11-13
+PKG_RELEASE:=1
PKG_SOURCE_URL:= \
http://www.orbit-lab.org/kernel/compat-wireless-2.6/2009/11 \
http://wireless.kernel.org/download/compat-wireless-2.6
-PKG_MD5SUM:=f8434790c9552abb9c98926d7ae616fe
+PKG_MD5SUM:=920c3bcfd1b4cd6079a8f9db4afe4e4f
PKG_SOURCE:=compat-wireless-$(PKG_VERSION).tar.bz2
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/compat-wireless-$(PKG_VERSION)
@@ -323,9 +323,10 @@ define KernelPackage/ath9k
URL:=http://linuxwireless.org/en/users/Drivers/ath9k
DEPENDS+= +kmod-ath
FILES:= \
+ $(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_common.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_hw.$(LINUX_KMOD_SUFFIX) \
$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k.$(LINUX_KMOD_SUFFIX)
- AUTOLOAD:=$(call AutoLoad,27,ath9k_hw ath9k)
+ AUTOLOAD:=$(call AutoLoad,27,ath9k_hw ath9k_common ath9k)
endef
define KernelPackage/ath9k/description
diff --git a/package/mac80211/patches/002-disable_rfkill.patch b/package/mac80211/patches/002-disable_rfkill.patch
index 0140ea264f..3aab629702 100644
--- a/package/mac80211/patches/002-disable_rfkill.patch
+++ b/package/mac80211/patches/002-disable_rfkill.patch
@@ -1,6 +1,6 @@
--- a/config.mk
+++ b/config.mk
-@@ -145,7 +145,7 @@ ifneq ($(CONFIG_PCI),)
+@@ -147,7 +147,7 @@ ifneq ($(CONFIG_PCI),)
CONFIG_ATH5K=m
# CONFIG_ATH5K_DEBUG=y
@@ -8,8 +8,8 @@
+# CONFIG_ATH5K_RFKILL=y
CONFIG_ATH9K_HW=m
CONFIG_ATH9K=m
- # CONFIG_ATH9K_DEBUG=y
-@@ -153,7 +153,7 @@ CONFIG_ATH9K=m
+ # Note: once ath9k_htc is added we'll have to move
+@@ -159,7 +159,7 @@ CONFIG_ATH9K_COMMON=m
CONFIG_IWLWIFI=m
CONFIG_IWLWIFI_LEDS=y
@@ -18,7 +18,7 @@
CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT=y
# CONFIG_IWLWIFI_DEBUG=y
# CONFIG_IWLWIFI_DEBUGFS=y
-@@ -173,7 +173,7 @@ CONFIG_B43_PCMCIA=y
+@@ -179,7 +179,7 @@ CONFIG_B43_PCMCIA=y
endif
CONFIG_B43_PIO=y
CONFIG_B43_LEDS=y
@@ -27,7 +27,7 @@
CONFIG_B43_PHY_LP=y
# CONFIG_B43_DEBUG=y
# CONFIG_B43_FORCE_PIO=y
-@@ -183,7 +183,7 @@ CONFIG_B43LEGACY_HWRNG=y
+@@ -189,7 +189,7 @@ CONFIG_B43LEGACY_HWRNG=y
CONFIG_B43LEGACY_PCI_AUTOSELECT=y
CONFIG_B43LEGACY_PCICORE_AUTOSELECT=y
CONFIG_B43LEGACY_LEDS=y
@@ -36,16 +36,7 @@
# CONFIG_B43LEGACY_DEBUG=y
CONFIG_B43LEGACY_DMA=y
CONFIG_B43LEGACY_PIO=y
-@@ -373,7 +373,7 @@ CONFIG_RT2X00_LIB=m
- CONFIG_RT2X00_LIB_HT=y
- CONFIG_RT2X00_LIB_FIRMWARE=y
- CONFIG_RT2X00_LIB_CRYPTO=y
--CONFIG_RT2X00_LIB_RFKILL=y
-+# CONFIG_RT2X00_LIB_RFKILL=y
- CONFIG_RT2X00_LIB_LEDS=y
- # CONFIG_RT2X00_LIB_DEBUGFS=y
- # CONFIG_RT2X00_DEBUG=y
-@@ -415,8 +415,8 @@ endif
+@@ -422,8 +422,8 @@ endif
# We need the backported rfkill module on kernel < 2.6.31.
# In more recent kernel versions use the in kernel rfkill module.
ifdef CONFIG_COMPAT_WIRELESS_31
diff --git a/package/mac80211/patches/009-remove_mac80211_module_dependence.patch b/package/mac80211/patches/009-remove_mac80211_module_dependence.patch
index d1c91594ae..14d42904a0 100644
--- a/package/mac80211/patches/009-remove_mac80211_module_dependence.patch
+++ b/package/mac80211/patches/009-remove_mac80211_module_dependence.patch
@@ -1,6 +1,6 @@
--- a/config.mk
+++ b/config.mk
-@@ -47,21 +47,6 @@ $(error "ERROR: Your 2.6.27 kernel has C
+@@ -49,21 +49,6 @@ $(error "ERROR: Your 2.6.27 kernel has C
endif
endif
diff --git a/package/mac80211/patches/010-b43_config.patch b/package/mac80211/patches/010-b43_config.patch
index ba97e7602e..9074ee7874 100644
--- a/package/mac80211/patches/010-b43_config.patch
+++ b/package/mac80211/patches/010-b43_config.patch
@@ -1,6 +1,6 @@
--- a/config.mk
+++ b/config.mk
-@@ -154,12 +154,12 @@ CONFIG_B43_HWRNG=y
+@@ -160,12 +160,12 @@ CONFIG_B43_HWRNG=y
CONFIG_B43_PCI_AUTOSELECT=y
CONFIG_B43_PCICORE_AUTOSELECT=y
ifneq ($(CONFIG_PCMCIA),)
@@ -16,7 +16,7 @@
# CONFIG_B43_DEBUG=y
# CONFIG_B43_FORCE_PIO=y
-@@ -208,8 +208,8 @@ CONFIG_SSB_PCIHOST_POSSIBLE=y
+@@ -219,8 +219,8 @@ CONFIG_SSB_PCIHOST_POSSIBLE=y
CONFIG_SSB_PCIHOST=y
CONFIG_SSB_B43_PCI_BRIDGE=y
ifneq ($(CONFIG_PCMCIA),)
diff --git a/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch b/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch
index b458dde6de..2a9bdc8b23 100644
--- a/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch
+++ b/package/mac80211/patches/401-ath9k-dont-register-leds-on-ar9100.patch
@@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1135,6 +1135,9 @@ static void ath_unregister_led(struct at
+@@ -1139,6 +1139,9 @@ static void ath_unregister_led(struct at
static void ath_deinit_leds(struct ath_softc *sc)
{
@@ -10,7 +10,7 @@
ath_unregister_led(&sc->assoc_led);
sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
ath_unregister_led(&sc->tx_led);
-@@ -1153,6 +1156,9 @@ static void ath_init_leds(struct ath_sof
+@@ -1157,6 +1160,9 @@ static void ath_init_leds(struct ath_sof
else
sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
diff --git a/package/mac80211/patches/405-b43_locking_fix.patch b/package/mac80211/patches/405-b43_locking_fix.patch
deleted file mode 100644
index c90890a7a7..0000000000
--- a/package/mac80211/patches/405-b43_locking_fix.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-Subject: [PATCH] b43: work around a locking issue in ->set_tim()
-
-ops->set_tim() must be atomic, so b43 trying to acquire a mutex leads
-to a kernel crash. This patch trades an easy to trigger crash in AP
-mode for an unlikely race condition. According to Michael, the real
-fix would be to allow set_tim() callbacks to sleep, since b43 is
-not the only driver that needs to sleep in all callbacks.
-
-Signed-off-by: Felix Fietkau <nbd@openwrt.org>
-
---- a/drivers/net/wireless/b43/main.c
-+++ b/drivers/net/wireless/b43/main.c
-@@ -4534,9 +4534,8 @@ static int b43_op_beacon_set_tim(struct
- {
- struct b43_wl *wl = hw_to_b43_wl(hw);
-
-- mutex_lock(&wl->mutex);
-+ /* FIXME: add locking */
- b43_update_templates(wl);
-- mutex_unlock(&wl->mutex);
-
- return 0;
- }
diff --git a/package/mac80211/patches/500-4addr_bcast_fix.patch b/package/mac80211/patches/500-4addr_bcast_fix.patch
new file mode 100644
index 0000000000..3143aaf8f9
--- /dev/null
+++ b/package/mac80211/patches/500-4addr_bcast_fix.patch
@@ -0,0 +1,11 @@
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1236,7 +1236,7 @@ ieee80211_deliver_skb(struct ieee80211_r
+ 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->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) {
+ if (is_multicast_ether_addr(ehdr->h_dest)) {
+ /*
+ * send multicast frames both to higher layers in
diff --git a/package/mac80211/patches/500-nl80211_4addr.patch b/package/mac80211/patches/500-nl80211_4addr.patch
deleted file mode 100644
index de3b78fdbb..0000000000
--- a/package/mac80211/patches/500-nl80211_4addr.patch
+++ /dev/null
@@ -1,69 +0,0 @@
---- a/include/linux/nl80211.h
-+++ b/include/linux/nl80211.h
-@@ -584,6 +584,8 @@ enum nl80211_commands {
- * changed then the list changed and the dump should be repeated
- * completely from scratch.
- *
-+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
-+ *
- * @NL80211_ATTR_MAX: highest attribute number currently defined
- * @__NL80211_ATTR_AFTER_LAST: internal use
- */
-@@ -714,6 +716,8 @@ enum nl80211_attrs {
-
- NL80211_ATTR_PID,
-
-+ NL80211_ATTR_4ADDR,
-+
- /* add attributes here, update the policy in nl80211.c */
-
- __NL80211_ATTR_AFTER_LAST,
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -207,10 +207,12 @@ struct ieee80211_supported_band {
- * struct vif_params - describes virtual interface parameters
- * @mesh_id: mesh ID to use
- * @mesh_id_len: length of the mesh ID
-+ * @use_4addr: use 4-address frames
- */
- struct vif_params {
- u8 *mesh_id;
- int mesh_id_len;
-+ int use_4addr;
- };
-
- /**
---- a/net/wireless/nl80211.c
-+++ b/net/wireless/nl80211.c
-@@ -140,6 +140,7 @@ static struct nla_policy nl80211_policy[
- [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
- [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
- [NL80211_ATTR_PID] = { .type = NLA_U32 },
-+ [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
- };
-
- /* policy for the attributes */
-@@ -989,6 +990,13 @@ static int nl80211_set_interface(struct
- change = true;
- }
-
-+ if (info->attrs[NL80211_ATTR_4ADDR]) {
-+ params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
-+ change = true;
-+ } else {
-+ params.use_4addr = -1;
-+ }
-+
- if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
- if (ntype != NL80211_IFTYPE_MONITOR) {
- err = -EINVAL;
-@@ -1055,6 +1063,9 @@ static int nl80211_new_interface(struct
- params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
- }
-
-+ if (info->attrs[NL80211_ATTR_4ADDR])
-+ params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
-+
- err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
- info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
- &flags);
diff --git a/package/mac80211/patches/510-mac80211_4addr_vlan.patch b/package/mac80211/patches/510-mac80211_4addr_vlan.patch
deleted file mode 100644
index d3d1e82930..0000000000
--- a/package/mac80211/patches/510-mac80211_4addr_vlan.patch
+++ /dev/null
@@ -1,269 +0,0 @@
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -208,6 +208,9 @@ struct ieee80211_if_wds {
-
- struct ieee80211_if_vlan {
- struct list_head list;
-+
-+ /* used for all tx if the VLAN is configured to 4-addr mode */
-+ struct sta_info *sta;
- };
-
- struct mesh_stats {
-@@ -457,6 +460,8 @@ 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;
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80
- }
- }
-
-+static bool nl80211_params_check(enum nl80211_iftype type,
-+ struct vif_params *params)
-+{
-+ 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;
-+}
-+
- static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
- enum nl80211_iftype type, u32 *flags,
- struct vif_params *params)
-@@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wi
- struct ieee80211_sub_if_data *sdata;
- int err;
-
-- if (!nl80211_type_check(type))
-+ if (!nl80211_params_check(type, params))
- return -EINVAL;
-
- err = ieee80211_if_add(local, name, &dev, type, params);
-@@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct
- if (netif_running(dev))
- return -EBUSY;
-
-- if (!nl80211_type_check(type))
-+ if (!nl80211_params_check(type, params))
- return -EINVAL;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-@@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct
- 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;
-
-@@ -806,6 +827,13 @@ static int ieee80211_change_station(stru
- return -EINVAL;
- }
-
-+ if (vlansdata->use_4addr) {
-+ if (vlansdata->u.vlan.sta)
-+ return -EBUSY;
-+
-+ rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
-+ }
-+
- sta->sdata = vlansdata;
- ieee80211_send_layer2_update(sta);
- }
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -489,6 +489,9 @@ static void __sta_info_unlink(struct sta
- local->num_sta--;
- local->sta_generation++;
-
-+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-+ rcu_assign_pointer(sdata->u.vlan.sta, NULL);
-+
- if (local->ops->sta_notify) {
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1046,7 +1046,10 @@ ieee80211_tx_prepare(struct ieee80211_su
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
-- tx->sta = sta_info_get(local, hdr->addr1);
-+ if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr)
-+ tx->sta = rcu_dereference(sdata->u.vlan.sta);
-+ if (!tx->sta)
-+ tx->sta = sta_info_get(local, hdr->addr1);
-
- if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
- (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
-@@ -1608,7 +1611,7 @@ netdev_tx_t ieee80211_subif_start_xmit(s
- const u8 *encaps_data;
- int encaps_len, skip_header_bytes;
- int nh_pos, h_pos;
-- struct sta_info *sta;
-+ struct sta_info *sta = NULL;
- u32 sta_flags = 0;
-
- if (unlikely(skb->len < ETH_HLEN)) {
-@@ -1625,8 +1628,25 @@ netdev_tx_t ieee80211_subif_start_xmit(s
- fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
-
- switch (sdata->vif.type) {
-- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_AP_VLAN:
-+ rcu_read_lock();
-+ if (sdata->use_4addr)
-+ sta = rcu_dereference(sdata->u.vlan.sta);
-+ if (sta) {
-+ fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
-+ /* RA TA DA SA */
-+ memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
-+ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
-+ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
-+ hdrlen = 30;
-+ sta_flags = get_sta_flags(sta);
-+ }
-+ rcu_read_unlock();
-+ if (sta)
-+ break;
-+ /* fall through */
-+ case NL80211_IFTYPE_AP:
- fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
- /* DA BSSID SA */
- memcpy(hdr.addr1, skb->data, ETH_ALEN);
-@@ -1700,12 +1720,21 @@ netdev_tx_t ieee80211_subif_start_xmit(s
- break;
- #endif
- case NL80211_IFTYPE_STATION:
-- fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
-- /* BSSID SA DA */
- memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
-- memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-- memcpy(hdr.addr3, skb->data, ETH_ALEN);
-- hdrlen = 24;
-+ if (sdata->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);
-+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
-+ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
-+ hdrlen = 30;
-+ } else {
-+ fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
-+ /* BSSID SA DA */
-+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
-+ hdrlen = 24;
-+ }
- break;
- case NL80211_IFTYPE_ADHOC:
- /* DA SA BSSID */
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -772,6 +772,7 @@ int ieee80211_if_change_type(struct ieee
- ieee80211_mandatory_rates(sdata->local,
- sdata->local->hw.conf.channel->band);
- sdata->drop_unencrypted = 0;
-+ sdata->use_4addr = 0;
-
- return 0;
- }
-@@ -853,6 +854,9 @@ int ieee80211_if_add(struct ieee80211_lo
- 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);
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -1237,6 +1237,13 @@ __ieee80211_data_to_8023(struct ieee8021
- {
- struct net_device *dev = rx->dev;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(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))
-+ return -1;
-+ if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1))
-+ return -1;
-
- return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type);
- }
-@@ -1285,7 +1292,7 @@ ieee80211_deliver_skb(struct ieee80211_r
- 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->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) {
- if (is_multicast_ether_addr(ehdr->h_dest)) {
- /*
- * send multicast frames both to higher layers in
-@@ -1590,6 +1597,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
- {
- struct net_device *dev = rx->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;
-
-@@ -1599,6 +1607,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_
- if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
- return RX_DROP_MONITOR;
-
-+ /*
-+ * Allow the cooked monitor interface of an AP to see 4-addr frames so
-+ * that a 4-addr station can be detected and moved into a separate VLAN
-+ */
-+ if (ieee80211_has_a4(hdr->frame_control) &&
-+ sdata->vif.type == NL80211_IFTYPE_AP)
-+ return RX_DROP_MONITOR;
-+
- err = __ieee80211_data_to_8023(rx);
- if (unlikely(err))
- return RX_DROP_UNUSABLE;
-@@ -2039,7 +2055,7 @@ static int prepare_for_handlers(struct i
-
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_STATION:
-- if (!bssid)
-+ if (!bssid && !sdata->use_4addr)
- return 0;
- if (!multicast &&
- compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) {
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buf
- break;
- case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
- if (unlikely(iftype != NL80211_IFTYPE_WDS &&
-- iftype != NL80211_IFTYPE_MESH_POINT))
-+ iftype != NL80211_IFTYPE_MESH_POINT &&
-+ iftype != NL80211_IFTYPE_AP_VLAN &&
-+ iftype != NL80211_IFTYPE_STATION))
- return -1;
- if (iftype == NL80211_IFTYPE_MESH_POINT) {
- struct ieee80211s_hdr *meshdr =
diff --git a/package/mac80211/patches/520-nl80211_vlan_add_fix.patch b/package/mac80211/patches/510-nl80211_vlan_add_fix.patch
index e0cdaead15..e0cdaead15 100644
--- a/package/mac80211/patches/520-nl80211_vlan_add_fix.patch
+++ b/package/mac80211/patches/510-nl80211_vlan_add_fix.patch
diff --git a/package/mac80211/patches/520-driver_flags.patch b/package/mac80211/patches/520-driver_flags.patch
new file mode 100644
index 0000000000..2dc2092b1a
--- /dev/null
+++ b/package/mac80211/patches/520-driver_flags.patch
@@ -0,0 +1,27 @@
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -386,11 +386,12 @@ struct ieee80211_tx_rate {
+ * @flags: transmit info flags, defined above
+ * @band: the band to transmit on (use for checking for races)
+ * @antenna_sel_tx: antenna to use, 0 for automatic diversity
++ * @driver_flags: flags for internal driver use
+ * @pad: padding, ignore
+ * @control: union for control data
+ * @status: union for status data
+ * @driver_data: array of driver_data pointers
+- * @ampdu_ack_len: number of aggregated frames.
++ * @ampdu_ack_len: number of acked aggregated frames.
+ * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ * @ampdu_ack_map: block ack bit map for the aggregation.
+ * relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+@@ -403,8 +404,8 @@ struct ieee80211_tx_info {
+
+ u8 antenna_sel_tx;
+
+- /* 2 byte hole */
+- u8 pad[2];
++ u8 driver_flags;
++ u8 ampdu_len;
+
+ union {
+ struct {
diff --git a/package/mac80211/patches/530-ath9k_cleanup.patch b/package/mac80211/patches/530-ath9k_cleanup.patch
new file mode 100644
index 0000000000..49a1143ab0
--- /dev/null
+++ b/package/mac80211/patches/530-ath9k_cleanup.patch
@@ -0,0 +1,460 @@
+--- a/drivers/net/wireless/ath/ath9k/common.h
++++ b/drivers/net/wireless/ath/ath9k/common.h
+@@ -81,6 +81,7 @@ struct ath_buf {
+ u16 bf_flags;
+ struct ath_buf_state bf_state;
+ dma_addr_t bf_dmacontext;
++ struct ath_wiphy *aphy;
+ };
+
+ struct ath_atx_tid {
+--- a/drivers/net/wireless/ath/ath9k/rc.h
++++ b/drivers/net/wireless/ath/ath9k/rc.h
+@@ -167,24 +167,18 @@ struct ath_rate_priv {
+ struct ath_rate_softc *asc;
+ };
+
++#define ATH_TX_INFO_FRAME_TYPE_INTERNAL (1 << 0)
++#define ATH_TX_INFO_FRAME_TYPE_PAUSE (1 << 1)
++#define ATH_TX_INFO_UPDATE_RC (1 << 2)
++#define ATH_TX_INFO_XRETRY (1 << 3)
++#define ATH_TX_INFO_UNDERRUN (1 << 4)
++
+ enum ath9k_internal_frame_type {
+ ATH9K_NOT_INTERNAL,
+ ATH9K_INT_PAUSE,
+ ATH9K_INT_UNPAUSE
+ };
+
+-struct ath_tx_info_priv {
+- struct ath_wiphy *aphy;
+- struct ath_tx_status tx;
+- int n_frames;
+- int n_bad_frames;
+- bool update_rc;
+- enum ath9k_internal_frame_type frame_type;
+-};
+-
+-#define ATH_TX_INFO_PRIV(tx_info) \
+- ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0]))
+-
+ void ath_rate_attach(struct ath_softc *sc);
+ u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate);
+ int ath_rate_control_register(void);
+--- a/drivers/net/wireless/ath/ath9k/virtual.c
++++ b/drivers/net/wireless/ath/ath9k/virtual.c
+@@ -338,13 +338,11 @@ void ath9k_wiphy_chan_work(struct work_s
+ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+ {
+ struct ath_wiphy *aphy = hw->priv;
+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+- struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+
+- if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE &&
++ if ((tx_info->driver_flags & ATH_TX_INFO_FRAME_TYPE_PAUSE) &&
+ aphy->state == ATH_WIPHY_PAUSING) {
+- if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
++ if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) {
+ printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
+ "frame\n", wiphy_name(hw->wiphy));
+ /*
+@@ -363,9 +361,6 @@ void ath9k_tx_status(struct ieee80211_hw
+ }
+ }
+
+- kfree(tx_info_priv);
+- tx_info->rate_driver_data[0] = NULL;
+-
+ dev_kfree_skb(skb);
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -251,6 +251,7 @@ static struct ath_buf* ath_clone_txbuf(s
+
+ ATH_TXBUF_RESET(tbf);
+
++ tbf->aphy = bf->aphy;
+ tbf->bf_mpdu = bf->bf_mpdu;
+ tbf->bf_buf_addr = bf->bf_buf_addr;
+ *(tbf->bf_desc) = *(bf->bf_desc);
+@@ -270,7 +271,6 @@ static void ath_tx_complete_aggr(struct
+ struct ieee80211_hw *hw;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *tx_info;
+- struct ath_tx_info_priv *tx_info_priv;
+ struct ath_atx_tid *tid = NULL;
+ struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
+ struct ath_desc *ds = bf_last->bf_desc;
+@@ -284,8 +284,7 @@ static void ath_tx_complete_aggr(struct
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ tx_info = IEEE80211_SKB_CB(skb);
+- tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
+- hw = tx_info_priv->aphy->hw;
++ hw = bf->aphy->hw;
+
+ rcu_read_lock();
+
+@@ -464,7 +463,6 @@ static u32 ath_lookup_rate(struct ath_so
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rates;
+- struct ath_tx_info_priv *tx_info_priv;
+ u32 max_4ms_framelen, frmlen;
+ u16 aggr_limit, legacy = 0;
+ int i;
+@@ -472,7 +470,6 @@ static u32 ath_lookup_rate(struct ath_so
+ skb = bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ rates = tx_info->control.rates;
+- tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
+
+ /*
+ * Find the lowest frame length among the rate series that will have a
+@@ -1560,21 +1557,26 @@ static int ath_tx_setup_buffer(struct ie
+ struct ath_softc *sc = aphy->sc;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+- struct ath_tx_info_priv *tx_info_priv;
+ int hdrlen;
+ __le16 fc;
+
+- tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
+- if (unlikely(!tx_info_priv))
+- return -ENOMEM;
+- tx_info->rate_driver_data[0] = tx_info_priv;
+- tx_info_priv->aphy = aphy;
+- tx_info_priv->frame_type = txctl->frame_type;
++ tx_info->driver_flags = 0;
++ switch (txctl->frame_type) {
++ case ATH9K_NOT_INTERNAL:
++ break;
++ case ATH9K_INT_PAUSE:
++ tx_info->driver_flags |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
++ /* fall through */
++ case ATH9K_INT_UNPAUSE:
++ tx_info->driver_flags |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
++ break;
++ }
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
+
+ ATH_TXBUF_RESET(bf);
+
++ bf->aphy = aphy;
+ bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
+
+ if (conf_is_ht(&hw->conf) && !is_pae(skb))
+@@ -1599,8 +1601,6 @@ static int ath_tx_setup_buffer(struct ie
+ skb->len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
+ bf->bf_mpdu = NULL;
+- kfree(tx_info_priv);
+- tx_info->rate_driver_data[0] = NULL;
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "dma_mapping_error() on TX\n");
+ return -ENOMEM;
+@@ -1781,27 +1781,17 @@ exit:
+ /*****************/
+
+ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+- int tx_flags)
++ struct ath_wiphy *aphy, int tx_flags)
+ {
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+- struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ int hdrlen, padsize;
+- int frame_type = ATH9K_NOT_INTERNAL;
+
+ ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+
+- if (tx_info_priv) {
+- hw = tx_info_priv->aphy->hw;
+- frame_type = tx_info_priv->frame_type;
+- }
+-
+- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+- tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+- kfree(tx_info_priv);
+- tx_info->rate_driver_data[0] = NULL;
+- }
++ if (aphy)
++ hw = aphy->hw;
+
+ if (tx_flags & ATH_TX_BAR)
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+@@ -1833,10 +1823,10 @@ static void ath_tx_complete(struct ath_s
+ SC_OP_WAIT_FOR_TX_ACK));
+ }
+
+- if (frame_type == ATH9K_NOT_INTERNAL)
+- ieee80211_tx_status(hw, skb);
+- else
++ if (unlikely(tx_info->driver_flags & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
+ ath9k_tx_status(hw, skb);
++ else
++ ieee80211_tx_status(hw, skb);
+ }
+
+ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
+@@ -1859,7 +1849,7 @@ static void ath_tx_complete_buf(struct a
+ }
+
+ dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
+- ath_tx_complete(sc, skb, tx_flags);
++ ath_tx_complete(sc, skb, bf->aphy, tx_flags);
+ ath_debug_stat_tx(sc, txq, bf);
+
+ /*
+@@ -1907,8 +1897,7 @@ static void ath_tx_rc_status(struct ath_
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+- struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+- struct ieee80211_hw *hw = tx_info_priv->aphy->hw;
++ struct ieee80211_hw *hw = bf->aphy->hw;
+ u8 i, tx_rateindex;
+
+ if (txok)
+@@ -1917,17 +1906,22 @@ static void ath_tx_rc_status(struct ath_
+ tx_rateindex = ds->ds_txstat.ts_rateindex;
+ WARN_ON(tx_rateindex >= hw->max_rates);
+
+- tx_info_priv->update_rc = update_rc;
++ if (update_rc)
++ tx_info->driver_flags |= ATH_TX_INFO_UPDATE_RC;
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+
+ if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+ (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
+ if (ieee80211_is_data(hdr->frame_control)) {
+- memcpy(&tx_info_priv->tx, &ds->ds_txstat,
+- sizeof(tx_info_priv->tx));
+- tx_info_priv->n_frames = bf->bf_nframes;
+- tx_info_priv->n_bad_frames = nbad;
++ if (ds->ds_txstat.ts_flags &
++ (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
++ tx_info->driver_flags |= ATH_TX_INFO_UNDERRUN;
++ if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
++ (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
++ tx_info->driver_flags |= ATH_TX_INFO_XRETRY;
++ tx_info->ampdu_len = bf->bf_nframes;
++ tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
+ }
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -257,14 +257,17 @@ static const struct file_operations fops
+
+ void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
+ {
+- struct ath_tx_info_priv *tx_info_priv = NULL;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *rates = tx_info->status.rates;
+- int final_ts_idx, idx;
++ int final_ts_idx = 0, idx, i;
+ struct ath_rc_stats *stats;
+
+- tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+- final_ts_idx = tx_info_priv->tx.ts_rateindex;
++ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++ if (!rates[i].count)
++ break;
++
++ final_ts_idx = i;
++ }
+ idx = rates[final_ts_idx].idx;
+ stats = &sc->debug.stats.rcstats[idx];
+ stats->success++;
+--- a/drivers/net/wireless/ath/ath9k/rc.c
++++ b/drivers/net/wireless/ath/ath9k/rc.c
+@@ -859,12 +859,12 @@ static void ath_get_rate(void *priv, str
+ static bool ath_rc_update_per(struct ath_softc *sc,
+ const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+- struct ath_tx_info_priv *tx_info_priv,
++ struct ieee80211_tx_info *tx_info,
+ int tx_rate, int xretries, int retries,
+ u32 now_msec)
+ {
+ bool state_change = false;
+- int count;
++ int count, n_bad_frames;
+ u8 last_per;
+ static u32 nretry_to_per_lookup[10] = {
+ 100 * 0 / 1,
+@@ -880,6 +880,7 @@ static bool ath_rc_update_per(struct ath
+ };
+
+ last_per = ath_rc_priv->per[tx_rate];
++ n_bad_frames = tx_info->ampdu_len - tx_info->status.ampdu_ack_len;
+
+ if (xretries) {
+ if (xretries == 1) {
+@@ -907,7 +908,7 @@ static bool ath_rc_update_per(struct ath
+ if (retries >= count)
+ retries = count - 1;
+
+- if (tx_info_priv->n_bad_frames) {
++ if (n_bad_frames) {
+ /* new_PER = 7/8*old_PER + 1/8*(currentPER)
+ * Assuming that n_frames is not 0. The current PER
+ * from the retries is 100 * retries / (retries+1),
+@@ -920,14 +921,14 @@ static bool ath_rc_update_per(struct ath
+ * the above PER. The expression below is a
+ * simplified version of the sum of these two terms.
+ */
+- if (tx_info_priv->n_frames > 0) {
+- int n_frames, n_bad_frames;
++ if (tx_info->ampdu_len > 0) {
++ int n_frames, n_bad_tries;
+ u8 cur_per, new_per;
+
+- n_bad_frames = retries * tx_info_priv->n_frames +
+- tx_info_priv->n_bad_frames;
+- n_frames = tx_info_priv->n_frames * (retries + 1);
+- cur_per = (100 * n_bad_frames / n_frames) >> 3;
++ n_bad_tries = retries * tx_info->ampdu_len +
++ n_bad_frames;
++ n_frames = tx_info->ampdu_len * (retries + 1);
++ cur_per = (100 * n_bad_tries / n_frames) >> 3;
+ new_per = (u8)(last_per - (last_per >> 3) + cur_per);
+ ath_rc_priv->per[tx_rate] = new_per;
+ }
+@@ -943,8 +944,7 @@ static bool ath_rc_update_per(struct ath
+ * this was a probe. Otherwise, ignore the probe.
+ */
+ if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) {
+- if (retries > 0 || 2 * tx_info_priv->n_bad_frames >
+- tx_info_priv->n_frames) {
++ if (retries > 0 || 2 * n_bad_frames > tx_info->ampdu_len) {
+ /*
+ * Since we probed with just a single attempt,
+ * any retries means the probe failed. Also,
+@@ -1003,7 +1003,7 @@ static bool ath_rc_update_per(struct ath
+
+ static void ath_rc_update_ht(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+- struct ath_tx_info_priv *tx_info_priv,
++ struct ieee80211_tx_info *tx_info,
+ int tx_rate, int xretries, int retries)
+ {
+ u32 now_msec = jiffies_to_msecs(jiffies);
+@@ -1020,7 +1020,7 @@ static void ath_rc_update_ht(struct ath_
+
+ /* Update PER first */
+ state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
+- tx_info_priv, tx_rate, xretries,
++ tx_info, tx_rate, xretries,
+ retries, now_msec);
+
+ /*
+@@ -1098,7 +1098,6 @@ static void ath_rc_tx_status(struct ath_
+ struct ieee80211_tx_info *tx_info,
+ int final_ts_idx, int xretries, int long_retry)
+ {
+- struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ const struct ath_rate_table *rate_table;
+ struct ieee80211_tx_rate *rates = tx_info->status.rates;
+ u8 flags;
+@@ -1124,9 +1123,8 @@ static void ath_rc_tx_status(struct ath_
+ return;
+
+ rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+- ath_rc_update_ht(sc, ath_rc_priv,
+- tx_info_priv, rix,
+- xretries ? 1 : 2,
++ ath_rc_update_ht(sc, ath_rc_priv, tx_info,
++ rix, xretries ? 1 : 2,
+ rates[i].count);
+ }
+ }
+@@ -1149,8 +1147,7 @@ static void ath_rc_tx_status(struct ath_
+ return;
+
+ rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+- ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix,
+- xretries, long_retry);
++ ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
+ }
+
+ static const
+@@ -1301,23 +1298,30 @@ static void ath_tx_status(void *priv, st
+ {
+ struct ath_softc *sc = priv;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
+- struct ath_tx_info_priv *tx_info_priv = NULL;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr;
+- int final_ts_idx, tx_status = 0, is_underrun = 0;
++ int final_ts_idx = 0, tx_status = 0, is_underrun = 0;
++ int long_retry = 0;
+ __le16 fc;
++ int i;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+- tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+- final_ts_idx = tx_info_priv->tx.ts_rateindex;
++ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
++ struct ieee80211_tx_rate *rate = &tx_info->status.rates[i];
++ if (!rate->count)
++ break;
++
++ final_ts_idx = i;
++ long_retry = rate->count - 1;
++ }
+
+ if (!priv_sta || !ieee80211_is_data(fc) ||
+- !tx_info_priv->update_rc)
+- goto exit;
++ !(tx_info->driver_flags & ATH_TX_INFO_UPDATE_RC))
++ return;
+
+- if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT)
+- goto exit;
++ if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
++ return;
+
+ /*
+ * If underrun error is seen assume it as an excessive retry only
+@@ -1325,20 +1329,17 @@ static void ath_tx_status(void *priv, st
+ * Adjust the long retry as if the frame was tried hw->max_rate_tries
+ * times. This affects how ratectrl updates PER for the failed rate.
+ */
+- if (tx_info_priv->tx.ts_flags &
+- (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
+- ((sc->sc_ah->tx_trig_level) >= ath_rc_priv->tx_triglevel_max)) {
++ if ((tx_info->driver_flags & ATH_TX_INFO_UNDERRUN) &&
++ (sc->sc_ah->tx_trig_level >= ath_rc_priv->tx_triglevel_max)) {
+ tx_status = 1;
+ is_underrun = 1;
+ }
+
+- if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
+- (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
++ if (tx_info->driver_flags & ATH_TX_INFO_XRETRY)
+ tx_status = 1;
+
+ ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
+- (is_underrun) ? sc->hw->max_rate_tries :
+- tx_info_priv->tx.ts_longretry);
++ (is_underrun) ? sc->hw->max_rate_tries : long_retry);
+
+ /* Check if aggregation has to be enabled for this tid */
+ if (conf_is_ht(&sc->hw->conf) &&
+@@ -1357,8 +1358,6 @@ static void ath_tx_status(void *priv, st
+ }
+
+ ath_debug_stat_rc(sc, skb);
+-exit:
+- kfree(tx_info_priv);
+ }
+
+ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
diff --git a/package/mac80211/patches/540-monitor_tx_status.patch b/package/mac80211/patches/540-monitor_tx_status.patch
new file mode 100644
index 0000000000..b2a35de852
--- /dev/null
+++ b/package/mac80211/patches/540-monitor_tx_status.patch
@@ -0,0 +1,14 @@
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -587,6 +587,11 @@ void ieee80211_tx_status(struct ieee8021
+ 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) {