mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 21:52:04 +00:00
ath9k: fix BSSID mask calculation
At the time the .add_interface driver op is called, the interface has not been marked as running yet, so ieee80211_iterate_active_interfaces will not pass it to the iterator function. Because of this, the calculated BSSID mask is wrong, which breaks multi-BSS operation. Additionally, the current way of comparing all addresses against each other is pointless, as the hardware only uses the hardware MAC address and the BSSID mask for matching the destination address, so all the address array reallocation is completely unnecessary. This patch simplifies the logic by setting the initial mask bytes to 0xff and removing all bits in the iterator call that don't match the hardware MAC address. It also calls the iterator for the vif that was passed to add_interface() Signed-off-by: Felix Fietkau <nbd@openwrt.org> Tested-by: Ben Greear <greearb@candelatech.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
4a0e8ecca4
commit
31a01645c0
@ -719,7 +719,7 @@ static inline void ath_ahb_exit(void) {};
|
||||
void ath9k_ps_wakeup(struct ath_softc *sc);
|
||||
void ath9k_ps_restore(struct ath_softc *sc);
|
||||
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
|
||||
void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||
int ath9k_wiphy_add(struct ath_softc *sc);
|
||||
int ath9k_wiphy_del(struct ath_wiphy *aphy);
|
||||
void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
|
@ -1415,7 +1415,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||
sc->nvifs++;
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
|
||||
ath9k_set_bssid_mask(hw);
|
||||
ath9k_set_bssid_mask(hw, vif);
|
||||
|
||||
if (sc->nvifs > 1)
|
||||
goto out; /* skip global settings for secondary vif */
|
||||
|
@ -19,45 +19,36 @@
|
||||
#include "ath9k.h"
|
||||
|
||||
struct ath9k_vif_iter_data {
|
||||
int count;
|
||||
u8 *addr;
|
||||
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;
|
||||
u8 *nbuf;
|
||||
int i;
|
||||
|
||||
nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
|
||||
GFP_ATOMIC);
|
||||
if (nbuf == NULL)
|
||||
return;
|
||||
|
||||
memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
|
||||
iter_data->addr = nbuf;
|
||||
iter_data->count++;
|
||||
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)
|
||||
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, j;
|
||||
u8 mask[ETH_ALEN];
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Add primary MAC address even if it is not in active use since it
|
||||
* will be configured to the hardware as the starting point and the
|
||||
* BSSID mask will need to be changed if another address is active.
|
||||
* Use the hardware MAC address as reference, the hardware uses it
|
||||
* together with the BSSID mask when matching addresses.
|
||||
*/
|
||||
iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
|
||||
if (iter_data.addr) {
|
||||
memcpy(iter_data.addr, common->macaddr, ETH_ALEN);
|
||||
iter_data.count = 1;
|
||||
} else
|
||||
iter_data.count = 0;
|
||||
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);
|
||||
@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
|
||||
}
|
||||
spin_unlock_bh(&sc->wiphy_lock);
|
||||
|
||||
/* Generate an address mask to cover all active addresses */
|
||||
memset(mask, 0, ETH_ALEN);
|
||||
for (i = 0; i < iter_data.count; i++) {
|
||||
u8 *a1 = iter_data.addr + i * ETH_ALEN;
|
||||
for (j = i + 1; j < iter_data.count; j++) {
|
||||
u8 *a2 = iter_data.addr + j * ETH_ALEN;
|
||||
mask[0] |= a1[0] ^ a2[0];
|
||||
mask[1] |= a1[1] ^ a2[1];
|
||||
mask[2] |= a1[2] ^ a2[2];
|
||||
mask[3] |= a1[3] ^ a2[3];
|
||||
mask[4] |= a1[4] ^ a2[4];
|
||||
mask[5] |= a1[5] ^ a2[5];
|
||||
}
|
||||
}
|
||||
|
||||
kfree(iter_data.addr);
|
||||
|
||||
/* Invert the mask and configure hardware */
|
||||
common->bssidmask[0] = ~mask[0];
|
||||
common->bssidmask[1] = ~mask[1];
|
||||
common->bssidmask[2] = ~mask[2];
|
||||
common->bssidmask[3] = ~mask[3];
|
||||
common->bssidmask[4] = ~mask[4];
|
||||
common->bssidmask[5] = ~mask[5];
|
||||
|
||||
memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
|
||||
ath_hw_setbssidmask(common);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user