From 01732ea5d922b2f0884ac3b2c7a59c62a5d3c729 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Thu, 12 Mar 2015 16:32:07 +0000
Subject: ath9k: fix a beacon enable handling bug

Backport of r44696

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

git-svn-id: svn://svn.openwrt.org/openwrt/branches/barrier_breaker@44697 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 .../kernel/mac80211/patches/300-pending_work.patch | 85 ++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch
index 10c5cad082..b391d58e13 100644
--- a/package/kernel/mac80211/patches/300-pending_work.patch
+++ b/package/kernel/mac80211/patches/300-pending_work.patch
@@ -1,3 +1,20 @@
+commit 182a72b61971fc7120d6163b2077c06618c422a4
+Author: Felix Fietkau <nbd@openwrt.org>
+Date:   Thu Mar 12 17:10:50 2015 +0100
+
+    ath9k: fix tracking of enabled AP beacons
+    
+    sc->nbcnvifs tracks assigned beacon slots, not enabled beacons.
+    Therefore, it cannot be used to decide if cur_conf->enable_beacon (bool)
+    should be updated, or if beacons have been enabled already.
+    With the current code (depending on the order of calls), beacons often
+    do not get enabled in an AP+STA setup.
+    To fix tracking of enabled beacons, convert cur_conf->enable_beacon to a
+    bitmask of enabled beacon slots.
+    
+    Cc: stable@vger.kernel.org
+    Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+
 commit 228ee4473b89118993c17ead26381c490c44f9fb
 Author: Felix Fietkau <nbd@openwrt.org>
 Date:   Sun Nov 30 20:34:16 2014 +0100
@@ -3552,3 +3569,71 @@ Date:   Mon May 19 21:20:49 2014 +0200
  		break;
  	default:
  		ath_err(common, "Invalid TX queue type: %u\n", type);
+--- a/drivers/net/wireless/ath/ath9k/beacon.c
++++ b/drivers/net/wireless/ath/ath9k/beacon.c
+@@ -223,12 +223,15 @@ void ath9k_beacon_remove_slot(struct ath
+ 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ 	struct ath_vif *avp = (void *)vif->drv_priv;
+ 	struct ath_buf *bf = avp->av_bcbuf;
++	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ 
+ 	ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
+ 		avp->av_bslot);
+ 
+ 	tasklet_disable(&sc->bcon_tasklet);
+ 
++	cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
++
+ 	if (bf && bf->bf_mpdu) {
+ 		struct sk_buff *skb = bf->bf_mpdu;
+ 		dma_unmap_single(sc->dev, bf->bf_buf_addr,
+@@ -503,8 +506,7 @@ static bool ath9k_allow_beacon_config(st
+ 	struct ath_vif *avp = (void *)vif->drv_priv;
+ 
+ 	if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
+-		if ((vif->type != NL80211_IFTYPE_AP) ||
+-		    (sc->nbcnvifs > 1)) {
++		if (vif->type != NL80211_IFTYPE_AP) {
+ 			ath_dbg(common, CONFIG,
+ 				"An AP interface is already present !\n");
+ 			return false;
+@@ -567,6 +569,7 @@ void ath9k_beacon_config(struct ath_soft
+ 	struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+         struct ath_hw *ah = sc->sc_ah;
+         struct ath_common *common = ath9k_hw_common(ah);
++	struct ath_vif *avp = (void *)vif->drv_priv;
+ 	unsigned long flags;
+ 	bool skip_beacon = false;
+ 
+@@ -588,12 +591,14 @@ void ath9k_beacon_config(struct ath_soft
+ 	 * enabling/disabling SWBA.
+ 	 */
+ 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+-		if (!bss_conf->enable_beacon &&
+-		    (sc->nbcnvifs <= 1)) {
+-			cur_conf->enable_beacon = false;
+-		} else if (bss_conf->enable_beacon) {
+-			cur_conf->enable_beacon = true;
+-			ath9k_cache_beacon_config(sc, bss_conf);
++		bool enabled = cur_conf->enable_beacon;
++
++		if (!bss_conf->enable_beacon) {
++			cur_conf->enable_beacon &= ~BIT(avp->av_bslot);
++		} else {
++			cur_conf->enable_beacon |= BIT(avp->av_bslot);
++			if (!enabled)
++				ath9k_cache_beacon_config(sc, bss_conf);
+ 		}
+ 	}
+ 
+--- a/drivers/net/wireless/ath/ath9k/common.h
++++ b/drivers/net/wireless/ath/ath9k/common.h
+@@ -53,7 +53,7 @@ struct ath_beacon_config {
+ 	u16 dtim_period;
+ 	u16 bmiss_timeout;
+ 	u8 dtim_count;
+-	bool enable_beacon;
++	u8 enable_beacon;
+ 	bool ibss_creator;
+ 	u32 nexttbtt;
+ 	u32 intval;
-- 
cgit v1.2.3