summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/beacon.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/beacon.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c99
1 files changed, 75 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index dfd1b98a086b..eccb0ec87adb 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -663,22 +663,63 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
ath9k_hw_set_interrupts(ah, ah->imask);
}
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+static bool ath9k_allow_beacon_config(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
{
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- enum nl80211_iftype iftype;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
- /* Setup the beacon configuration parameters */
- if (vif) {
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- iftype = vif->type;
- cur_conf->beacon_interval = bss_conf->beacon_int;
- cur_conf->dtim_period = bss_conf->dtim_period;
- } else {
- iftype = sc->sc_ah->opmode;
+ /*
+ * Can not have different beacon interval on multiple
+ * AP interface case
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (sc->nbcnvifs > 1) &&
+ (vif->type == NL80211_IFTYPE_AP) &&
+ (cur_conf->beacon_interval != bss_conf->beacon_int)) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Changing beacon interval of multiple \
+ AP interfaces !\n");
+ return false;
+ }
+ /*
+ * Can not configure station vif's beacon config
+ * while on AP opmode
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (vif->type != NL80211_IFTYPE_AP)) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "STA vif's beacon not allowed on AP mode\n");
+ return false;
+ }
+ /*
+ * Do not allow beacon config if HW was already configured
+ * with another STA vif
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ (vif->type == NL80211_IFTYPE_STATION) &&
+ (sc->sc_flags & SC_OP_BEACONS) &&
+ !avp->primary_sta_vif) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Beacon already configured for a station interface\n");
+ return false;
}
+ return true;
+}
+
+void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ if (!ath9k_allow_beacon_config(sc, vif))
+ return;
+
+ /* Setup the beacon configuration parameters */
+ cur_conf->beacon_interval = bss_conf->beacon_int;
+ cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
@@ -701,6 +742,15 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1;
+ ath_set_beacon(sc);
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+}
+
+void ath_set_beacon(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+
switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
ath_beacon_config_ap(sc, cur_conf);
@@ -728,22 +778,23 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
int slot;
bool found = false;
- ath9k_ps_wakeup(sc);
- if (status) {
- for (slot = 0; slot < ATH_BCBUF; slot++) {
- if (sc->beacon.bslot[slot]) {
- avp = (void *)sc->beacon.bslot[slot]->drv_priv;
- if (avp->is_bslot_active) {
- found = true;
- break;
- }
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (sc->beacon.bslot[slot]) {
+ avp = (void *)sc->beacon.bslot[slot]->drv_priv;
+ if (avp->is_bslot_active) {
+ found = true;
+ break;
}
}
- if (found) {
- /* Re-enable beaconing */
- ah->imask |= ATH9K_INT_SWBA;
- ath9k_hw_set_interrupts(ah, ah->imask);
- }
+ }
+ if (!found)
+ return;
+
+ ath9k_ps_wakeup(sc);
+ if (status) {
+ /* Re-enable beaconing */
+ ah->imask |= ATH9K_INT_SWBA;
+ ath9k_hw_set_interrupts(ah, ah->imask);
} else {
/* Disable SWBA interrupt */
ah->imask &= ~ATH9K_INT_SWBA;