From 4c0c6cd52075880e4b8a8b9510d0ea048c707ded Mon Sep 17 00:00:00 2001 From: nbd Date: Tue, 14 Sep 2010 16:26:46 +0000 Subject: [PATCH] ath9k: fix multi-bss operation (fixes #7914) git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23059 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../patches/550-ath9k_bssid_mask_fix.patch | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 package/mac80211/patches/550-ath9k_bssid_mask_fix.patch diff --git a/package/mac80211/patches/550-ath9k_bssid_mask_fix.patch b/package/mac80211/patches/550-ath9k_bssid_mask_fix.patch new file mode 100644 index 000000000..f44887043 --- /dev/null +++ b/package/mac80211/patches/550-ath9k_bssid_mask_fix.patch @@ -0,0 +1,117 @@ +--- 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 */ -- 2.20.1