From 2754907a13a9b7c38e0b9fabdb642a6a8155e4fa Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Sun, 24 Feb 2013 01:11:20 +0000
Subject: [PATCH] mac80211: brcmsmac: add ap mode support

This does not work very well. I did not got this running in 5GHz mode and it was not very fast.

SVN-Revision: 35763
---
 ...nt-ieee80211_ops-get_tsf-and-set_tsf.patch | 121 ++++++++
 ...-add-interface-type-to-brcms_bss_cfg.patch |  66 +++++
 ...62-brcmsmac-remove-brcms_bss_cfg-BSS.patch |  77 +++++
 ...smac-remove-brcms_bss_cfg-associated.patch |  74 +++++
 ...brcmsmac-remove-brcms_bss_cfg-enable.patch |  32 +++
 ...865-brcmsmac-remove-brcms_bss_cfg-up.patch |  47 ++++
 ...c-remove-brcms_bss_cfg-cur_etheraddr.patch |  30 ++
 ...867-brcmsmac-remove-brcms_pub-bcmerr.patch |  21 ++
 ...smac-write-beacon-period-to-hardware.patch |  23 ++
 ...brcmsmac-add-beacon-template-support.patch | 266 ++++++++++++++++++
 .../870-brcmsmac-react-on-changing-SSID.patch |  43 +++
 ...-support-for-probe-response-template.patch | 216 ++++++++++++++
 .../872-brcmsmac-activate-AP-support.patch    |  74 +++++
 ...-remove-extra-regulation-restriction.patch |  31 ++
 14 files changed, 1121 insertions(+)
 create mode 100644 package/mac80211/patches/860-brcmsmac-implement-ieee80211_ops-get_tsf-and-set_tsf.patch
 create mode 100644 package/mac80211/patches/861-brcmsmac-add-interface-type-to-brcms_bss_cfg.patch
 create mode 100644 package/mac80211/patches/862-brcmsmac-remove-brcms_bss_cfg-BSS.patch
 create mode 100644 package/mac80211/patches/863-brcmsmac-remove-brcms_bss_cfg-associated.patch
 create mode 100644 package/mac80211/patches/864-brcmsmac-remove-brcms_bss_cfg-enable.patch
 create mode 100644 package/mac80211/patches/865-brcmsmac-remove-brcms_bss_cfg-up.patch
 create mode 100644 package/mac80211/patches/866-brcmsmac-remove-brcms_bss_cfg-cur_etheraddr.patch
 create mode 100644 package/mac80211/patches/867-brcmsmac-remove-brcms_pub-bcmerr.patch
 create mode 100644 package/mac80211/patches/868-brcmsmac-write-beacon-period-to-hardware.patch
 create mode 100644 package/mac80211/patches/869-brcmsmac-add-beacon-template-support.patch
 create mode 100644 package/mac80211/patches/870-brcmsmac-react-on-changing-SSID.patch
 create mode 100644 package/mac80211/patches/871-brcmsmac-add-support-for-probe-response-template.patch
 create mode 100644 package/mac80211/patches/872-brcmsmac-activate-AP-support.patch
 create mode 100644 package/mac80211/patches/873-brcmsmac-remove-extra-regulation-restriction.patch

diff --git a/package/mac80211/patches/860-brcmsmac-implement-ieee80211_ops-get_tsf-and-set_tsf.patch b/package/mac80211/patches/860-brcmsmac-implement-ieee80211_ops-get_tsf-and-set_tsf.patch
new file mode 100644
index 0000000000..33991bcf62
--- /dev/null
+++ b/package/mac80211/patches/860-brcmsmac-implement-ieee80211_ops-get_tsf-and-set_tsf.patch
@@ -0,0 +1,121 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/d11.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
+@@ -457,6 +457,7 @@ struct d11regs {
+ /*== maccontrol register ==*/
+ #define	MCTL_GMODE		(1U << 31)
+ #define	MCTL_DISCARD_PMQ	(1 << 30)
++#define	MCTL_TBTTHOLD		(1 << 28)
+ #define	MCTL_WAKE		(1 << 26)
+ #define	MCTL_HPS		(1 << 25)
+ #define	MCTL_PROMISC		(1 << 24)
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -741,6 +741,28 @@ static void brcms_ops_flush(struct ieee8
+ 			   "ret=%d\n", jiffies_to_msecs(ret));
+ }
+ 
++static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
++{
++	struct brcms_info *wl = hw->priv;
++	u64 tsf;
++
++	spin_lock_bh(&wl->lock);
++	tsf = brcms_c_tsf_get(wl->wlc);
++	spin_unlock_bh(&wl->lock);
++
++	return tsf;
++}
++
++static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
++			   struct ieee80211_vif *vif, u64 tsf)
++{
++	struct brcms_info *wl = hw->priv;
++
++	spin_lock_bh(&wl->lock);
++	brcms_c_tsf_set(wl->wlc, tsf);
++	spin_unlock_bh(&wl->lock);
++}
++
+ static const struct ieee80211_ops brcms_ops = {
+ 	.tx = brcms_ops_tx,
+ 	.start = brcms_ops_start,
+@@ -757,6 +779,8 @@ static const struct ieee80211_ops brcms_
+ 	.ampdu_action = brcms_ops_ampdu_action,
+ 	.rfkill_poll = brcms_ops_rfkill_poll,
+ 	.flush = brcms_ops_flush,
++	.get_tsf = brcms_ops_get_tsf,
++	.set_tsf = brcms_ops_set_tsf,
+ };
+ 
+ void brcms_dpc(unsigned long data)
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -5545,6 +5545,20 @@ int brcms_c_set_rateset(struct brcms_c_i
+ 	return bcmerror;
+ }
+ 
++static void brcms_c_time_lock(struct brcms_c_info *wlc)
++{
++	bcma_set32(wlc->hw->d11core, D11REGOFFS(maccontrol), MCTL_TBTTHOLD);
++	/* Commit the write */
++	bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
++}
++
++static void brcms_c_time_unlock(struct brcms_c_info *wlc)
++{
++	bcma_mask32(wlc->hw->d11core, D11REGOFFS(maccontrol), ~MCTL_TBTTHOLD);
++	/* Commit the write */
++	bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
++}
++
+ int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
+ {
+ 	if (period == 0)
+@@ -7530,6 +7544,36 @@ void brcms_c_set_beacon_listen_interval(
+ 		brcms_c_bcn_li_upd(wlc);
+ }
+ 
++u64 brcms_c_tsf_get(struct brcms_c_info *wlc)
++{
++	u32 tsf_h, tsf_l;
++	u64 tsf;
++
++	brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
++
++	tsf = tsf_h;
++	tsf <<= 32;
++	tsf |= tsf_l;
++
++	return tsf;
++}
++
++void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf)
++{
++	u32 tsf_h, tsf_l;
++
++	brcms_c_time_lock(wlc);
++
++	tsf_l = tsf;
++	tsf_h = (tsf >> 32);
++
++	/* read the tsf timer low, then high to get an atomic read */
++	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerlow), tsf_l);
++	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerhigh), tsf_h);
++
++	brcms_c_time_unlock(wlc);
++}
++
+ int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
+ {
+ 	uint qdbm;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -326,6 +326,8 @@ extern void brcms_c_set_shortslot_overri
+ 				    s8 sslot_override);
+ extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
+ 					u8 interval);
++extern u64 brcms_c_tsf_get(struct brcms_c_info *wlc);
++extern void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf);
+ extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
+ extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
+ extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
diff --git a/package/mac80211/patches/861-brcmsmac-add-interface-type-to-brcms_bss_cfg.patch b/package/mac80211/patches/861-brcmsmac-add-interface-type-to-brcms_bss_cfg.patch
new file mode 100644
index 0000000000..21b1e0e4d7
--- /dev/null
+++ b/package/mac80211/patches/861-brcmsmac-add-interface-type-to-brcms_bss_cfg.patch
@@ -0,0 +1,66 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -367,9 +367,10 @@ brcms_ops_add_interface(struct ieee80211
+ 	}
+ 
+ 	spin_lock_bh(&wl->lock);
+-	memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
+ 	wl->mute_tx = false;
+ 	brcms_c_mute(wl->wlc, false);
++	if (vif->type == NL80211_IFTYPE_STATION)
++		brcms_c_start_station(wl->wlc, vif->addr);
+ 	spin_unlock_bh(&wl->lock);
+ 
+ 	return 0;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -2165,6 +2165,12 @@ void brcms_b_switch_macfreq(struct brcms
+ 	}
+ }
+ 
++void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr)
++{
++	memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
++	wlc->bsscfg->type = BRCMS_TYPE_STATION;
++}
++
+ /* Initialize GPIOs that are controlled by D11 core */
+ static void brcms_c_gpio_init(struct brcms_c_info *wlc)
+ {
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -576,10 +576,17 @@ struct antsel_info {
+ 	struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */
+ };
+ 
++enum brcms_bss_type {
++	BRCMS_TYPE_STATION,
++	BRCMS_TYPE_AP,
++	BRCMS_TYPE_ADHOC,
++};
++
+ /*
+  * BSS configuration state
+  *
+  * wlc: wlc to which this bsscfg belongs to.
++ * type: interface type
+  * up: is this configuration up operational
+  * enable: is this configuration enabled
+  * associated: is BSS in ASSOCIATED state
+@@ -599,6 +606,7 @@ struct antsel_info {
+  */
+ struct brcms_bss_cfg {
+ 	struct brcms_c_info *wlc;
++	enum brcms_bss_type type;
+ 	bool up;
+ 	bool enable;
+ 	bool associated;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -333,5 +333,6 @@ extern int brcms_c_get_tx_power(struct b
+ extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
+ extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
+ extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
++extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr);
+ 
+ #endif				/* _BRCM_PUB_H_ */
diff --git a/package/mac80211/patches/862-brcmsmac-remove-brcms_bss_cfg-BSS.patch b/package/mac80211/patches/862-brcmsmac-remove-brcms_bss_cfg-BSS.patch
new file mode 100644
index 0000000000..a7ffcf6a78
--- /dev/null
+++ b/package/mac80211/patches/862-brcmsmac-remove-brcms_bss_cfg-BSS.patch
@@ -0,0 +1,77 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -1071,7 +1071,7 @@ brcms_b_txstatus(struct brcms_hardware *
+ 
+ static void brcms_c_tbtt(struct brcms_c_info *wlc)
+ {
+-	if (!wlc->bsscfg->BSS)
++	if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
+ 		/*
+ 		 * DirFrmQ is now valid...defer setting until end
+ 		 * of ATIM window
+@@ -3061,16 +3061,8 @@ static bool brcms_c_ps_allowed(struct br
+ 	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
+ 		return false;
+ 
+-	if (cfg->associated) {
+-		/*
+-		 * disallow PS when one of the following
+-		 * bsscfg specific conditions meets
+-		 */
+-		if (!cfg->BSS)
+-			return false;
+-
++	if (cfg->associated)
+ 		return false;
+-	}
+ 
+ 	return true;
+ }
+@@ -5080,8 +5072,9 @@ int brcms_c_up(struct brcms_c_info *wlc)
+ 				struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 				mboolset(wlc->pub->radio_disabled,
+ 					 WL_RADIO_HW_DISABLE);
+-
+-				if (bsscfg->enable && bsscfg->BSS)
++				if (bsscfg->enable &&
++				    (bsscfg->type == BRCMS_TYPE_STATION ||
++				     bsscfg->type == BRCMS_TYPE_ADHOC))
+ 					brcms_err(wlc->hw->d11core,
+ 						  "wl%d: up: rfdisable -> "
+ 						  "bsscfg_disable()\n",
+@@ -7390,7 +7383,7 @@ void brcms_c_update_beacon(struct brcms_
+ {
+ 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 
+-	if (bsscfg->up && !bsscfg->BSS)
++	if (bsscfg->up && bsscfg->type == BRCMS_TYPE_AP)
+ 		/* Clear the soft intmask */
+ 		wlc->defmacintmask &= ~MI_BCNTPL;
+ }
+@@ -7465,7 +7458,7 @@ void brcms_c_update_probe_resp(struct br
+ 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 
+ 	/* update AP or IBSS probe responses */
+-	if (bsscfg->up && !bsscfg->BSS)
++	if (bsscfg->up && bsscfg->type == BRCMS_TYPE_AP)
+ 		brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
+ }
+ 
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -590,7 +590,6 @@ enum brcms_bss_type {
+  * up: is this configuration up operational
+  * enable: is this configuration enabled
+  * associated: is BSS in ASSOCIATED state
+- * BSS: infraustructure or adhoc
+  * SSID_len: the length of SSID
+  * SSID: SSID string
+  *
+@@ -610,7 +609,6 @@ struct brcms_bss_cfg {
+ 	bool up;
+ 	bool enable;
+ 	bool associated;
+-	bool BSS;
+ 	u8 SSID_len;
+ 	u8 SSID[IEEE80211_MAX_SSID_LEN];
+ 	u8 BSSID[ETH_ALEN];
diff --git a/package/mac80211/patches/863-brcmsmac-remove-brcms_bss_cfg-associated.patch b/package/mac80211/patches/863-brcmsmac-remove-brcms_bss_cfg-associated.patch
new file mode 100644
index 0000000000..7f84f00e29
--- /dev/null
+++ b/package/mac80211/patches/863-brcmsmac-remove-brcms_bss_cfg-associated.patch
@@ -0,0 +1,74 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -3051,8 +3051,6 @@ static void brcms_b_antsel_set(struct br
+  */
+ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+ {
+-	struct brcms_bss_cfg *cfg = wlc->bsscfg;
+-
+ 	/* disallow PS when one of the following global conditions meets */
+ 	if (!wlc->pub->associated)
+ 		return false;
+@@ -3061,9 +3059,6 @@ static bool brcms_c_ps_allowed(struct br
+ 	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
+ 		return false;
+ 
+-	if (cfg->associated)
+-		return false;
+-
+ 	return true;
+ }
+ 
+@@ -3821,7 +3816,7 @@ static void brcms_c_set_home_chanspec(st
+ 	if (wlc->home_chanspec != chanspec) {
+ 		wlc->home_chanspec = chanspec;
+ 
+-		if (wlc->bsscfg->associated)
++		if (wlc->pub->associated)
+ 			wlc->bsscfg->current_bss->chanspec = chanspec;
+ 	}
+ }
+@@ -5435,7 +5430,7 @@ static void brcms_c_ofdm_rateset_war(str
+ 	u8 r;
+ 	bool war = false;
+ 
+-	if (wlc->bsscfg->associated)
++	if (wlc->pub->associated)
+ 		r = wlc->bsscfg->current_bss->rateset.rates[0];
+ 	else
+ 		r = wlc->default_bss->rateset.rates[0];
+@@ -5529,7 +5524,7 @@ int brcms_c_set_rateset(struct brcms_c_i
+ 	/* merge rateset coming in with the current mcsset */
+ 	if (wlc->pub->_n_enab & SUPPORT_11N) {
+ 		struct brcms_bss_info *mcsset_bss;
+-		if (wlc->bsscfg->associated)
++		if (wlc->pub->associated)
+ 			mcsset_bss = wlc->bsscfg->current_bss;
+ 		else
+ 			mcsset_bss = wlc->default_bss;
+@@ -7498,7 +7493,6 @@ void brcms_c_scan_stop(struct brcms_c_in
+ void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
+ {
+ 	wlc->pub->associated = state;
+-	wlc->bsscfg->associated = state;
+ }
+ 
+ /*
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -589,7 +589,6 @@ enum brcms_bss_type {
+  * type: interface type
+  * up: is this configuration up operational
+  * enable: is this configuration enabled
+- * associated: is BSS in ASSOCIATED state
+  * SSID_len: the length of SSID
+  * SSID: SSID string
+  *
+@@ -608,7 +607,6 @@ struct brcms_bss_cfg {
+ 	enum brcms_bss_type type;
+ 	bool up;
+ 	bool enable;
+-	bool associated;
+ 	u8 SSID_len;
+ 	u8 SSID[IEEE80211_MAX_SSID_LEN];
+ 	u8 BSSID[ETH_ALEN];
diff --git a/package/mac80211/patches/864-brcmsmac-remove-brcms_bss_cfg-enable.patch b/package/mac80211/patches/864-brcmsmac-remove-brcms_bss_cfg-enable.patch
new file mode 100644
index 0000000000..9f5c4da7fe
--- /dev/null
+++ b/package/mac80211/patches/864-brcmsmac-remove-brcms_bss_cfg-enable.patch
@@ -0,0 +1,32 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -5067,9 +5067,8 @@ int brcms_c_up(struct brcms_c_info *wlc)
+ 				struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 				mboolset(wlc->pub->radio_disabled,
+ 					 WL_RADIO_HW_DISABLE);
+-				if (bsscfg->enable &&
+-				    (bsscfg->type == BRCMS_TYPE_STATION ||
+-				     bsscfg->type == BRCMS_TYPE_ADHOC))
++				if (bsscfg->type == BRCMS_TYPE_STATION ||
++				    bsscfg->type == BRCMS_TYPE_ADHOC)
+ 					brcms_err(wlc->hw->d11core,
+ 						  "wl%d: up: rfdisable -> "
+ 						  "bsscfg_disable()\n",
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -588,7 +588,6 @@ enum brcms_bss_type {
+  * wlc: wlc to which this bsscfg belongs to.
+  * type: interface type
+  * up: is this configuration up operational
+- * enable: is this configuration enabled
+  * SSID_len: the length of SSID
+  * SSID: SSID string
+  *
+@@ -606,7 +605,6 @@ struct brcms_bss_cfg {
+ 	struct brcms_c_info *wlc;
+ 	enum brcms_bss_type type;
+ 	bool up;
+-	bool enable;
+ 	u8 SSID_len;
+ 	u8 SSID[IEEE80211_MAX_SSID_LEN];
+ 	u8 BSSID[ETH_ALEN];
diff --git a/package/mac80211/patches/865-brcmsmac-remove-brcms_bss_cfg-up.patch b/package/mac80211/patches/865-brcmsmac-remove-brcms_bss_cfg-up.patch
new file mode 100644
index 0000000000..40fe6eaf6e
--- /dev/null
+++ b/package/mac80211/patches/865-brcmsmac-remove-brcms_bss_cfg-up.patch
@@ -0,0 +1,47 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -7377,7 +7377,7 @@ void brcms_c_update_beacon(struct brcms_
+ {
+ 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 
+-	if (bsscfg->up && bsscfg->type == BRCMS_TYPE_AP)
++	if (wlc->pub->up && bsscfg->type == BRCMS_TYPE_AP)
+ 		/* Clear the soft intmask */
+ 		wlc->defmacintmask &= ~MI_BCNTPL;
+ }
+@@ -7452,7 +7452,7 @@ void brcms_c_update_probe_resp(struct br
+ 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 
+ 	/* update AP or IBSS probe responses */
+-	if (bsscfg->up && bsscfg->type == BRCMS_TYPE_AP)
++	if (wlc->pub->up && bsscfg->type == BRCMS_TYPE_AP)
+ 		brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
+ }
+ 
+@@ -7805,7 +7805,7 @@ void brcms_c_init(struct brcms_c_info *w
+ 	brcms_c_set_bssid(wlc->bsscfg);
+ 
+ 	/* Update tsf_cfprep if associated and up */
+-	if (wlc->pub->associated && wlc->bsscfg->up) {
++	if (wlc->pub->associated && wlc->pub->up) {
+ 		u32 bi;
+ 
+ 		/* get beacon period and convert to uS */
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -587,7 +587,6 @@ enum brcms_bss_type {
+  *
+  * wlc: wlc to which this bsscfg belongs to.
+  * type: interface type
+- * up: is this configuration up operational
+  * SSID_len: the length of SSID
+  * SSID: SSID string
+  *
+@@ -604,7 +603,6 @@ enum brcms_bss_type {
+ struct brcms_bss_cfg {
+ 	struct brcms_c_info *wlc;
+ 	enum brcms_bss_type type;
+-	bool up;
+ 	u8 SSID_len;
+ 	u8 SSID[IEEE80211_MAX_SSID_LEN];
+ 	u8 BSSID[ETH_ALEN];
diff --git a/package/mac80211/patches/866-brcmsmac-remove-brcms_bss_cfg-cur_etheraddr.patch b/package/mac80211/patches/866-brcmsmac-remove-brcms_bss_cfg-cur_etheraddr.patch
new file mode 100644
index 0000000000..0571932e8c
--- /dev/null
+++ b/package/mac80211/patches/866-brcmsmac-remove-brcms_bss_cfg-cur_etheraddr.patch
@@ -0,0 +1,30 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -3766,7 +3766,7 @@ static int brcms_c_set_mac(struct brcms_
+ 	struct brcms_c_info *wlc = bsscfg->wlc;
+ 
+ 	/* enter the MAC addr into the RXE match registers */
+-	brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr);
++	brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, wlc->pub->cur_etheraddr);
+ 
+ 	brcms_c_ampdu_macaddr_upd(wlc);
+ 
+@@ -7359,7 +7359,7 @@ brcms_c_bcn_prb_template(struct brcms_c_
+ 	/* A1 filled in by MAC for prb resp, broadcast for bcn */
+ 	if (type == IEEE80211_STYPE_BEACON)
+ 		memcpy(&h->da, &ether_bcast, ETH_ALEN);
+-	memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
++	memcpy(&h->sa, &wlc->pub->cur_etheraddr, ETH_ALEN);
+ 	memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
+ 
+ 	/* SEQ filled in by MAC */
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -606,7 +606,6 @@ struct brcms_bss_cfg {
+ 	u8 SSID_len;
+ 	u8 SSID[IEEE80211_MAX_SSID_LEN];
+ 	u8 BSSID[ETH_ALEN];
+-	u8 cur_etheraddr[ETH_ALEN];
+ 	struct brcms_bss_info *current_bss;
+ };
+ 
diff --git a/package/mac80211/patches/867-brcmsmac-remove-brcms_pub-bcmerr.patch b/package/mac80211/patches/867-brcmsmac-remove-brcms_pub-bcmerr.patch
new file mode 100644
index 0000000000..2e7c166c36
--- /dev/null
+++ b/package/mac80211/patches/867-brcmsmac-remove-brcms_pub-bcmerr.patch
@@ -0,0 +1,21 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -4327,7 +4327,6 @@ static void brcms_c_info_init(struct brc
+ 
+ 	/* WME QoS mode is Auto by default */
+ 	wlc->pub->_ampdu = AMPDU_AGG_HOST;
+-	wlc->pub->bcmerror = 0;
+ }
+ 
+ static uint brcms_c_attach_module(struct brcms_c_info *wlc)
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -164,8 +164,6 @@ struct brcms_pub {
+ 
+ 	u8 cur_etheraddr[ETH_ALEN];	/* our local ethernet address */
+ 
+-	int bcmerror;		/* last bcm error */
+-
+ 	u32 radio_disabled;	/* bit vector for radio disabled reasons */
+ 
+ 	u16 boardrev;	/* version # of particular board */
diff --git a/package/mac80211/patches/868-brcmsmac-write-beacon-period-to-hardware.patch b/package/mac80211/patches/868-brcmsmac-write-beacon-period-to-hardware.patch
new file mode 100644
index 0000000000..fb10e1ba6e
--- /dev/null
+++ b/package/mac80211/patches/868-brcmsmac-write-beacon-period-to-hardware.patch
@@ -0,0 +1,23 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -5553,10 +5553,20 @@ static void brcms_c_time_unlock(struct b
+ 
+ int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
+ {
++	u32 bcnint_us;
++
+ 	if (period == 0)
+ 		return -EINVAL;
+ 
+ 	wlc->default_bss->beacon_period = period;
++
++	bcnint_us = period << 10;
++	brcms_c_time_lock(wlc);
++	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfprep),
++		     (bcnint_us << CFPREP_CBI_SHIFT));
++	bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfpstart), bcnint_us);
++	brcms_c_time_unlock(wlc);
++
+ 	return 0;
+ }
+ 
diff --git a/package/mac80211/patches/869-brcmsmac-add-beacon-template-support.patch b/package/mac80211/patches/869-brcmsmac-add-beacon-template-support.patch
new file mode 100644
index 0000000000..ab864a3dbf
--- /dev/null
+++ b/package/mac80211/patches/869-brcmsmac-add-beacon-template-support.patch
@@ -0,0 +1,266 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright (c) 2010 Broadcom Corporation
++ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Permission to use, copy, modify, and/or distribute this software for any
+  * purpose with or without fee is hereby granted, provided that the above
+@@ -522,9 +523,17 @@ brcms_ops_bss_info_changed(struct ieee80
+ 		brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
+ 		spin_unlock_bh(&wl->lock);
+ 	}
+-	if (changed & BSS_CHANGED_BEACON)
++	if (changed & BSS_CHANGED_BEACON) {
+ 		/* Beacon data changed, retrieve new beacon (beaconing modes) */
+-		brcms_err(core, "%s: beacon changed\n", __func__);
++		struct sk_buff *beacon;
++		u16 tim_offset = 0;
++
++		spin_lock_bh(&wl->lock);
++		beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL);
++		brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,
++				       info->dtim_period);
++		spin_unlock_bh(&wl->lock);
++	}
+ 
+ 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ 		/* Beaconing should be enabled/disabled (beaconing modes) */
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright (c) 2010 Broadcom Corporation
++ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Permission to use, copy, modify, and/or distribute this software for any
+  * purpose with or without fee is hereby granted, provided that the above
+@@ -450,6 +451,8 @@ static void brcms_c_detach_mfree(struct
+ 	kfree(wlc->corestate);
+ 	kfree(wlc->hw->bandstate[0]);
+ 	kfree(wlc->hw);
++	if (wlc->beacon)
++		dev_kfree_skb_any(wlc->beacon);
+ 
+ 	/* free the wlc */
+ 	kfree(wlc);
+@@ -4086,10 +4089,14 @@ void brcms_c_wme_setparams(struct brcms_
+ 					  *shm_entry++);
+ 	}
+ 
+-	if (suspend) {
++	if (suspend)
+ 		brcms_c_suspend_mac_and_wait(wlc);
++
++	brcms_c_update_beacon(wlc);
++	brcms_c_update_probe_resp(wlc, false);
++
++	if (suspend)
+ 		brcms_c_enable_mac(wlc);
+-	}
+ }
+ 
+ static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+@@ -7379,6 +7386,107 @@ int brcms_c_get_header_len(void)
+ 	return TXOFF;
+ }
+ 
++static void brcms_c_beacon_write(struct brcms_c_info *wlc,
++				 struct sk_buff *beacon, u16 tim_offset,
++				 u16 dtim_period, bool bcn0, bool bcn1)
++{
++	size_t len;
++	struct ieee80211_tx_info *tx_info;
++	struct brcms_hardware *wlc_hw = wlc->hw;
++	struct ieee80211_hw *ieee_hw = brcms_c_pub(wlc)->ieee_hw;
++
++	/* Get tx_info */
++	tx_info = IEEE80211_SKB_CB(beacon);
++
++	len = min_t(size_t, beacon->len, BCN_TMPL_LEN);
++	wlc->bcn_rspec = ieee80211_get_tx_rate(ieee_hw, tx_info)->hw_value;
++
++	brcms_c_compute_plcp(wlc, wlc->bcn_rspec,
++			     len + FCS_LEN - D11_PHY_HDR_LEN, beacon->data);
++
++	/* "Regular" and 16 MBSS but not for 4 MBSS */
++	/* Update the phytxctl for the beacon based on the rspec */
++	brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
++
++	if (bcn0) {
++		/* write the probe response into the template region */
++		brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE,
++					    (len + 3) & ~3, beacon->data);
++
++		/* write beacon length to SCR */
++		brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
++	}
++	if (bcn1) {
++		/* write the probe response into the template region */
++		brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE,
++					    (len + 3) & ~3, beacon->data);
++
++		/* write beacon length to SCR */
++		brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
++	}
++
++	if (tim_offset != 0) {
++		brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
++				  tim_offset + D11B_PHY_HDR_LEN);
++		brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, dtim_period);
++	} else {
++		brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
++				  len + D11B_PHY_HDR_LEN);
++		brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, 0);
++	}
++}
++
++static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc,
++				     struct sk_buff *beacon, u16 tim_offset,
++				     u16 dtim_period)
++{
++	struct brcms_hardware *wlc_hw = wlc->hw;
++	struct bcma_device *core = wlc_hw->d11core;
++
++	/* Hardware beaconing for this config */
++	u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
++
++	/* Check if both templates are in use, if so sched. an interrupt
++	 *      that will call back into this routine
++	 */
++	if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid)
++		/* clear any previous status */
++		bcma_write32(core, D11REGOFFS(macintstatus), MI_BCNTPL);
++
++	if (wlc->beacon_template_virgin) {
++		wlc->beacon_template_virgin = false;
++		brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
++				     true);
++		/* mark beacon0 valid */
++		bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
++		return;
++	}
++
++	/* Check that after scheduling the interrupt both of the
++	 *      templates are still busy. if not clear the int. & remask
++	 */
++	if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid) {
++		wlc->defmacintmask |= MI_BCNTPL;
++		return;
++	}
++
++	if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN0VLD)) {
++		brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
++				     false);
++		/* mark beacon0 valid */
++		bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
++		return;
++	}
++	if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN1VLD)) {
++		brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period,
++				     false, true);
++		/* mark beacon0 valid */
++		bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD);
++		return;
++	}
++	return;
++}
++
+ /*
+  * Update all beacons for the system.
+  */
+@@ -7386,9 +7494,31 @@ void brcms_c_update_beacon(struct brcms_
+ {
+ 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 
+-	if (wlc->pub->up && bsscfg->type == BRCMS_TYPE_AP)
++	if (wlc->pub->up && bsscfg->type == BRCMS_TYPE_AP) {
+ 		/* Clear the soft intmask */
+ 		wlc->defmacintmask &= ~MI_BCNTPL;
++		if (!wlc->beacon)
++			return;
++		brcms_c_update_beacon_hw(wlc, wlc->beacon,
++					 wlc->beacon_tim_offset,
++					 wlc->beacon_dtim_period);
++	}
++}
++
++void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon,
++			    u16 tim_offset, u16 dtim_period)
++{
++	if (!beacon)
++		return;
++	if (wlc->beacon)
++		dev_kfree_skb_any(wlc->beacon);
++	wlc->beacon = beacon;
++
++	/* add PLCP */
++	skb_push(wlc->beacon, D11_PHY_HDR_LEN);
++	wlc->beacon_tim_offset = tim_offset;
++	wlc->beacon_dtim_period = dtim_period;
++	brcms_c_update_beacon(wlc);
+ }
+ 
+ /* Write ssid into shared memory */
+@@ -7786,6 +7916,10 @@ bool brcms_c_dpc(struct brcms_c_info *wl
+ 		brcms_rfkill_set_hw_state(wlc->wl);
+ 	}
+ 
++	/* BCN template is available */
++	if (macintstatus & MI_BCNTPL)
++		brcms_c_update_beacon(wlc);
++
+ 	/* it isn't done and needs to be resched if macintstatus is non-zero */
+ 	return wlc->macintstatus != 0;
+ 
+@@ -7917,6 +8051,7 @@ brcms_c_attach(struct brcms_info *wl, st
+ 	pub->unit = unit;
+ 	pub->_piomode = piomode;
+ 	wlc->bandinit_pending = false;
++	wlc->beacon_template_virgin = true;
+ 
+ 	/* populate struct brcms_c_info with default values  */
+ 	brcms_c_info_init(wlc, unit);
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -492,6 +492,8 @@ struct brcms_c_info {
+ 	bool radio_monitor;
+ 	bool going_down;
+ 
++	bool beacon_template_virgin;
++
+ 	struct brcms_timer *wdtimer;
+ 	struct brcms_timer *radio_timer;
+ 
+@@ -561,6 +563,10 @@ struct brcms_c_info {
+ 
+ 	struct wiphy *wiphy;
+ 	struct scb pri_scb;
++
++	struct sk_buff *beacon;
++	u16 beacon_tim_offset;
++	u16 beacon_dtim_period;
+ };
+ 
+ /* antsel module specific state */
+@@ -630,7 +636,6 @@ extern u16 brcms_c_compute_rtscts_dur(st
+ extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
+ 			       struct ieee80211_sta *sta,
+ 			       void (*dma_callback_fn));
+-extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
+ extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
+ extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
+ extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -332,5 +332,9 @@ extern bool brcms_c_check_radio_disabled
+ extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
+ extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
+ extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr);
++extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
++extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
++				   struct sk_buff *beacon, u16 tim_offset,
++				   u16 dtim_period);
+ 
+ #endif				/* _BRCM_PUB_H_ */
diff --git a/package/mac80211/patches/870-brcmsmac-react-on-changing-SSID.patch b/package/mac80211/patches/870-brcmsmac-react-on-changing-SSID.patch
new file mode 100644
index 0000000000..34969ad351
--- /dev/null
+++ b/package/mac80211/patches/870-brcmsmac-react-on-changing-SSID.patch
@@ -0,0 +1,43 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -523,6 +523,12 @@ brcms_ops_bss_info_changed(struct ieee80
+ 		brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
+ 		spin_unlock_bh(&wl->lock);
+ 	}
++	if (changed & BSS_CHANGED_SSID) {
++		/* BSSID changed, for whatever reason (IBSS and managed mode) */
++		spin_lock_bh(&wl->lock);
++		brcms_c_set_ssid(wl->wlc, info->ssid, info->ssid_len);
++		spin_unlock_bh(&wl->lock);
++	}
+ 	if (changed & BSS_CHANGED_BEACON) {
+ 		/* Beacon data changed, retrieve new beacon (beaconing modes) */
+ 		struct sk_buff *beacon;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -3785,6 +3785,15 @@ static void brcms_c_set_bssid(struct brc
+ 	brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
+ }
+ 
++void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, size_t ssid_len)
++{
++	u8 len = min_t(u8, sizeof(wlc->bsscfg->SSID), ssid_len);
++	memset(wlc->bsscfg->SSID, 0, sizeof(wlc->bsscfg->SSID));
++
++	memcpy(wlc->bsscfg->SSID, ssid, len);
++	wlc->bsscfg->SSID_len = len;
++}
++
+ static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
+ {
+ 	wlc_hw->shortslot = shortslot;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -336,5 +336,7 @@ extern void brcms_c_update_beacon(struct
+ extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
+ 				   struct sk_buff *beacon, u16 tim_offset,
+ 				   u16 dtim_period);
++extern void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid,
++			     size_t ssid_len);
+ 
+ #endif				/* _BRCM_PUB_H_ */
diff --git a/package/mac80211/patches/871-brcmsmac-add-support-for-probe-response-template.patch b/package/mac80211/patches/871-brcmsmac-add-support-for-probe-response-template.patch
new file mode 100644
index 0000000000..5d022d2b57
--- /dev/null
+++ b/package/mac80211/patches/871-brcmsmac-add-support-for-probe-response-template.patch
@@ -0,0 +1,216 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -541,6 +541,15 @@ brcms_ops_bss_info_changed(struct ieee80
+ 		spin_unlock_bh(&wl->lock);
+ 	}
+ 
++	if (changed & BSS_CHANGED_AP_PROBE_RESP) {
++		struct sk_buff *probe_resp;
++
++		spin_lock_bh(&wl->lock);
++		probe_resp = ieee80211_proberesp_get(hw, vif);
++		brcms_c_set_new_probe_resp(wl->wlc, probe_resp);
++		spin_unlock_bh(&wl->lock);
++	}
++
+ 	if (changed & BSS_CHANGED_BEACON_ENABLED) {
+ 		/* Beaconing should be enabled/disabled (beaconing modes) */
+ 		brcms_err(core, "%s: Beacon enabled: %s\n", __func__,
+@@ -1039,6 +1048,8 @@ static int ieee_hw_init(struct ieee80211
+ 	hw->channel_change_time = 7 * 1000;
+ 	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ 
++	hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
++
+ 	hw->rate_control_algorithm = "minstrel_ht";
+ 
+ 	hw->sta_data_size = 0;
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -453,6 +453,8 @@ static void brcms_c_detach_mfree(struct
+ 	kfree(wlc->hw);
+ 	if (wlc->beacon)
+ 		dev_kfree_skb_any(wlc->beacon);
++	if (wlc->probe_resp)
++		dev_kfree_skb_any(wlc->probe_resp);
+ 
+ 	/* free the wlc */
+ 	kfree(wlc);
+@@ -7327,69 +7329,6 @@ brcms_c_mod_prb_rsp_rate_table(struct br
+ 	}
+ }
+ 
+-/*	Max buffering needed for beacon template/prb resp template is 142 bytes.
+- *
+- *	PLCP header is 6 bytes.
+- *	802.11 A3 header is 24 bytes.
+- *	Max beacon frame body template length is 112 bytes.
+- *	Max probe resp frame body template length is 110 bytes.
+- *
+- *      *len on input contains the max length of the packet available.
+- *
+- *	The *len value is set to the number of bytes in buf used, and starts
+- *	with the PLCP and included up to, but not including, the 4 byte FCS.
+- */
+-static void
+-brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
+-			 u32 bcn_rspec,
+-			 struct brcms_bss_cfg *cfg, u16 *buf, int *len)
+-{
+-	static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
+-	struct cck_phy_hdr *plcp;
+-	struct ieee80211_mgmt *h;
+-	int hdr_len, body_len;
+-
+-	hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
+-
+-	/* calc buffer size provided for frame body */
+-	body_len = *len - hdr_len;
+-	/* return actual size */
+-	*len = hdr_len + body_len;
+-
+-	/* format PHY and MAC headers */
+-	memset(buf, 0, hdr_len);
+-
+-	plcp = (struct cck_phy_hdr *) buf;
+-
+-	/*
+-	 * PLCP for Probe Response frames are filled in from
+-	 * core's rate table
+-	 */
+-	if (type == IEEE80211_STYPE_BEACON)
+-		/* fill in PLCP */
+-		brcms_c_compute_plcp(wlc, bcn_rspec,
+-				 (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
+-				 (u8 *) plcp);
+-
+-	/* "Regular" and 16 MBSS but not for 4 MBSS */
+-	/* Update the phytxctl for the beacon based on the rspec */
+-	brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
+-
+-	h = (struct ieee80211_mgmt *)&plcp[1];
+-
+-	/* fill in 802.11 header */
+-	h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
+-
+-	/* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
+-	/* A1 filled in by MAC for prb resp, broadcast for bcn */
+-	if (type == IEEE80211_STYPE_BEACON)
+-		memcpy(&h->da, &ether_bcast, ETH_ALEN);
+-	memcpy(&h->sa, &wlc->pub->cur_etheraddr, ETH_ALEN);
+-	memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
+-
+-	/* SEQ filled in by MAC */
+-}
+-
+ int brcms_c_get_header_len(void)
+ {
+ 	return TXOFF;
+@@ -7530,6 +7469,20 @@ void brcms_c_set_new_beacon(struct brcms
+ 	brcms_c_update_beacon(wlc);
+ }
+ 
++void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
++				struct sk_buff *probe_resp)
++{
++	if (!probe_resp)
++		return;
++	if (wlc->probe_resp)
++		dev_kfree_skb_any(wlc->probe_resp);
++	wlc->probe_resp = probe_resp;
++
++	/* add PLCP */
++	skb_push(wlc->probe_resp, D11_PHY_HDR_LEN);
++	brcms_c_update_probe_resp(wlc, false);
++}
++
+ /* Write ssid into shared memory */
+ static void
+ brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
+@@ -7549,30 +7502,19 @@ brcms_c_shm_ssid_upd(struct brcms_c_info
+ static void
+ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
+ 			      struct brcms_bss_cfg *cfg,
++			      struct sk_buff *probe_resp,
+ 			      bool suspend)
+ {
+-	u16 *prb_resp;
+-	int len = BCN_TMPL_LEN;
++	int len;
+ 
+-	prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
+-	if (!prb_resp)
+-		return;
+-
+-	/*
+-	 * write the probe response to hardware, or save in
+-	 * the config structure
+-	 */
+-
+-	/* create the probe response template */
+-	brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
+-				 cfg, prb_resp, &len);
++	len = min_t(size_t, probe_resp->len, BCN_TMPL_LEN);
+ 
+ 	if (suspend)
+ 		brcms_c_suspend_mac_and_wait(wlc);
+ 
+ 	/* write the probe response into the template region */
+ 	brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
+-				    (len + 3) & ~3, prb_resp);
++				    (len + 3) & ~3, probe_resp->data);
+ 
+ 	/* write the length of the probe response frame (+PLCP/-FCS) */
+ 	brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
+@@ -7586,13 +7528,11 @@ brcms_c_bss_update_probe_resp(struct brc
+ 	 * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
+ 	 * by subtracting the PLCP len and adding the FCS.
+ 	 */
+-	len += (-D11_PHY_HDR_LEN + FCS_LEN);
+-	brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
++	brcms_c_mod_prb_rsp_rate_table(wlc,
++				      (u16)len + FCS_LEN - D11_PHY_HDR_LEN);
+ 
+ 	if (suspend)
+ 		brcms_c_enable_mac(wlc);
+-
+-	kfree(prb_resp);
+ }
+ 
+ void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
+@@ -7600,8 +7540,12 @@ void brcms_c_update_probe_resp(struct br
+ 	struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+ 
+ 	/* update AP or IBSS probe responses */
+-	if (wlc->pub->up && bsscfg->type == BRCMS_TYPE_AP)
+-		brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
++	if (wlc->pub->up && bsscfg->type == BRCMS_TYPE_AP) {
++		if (!wlc->probe_resp)
++			return;
++		brcms_c_bss_update_probe_resp(wlc, bsscfg, wlc->probe_resp,
++					      suspend);
++	}
+ }
+ 
+ int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
+@@ -567,6 +567,7 @@ struct brcms_c_info {
+ 	struct sk_buff *beacon;
+ 	u16 beacon_tim_offset;
+ 	u16 beacon_dtim_period;
++	struct sk_buff *probe_resp;
+ };
+ 
+ /* antsel module specific state */
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -336,6 +336,8 @@ extern void brcms_c_update_beacon(struct
+ extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
+ 				   struct sk_buff *beacon, u16 tim_offset,
+ 				   u16 dtim_period);
++extern void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
++				       struct sk_buff *probe_resp);
+ extern void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid,
+ 			     size_t ssid_len);
+ 
diff --git a/package/mac80211/patches/872-brcmsmac-activate-AP-support.patch b/package/mac80211/patches/872-brcmsmac-activate-AP-support.patch
new file mode 100644
index 0000000000..aaf6840c56
--- /dev/null
+++ b/package/mac80211/patches/872-brcmsmac-activate-AP-support.patch
@@ -0,0 +1,74 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+@@ -360,7 +360,8 @@ brcms_ops_add_interface(struct ieee80211
+ 	struct brcms_info *wl = hw->priv;
+ 
+ 	/* Just STA for now */
+-	if (vif->type != NL80211_IFTYPE_STATION) {
++	if (vif->type != NL80211_IFTYPE_STATION &&
++	    vif->type != NL80211_IFTYPE_AP) {
+ 		brcms_err(wl->wlc->hw->d11core,
+ 			  "%s: Attempt to add type %d, only STA for now\n",
+ 			  __func__, vif->type);
+@@ -372,6 +373,9 @@ brcms_ops_add_interface(struct ieee80211
+ 	brcms_c_mute(wl->wlc, false);
+ 	if (vif->type == NL80211_IFTYPE_STATION)
+ 		brcms_c_start_station(wl->wlc, vif->addr);
++	else if (vif->type == NL80211_IFTYPE_AP)
++		brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid,
++				 vif->bss_conf.ssid, vif->bss_conf.ssid_len);
+ 	spin_unlock_bh(&wl->lock);
+ 
+ 	return 0;
+@@ -1046,7 +1050,8 @@ static int ieee_hw_init(struct ieee80211
+ 
+ 	/* channel change time is dependent on chip and band  */
+ 	hw->channel_change_time = 7 * 1000;
+-	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
++	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
++				     BIT(NL80211_IFTYPE_AP);
+ 
+ 	hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+ 
+--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
+@@ -2176,6 +2176,18 @@ void brcms_c_start_station(struct brcms_
+ 	wlc->bsscfg->type = BRCMS_TYPE_STATION;
+ }
+ 
++void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, const u8 *bssid,
++		      u8 *ssid, size_t ssid_len)
++{
++	brcms_c_set_ssid(wlc, ssid, ssid_len);
++
++	memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
++	memcpy(wlc->bsscfg->BSSID, bssid, sizeof(wlc->bsscfg->BSSID));
++	wlc->bsscfg->type = BRCMS_TYPE_AP;
++
++	brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, MCTL_AP | MCTL_INFRA);
++}
++
+ /* Initialize GPIOs that are controlled by D11 core */
+ static void brcms_c_gpio_init(struct brcms_c_info *wlc)
+ {
+@@ -3064,6 +3076,9 @@ static bool brcms_c_ps_allowed(struct br
+ 	if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
+ 		return false;
+ 
++	if (wlc->bsscfg->type == BRCMS_TYPE_AP)
++		return false;
++
+ 	return true;
+ }
+ 
+--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
++++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+@@ -332,6 +332,8 @@ extern bool brcms_c_check_radio_disabled
+ extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
+ extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
+ extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr);
++extern void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr,
++			     const u8 *bssid, u8 *ssid, size_t ssid_len);
+ extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
+ extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
+ 				   struct sk_buff *beacon, u16 tim_offset,
diff --git a/package/mac80211/patches/873-brcmsmac-remove-extra-regulation-restriction.patch b/package/mac80211/patches/873-brcmsmac-remove-extra-regulation-restriction.patch
new file mode 100644
index 0000000000..dd1393ae5d
--- /dev/null
+++ b/package/mac80211/patches/873-brcmsmac-remove-extra-regulation-restriction.patch
@@ -0,0 +1,31 @@
+--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
++++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+@@ -59,23 +59,16 @@
+ 
+ #define BRCM_2GHZ_2412_2462	REG_RULE(2412-10, 2462+10, 40, 0, 19, 0)
+ #define BRCM_2GHZ_2467_2472	REG_RULE(2467-10, 2472+10, 20, 0, 19, \
+-					 NL80211_RRF_PASSIVE_SCAN | \
+-					 NL80211_RRF_NO_IBSS)
++					 0)
+ 
+ #define BRCM_5GHZ_5180_5240	REG_RULE(5180-10, 5240+10, 40, 0, 21, \
+-					 NL80211_RRF_PASSIVE_SCAN | \
+-					 NL80211_RRF_NO_IBSS)
++					 0)
+ #define BRCM_5GHZ_5260_5320	REG_RULE(5260-10, 5320+10, 40, 0, 21, \
+-					 NL80211_RRF_PASSIVE_SCAN | \
+-					 NL80211_RRF_DFS | \
+-					 NL80211_RRF_NO_IBSS)
++					 0)
+ #define BRCM_5GHZ_5500_5700	REG_RULE(5500-10, 5700+10, 40, 0, 21, \
+-					 NL80211_RRF_PASSIVE_SCAN | \
+-					 NL80211_RRF_DFS | \
+-					 NL80211_RRF_NO_IBSS)
++					 0)
+ #define BRCM_5GHZ_5745_5825	REG_RULE(5745-10, 5825+10, 40, 0, 21, \
+-					 NL80211_RRF_PASSIVE_SCAN | \
+-					 NL80211_RRF_NO_IBSS)
++					 0)
+ 
+ static const struct ieee80211_regdomain brcms_regdom_x2 = {
+ 	.n_reg_rules = 6,
-- 
GitLab