--- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -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; - - nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN, - GFP_ATOMIC); - if (nbuf == NULL) - return; + int i; - 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 ieee802 } 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); } --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -666,7 +666,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); --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1416,7 +1416,7 @@ static int ath9k_add_interface(struct ie 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 */