* [PATCH 3/5] ath9k: Handle BSSID/AID for multiple interfaces
2011-04-04 17:26 [PATCH 1/5] ath9k: deny new interface addtion on IBSS mode Rajkumar Manoharan
2011-04-04 17:26 ` [PATCH 2/5] ath9k: Cleanup ath_vif struct Rajkumar Manoharan
@ 2011-04-04 17:26 ` Rajkumar Manoharan
2011-04-04 17:26 ` [PATCH 4/5] ath9k: configure beacons based on hw opmode Rajkumar Manoharan
2 siblings, 0 replies; 4+ messages in thread
From: Rajkumar Manoharan @ 2011-04-04 17:26 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Rajkumar Manoharan
As of now bssid/aid is overridden with recently changed vif's
bss config. This may cause improper beacon updation due to
bssid/aid mismatch. On station mode, select an associated
sta vif as primary vif and configure that vif's bss into hw.
Update the primary vif on interface change and bss info change.
Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 3 +-
drivers/net/wireless/ath/ath9k/main.c | 70 +++++++++++++++++++++++++++----
2 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index d637345..1ffe8d4 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -346,7 +346,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
struct ath_vif {
int av_bslot;
- bool is_bslot_active;
+ bool is_bslot_active, primary_sta_vif;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
struct ath_buf *av_bcbuf;
};
@@ -548,6 +548,7 @@ struct ath_ant_comb {
#define SC_OP_BT_SCAN BIT(13)
#define SC_OP_ANI_RUN BIT(14)
#define SC_OP_ENABLE_APM BIT(15)
+#define SC_OP_PRIM_STA_VIF BIT(16)
/* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 729f3db..e5a9f69 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -841,10 +841,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
"Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, common->curbssid);
- /* New association, store aid */
- common->curaid = bss_conf->aid;
- ath9k_hw_write_associd(ah);
-
/*
* Request a re-configuration of Beacon related timers
* on the receipt of the first Beacon frame (i.e.,
@@ -863,7 +859,6 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
ath_start_ani(common);
} else {
ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
- common->curaid = 0;
/* Stop ANI */
sc->sc_flags &= ~SC_OP_ANI_RUN;
del_timer_sync(&common->ani.timer);
@@ -1890,6 +1885,66 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
return ret;
}
+static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct ath_softc *sc = data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ switch (sc->sc_ah->opmode) {
+ case NL80211_IFTYPE_ADHOC:
+ /* There can be only one vif available */
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc->sc_ah);
+ break;
+ case NL80211_IFTYPE_STATION:
+ /*
+ * Skip iteration if primary station vif's bss info
+ * was not changed
+ */
+ if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+ break;
+
+ if (bss_conf->assoc) {
+ sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+ avp->primary_sta_vif = true;
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc->sc_ah);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ /* Reconfigure bss info */
+ if (avp->primary_sta_vif && !bss_conf->assoc) {
+ sc->sc_flags &= ~SC_OP_PRIM_STA_VIF;
+ avp->primary_sta_vif = false;
+ memset(common->curbssid, 0, ETH_ALEN);
+ common->curaid = 0;
+ }
+
+ ieee80211_iterate_active_interfaces_atomic(
+ sc->hw, ath9k_bss_iter, sc);
+
+ /*
+ * None of station vifs are associated.
+ * Clear bssid & aid
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ !(sc->sc_flags & SC_OP_PRIM_STA_VIF))
+ ath9k_hw_write_associd(sc->sc_ah);
+}
static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -1907,10 +1962,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
if (changed & BSS_CHANGED_BSSID) {
- /* Set BSSID */
- memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
- common->curaid = 0;
- ath9k_hw_write_associd(ah);
+ ath9k_config_bss(sc, vif);
/* Set aggregation protection mode parameters */
sc->config.ath_aggr_prot = 0;
--
1.7.4.2
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 4/5] ath9k: configure beacons based on hw opmode
2011-04-04 17:26 [PATCH 1/5] ath9k: deny new interface addtion on IBSS mode Rajkumar Manoharan
2011-04-04 17:26 ` [PATCH 2/5] ath9k: Cleanup ath_vif struct Rajkumar Manoharan
2011-04-04 17:26 ` [PATCH 3/5] ath9k: Handle BSSID/AID for multiple interfaces Rajkumar Manoharan
@ 2011-04-04 17:26 ` Rajkumar Manoharan
2 siblings, 0 replies; 4+ messages in thread
From: Rajkumar Manoharan @ 2011-04-04 17:26 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Rajkumar Manoharan
Current ath9k code does not handle beacon timers on opmode
specific. One such example is that a STA beacon config overwrites
already configured AP vif's beacon timers during scan.
On multi station vif case, configure beacon timers beased
on primary vif selected. This also helps while moving back
to single STA vif from multi STA vifs, where the power save
is enabled and hw has to be reconfigured with proper
beacon and bssid/aid. Otherwise connection poll will be triggered
so frequently due to beacon loss.
Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 1 +
drivers/net/wireless/ath/ath9k/beacon.c | 101 +++++++++++++++++++++++--------
drivers/net/wireless/ath/ath9k/main.c | 84 ++++++++------------------
drivers/net/wireless/ath/ath9k/recv.c | 2 +-
4 files changed, 104 insertions(+), 84 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1ffe8d4..e6f8fa6 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -399,6 +399,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
int ath_beaconq_config(struct ath_softc *sc);
+void ath_set_beacon(struct ath_softc *sc);
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
/*******/
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index fec9255..801c3c0 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -671,22 +671,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 =
@@ -709,7 +750,16 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1;
- switch (iftype) {
+ 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);
break;
@@ -736,22 +786,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;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index e5a9f69..ba1c9a6 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -299,7 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
if (sc->sc_flags & SC_OP_BEACONS)
- ath_beacon_config(sc, NULL);
+ ath_set_beacon(sc);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
ath_start_ani(common);
@@ -828,43 +828,6 @@ chip_reset:
#undef SCHED_INTR
}
-static void ath9k_bss_assoc_info(struct ath_softc *sc,
- struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (bss_conf->assoc) {
- ath_dbg(common, ATH_DBG_CONFIG,
- "Bss Info ASSOC %d, bssid: %pM\n",
- bss_conf->aid, common->curbssid);
-
- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->ps_flags |= PS_BEACON_SYNC;
-
- /* Configure the beacon */
- ath_beacon_config(sc, vif);
-
- /* Reset rssi stats */
- sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
- sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
-
- sc->sc_flags |= SC_OP_ANI_RUN;
- ath_start_ani(common);
- } else {
- ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
- /* Stop ANI */
- sc->sc_flags &= ~SC_OP_ANI_RUN;
- del_timer_sync(&common->ani.timer);
- }
-}
-
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
@@ -894,7 +857,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
goto out;
}
if (sc->sc_flags & SC_OP_BEACONS)
- ath_beacon_config(sc, NULL); /* restart beacons */
+ ath_set_beacon(sc); /* restart beacons */
/* Re-Enable interrupts */
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -1001,7 +964,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
sc->config.txpowlimit, &sc->curtxpow);
if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
- ath_beacon_config(sc, NULL); /* restart beacons */
+ ath_set_beacon(sc); /* restart beacons */
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -1412,9 +1375,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
if ((iter_data.naps + iter_data.nadhocs) > 0) {
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
- } else {
- sc->sc_flags &= ~SC_OP_ANI_RUN;
- del_timer_sync(&common->ani.timer);
}
}
@@ -1898,6 +1858,9 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = bss_conf->aid;
ath9k_hw_write_associd(sc->sc_ah);
+ /* configure beacon */
+ if (bss_conf->enable_beacon)
+ ath_beacon_config(sc, vif);
break;
case NL80211_IFTYPE_STATION:
/*
@@ -1913,6 +1876,16 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
common->curaid = bss_conf->aid;
ath9k_hw_write_associd(sc->sc_ah);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
+ ath_beacon_config(sc, vif);
+ /* Reset rssi stats */
+ sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
+
+ sc->sc_flags |= SC_OP_ANI_RUN;
+ ath_start_ani(common);
}
break;
default:
@@ -1928,7 +1901,10 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
/* Reconfigure bss info */
if (avp->primary_sta_vif && !bss_conf->assoc) {
- sc->sc_flags &= ~SC_OP_PRIM_STA_VIF;
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Bss Info DISASSOC %d, bssid %pM\n",
+ common->curaid, common->curbssid);
+ sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
avp->primary_sta_vif = false;
memset(common->curbssid, 0, ETH_ALEN);
common->curaid = 0;
@@ -1942,8 +1918,12 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
* Clear bssid & aid
*/
if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
- !(sc->sc_flags & SC_OP_PRIM_STA_VIF))
+ !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
ath9k_hw_write_associd(sc->sc_ah);
+ /* Stop ANI */
+ sc->sc_flags &= ~SC_OP_ANI_RUN;
+ del_timer_sync(&common->ani.timer);
+ }
}
static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
@@ -1952,7 +1932,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
u32 changed)
{
struct ath_softc *sc = hw->priv;
- 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;
@@ -1969,9 +1948,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
common->curbssid, common->curaid);
-
- /* need to reconfigure the beacon */
- sc->sc_flags &= ~SC_OP_BEACONS ;
}
/* Enable transmission of beacons (AP, IBSS, MESH) */
@@ -2012,7 +1988,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BEACON_INT) {
- cur_conf->beacon_interval = bss_conf->beacon_int;
/*
* In case of AP mode, the HW TSF has to be reset
* when the beacon interval changes.
@@ -2024,9 +1999,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if (!error)
ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
- } else {
+ } else
ath_beacon_config(sc, vif);
- }
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -2048,12 +2022,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
}
- if (changed & BSS_CHANGED_ASSOC) {
- ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
- bss_conf->assoc);
- ath9k_bss_assoc_info(sc, hw, vif, bss_conf);
- }
-
mutex_unlock(&sc->mutex);
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a9c3f46..3842b75 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -574,7 +574,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, ATH_DBG_PS,
"Reconfigure Beacon timers based on timestamp from the AP\n");
- ath_beacon_config(sc, NULL);
+ ath_set_beacon(sc);
}
if (ath_beacon_dtim_pending_cab(skb)) {
--
1.7.4.2
^ permalink raw reply related [flat|nested] 4+ messages in thread