Commit 4801416c authored by Ben Greear's avatar Ben Greear Committed by John W. Linville

ath9k: Fix up hardware mode and beacons with multiple vifs.

When using a mixture of AP and Station interfaces,
the hardware mode was using the type of the
last VIF registered.  Instead, we should keep track
of the number of different types of vifs and set the
mode accordingly.

In addtion, use the vif type instead of hardware opmode
when dealing with beacons.

Attempt to move some of the common setup code into smaller
methods so we can re-use it when changing vif mode as
well as adding/deleting vifs.
Signed-off-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f0b8220c
......@@ -560,6 +560,20 @@ struct ath_ant_comb {
struct ath_wiphy;
struct ath_rate_table;
struct ath9k_vif_iter_data {
const u8 *hw_macaddr; /* phy's hardware address, set
* before starting iteration for
* valid bssid mask.
*/
u8 mask[ETH_ALEN]; /* bssid mask */
int naps; /* number of AP vifs */
int nmeshes; /* number of mesh vifs */
int nstations; /* number of station vifs */
int nwds; /* number of nwd vifs */
int nadhocs; /* number of adhoc vifs */
int nothers; /* number of vifs not specified above. */
};
struct ath_softc {
struct ieee80211_hw *hw;
struct device *dev;
......@@ -599,10 +613,10 @@ struct ath_softc {
u32 sc_flags; /* SC_OP_* */
u16 ps_flags; /* PS_* */
u16 curtxpow;
u8 nbcnvifs;
u16 nvifs;
bool ps_enabled;
bool ps_idle;
short nbcnvifs;
short nvifs;
unsigned long ps_usecount;
struct ath_config config;
......@@ -683,6 +697,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
bool ath9k_uses_beacons(int type);
#ifdef CONFIG_PCI
int ath_pci_init(void);
......@@ -727,5 +742,9 @@ bool ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
void ath_start_rfkill_poll(struct ath_softc *sc);
extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ath9k_vif_iter_data *iter_data);
#endif /* ATH9K_H */
......@@ -244,9 +244,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
struct ath_buf, list);
list_del(&avp->av_bcbuf->list);
if (sc->sc_ah->opmode == NL80211_IFTYPE_AP ||
sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC ||
sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) {
if (ath9k_uses_beacons(vif->type)) {
int slot;
/*
* Assign the vif to a beacon xmit slot. As
......@@ -282,7 +280,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
/* NB: the beacon data buffer must be 32-bit aligned. */
skb = ieee80211_beacon_get(sc->hw, vif);
if (skb == NULL) {
ath_dbg(common, ATH_DBG_BEACON, "cannot get skb\n");
ath_err(common, "ieee80211_beacon_get failed\n");
return -ENOMEM;
}
......@@ -720,10 +718,10 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
iftype = sc->sc_ah->opmode;
}
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
/*
* It looks like mac80211 may end up using beacon interval of zero in
......
This diff is collapsed.
......@@ -588,8 +588,14 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
return;
mgmt = (struct ieee80211_mgmt *)skb->data;
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0)
if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) {
/* TODO: This doesn't work well if you have stations
* associated to two different APs because curbssid
* is just the last AP that any of the stations associated
* with.
*/
return; /* not from our current AP */
}
sc->ps_flags &= ~PS_WAIT_FOR_BEACON;
......@@ -984,8 +990,14 @@ static void ath9k_process_rssi(struct ath_common *common,
fc = hdr->frame_control;
if (!ieee80211_is_beacon(fc) ||
compare_ether_addr(hdr->addr3, common->curbssid))
compare_ether_addr(hdr->addr3, common->curbssid)) {
/* TODO: This doesn't work well if you have stations
* associated to two different APs because curbssid
* is just the last AP that any of the stations associated
* with.
*/
return;
}
if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr)
ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi);
......
......@@ -18,54 +18,6 @@
#include "ath9k.h"
struct ath9k_vif_iter_data {
const u8 *hw_macaddr;
u8 mask[ETH_ALEN];
};
static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct ath9k_vif_iter_data *iter_data = data;
int i;
for (i = 0; i < ETH_ALEN; i++)
iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
}
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_vif_iter_data iter_data;
int i;
/*
* Use the hardware MAC address as reference, the hardware uses it
* together with the BSSID mask when matching addresses.
*/
iter_data.hw_macaddr = common->macaddr;
memset(&iter_data.mask, 0xff, ETH_ALEN);
if (vif)
ath9k_vif_iter(&iter_data, vif->addr, vif);
/* Get list of all active MAC addresses */
spin_lock_bh(&sc->wiphy_lock);
ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
&iter_data);
for (i = 0; i < sc->num_sec_wiphy; i++) {
if (sc->sec_wiphy[i] == NULL)
continue;
ieee80211_iterate_active_interfaces_atomic(
sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data);
}
spin_unlock_bh(&sc->wiphy_lock);
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
ath_hw_setbssidmask(common);
}
int ath9k_wiphy_add(struct ath_softc *sc)
{
int i, error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment