aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-09-14 12:37:19 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-09-14 16:14:26 -0400
commit31a01645c0c7b46d7f74777cd2a66ddb2a22bbd9 (patch)
treefd31575a505b3affea5b4fe7ae0bd40f2d70419a /drivers
parent4a0e8ecca4eeed38d4b3b7a317a3aaab4dd3cacd (diff)
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c63
3 files changed, 17 insertions, 50 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5fe570bb5c4c..c8ff417f6c10 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -719,7 +719,7 @@ static inline void ath_ahb_exit(void) {};
719void ath9k_ps_wakeup(struct ath_softc *sc); 719void ath9k_ps_wakeup(struct ath_softc *sc);
720void ath9k_ps_restore(struct ath_softc *sc); 720void ath9k_ps_restore(struct ath_softc *sc);
721 721
722void ath9k_set_bssid_mask(struct ieee80211_hw *hw); 722void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
723int ath9k_wiphy_add(struct ath_softc *sc); 723int ath9k_wiphy_add(struct ath_softc *sc);
724int ath9k_wiphy_del(struct ath_wiphy *aphy); 724int ath9k_wiphy_del(struct ath_wiphy *aphy);
725void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb); 725void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1165f909ef04..d3f96e4520f1 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1415,7 +1415,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
1415 sc->nvifs++; 1415 sc->nvifs++;
1416 1416
1417 if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) 1417 if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
1418 ath9k_set_bssid_mask(hw); 1418 ath9k_set_bssid_mask(hw, vif);
1419 1419
1420 if (sc->nvifs > 1) 1420 if (sc->nvifs > 1)
1421 goto out; /* skip global settings for secondary vif */ 1421 goto out; /* skip global settings for secondary vif */
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index fd20241f57d8..ec7cf5ee56bc 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -19,45 +19,36 @@
19#include "ath9k.h" 19#include "ath9k.h"
20 20
21struct ath9k_vif_iter_data { 21struct ath9k_vif_iter_data {
22 int count; 22 const u8 *hw_macaddr;
23 u8 *addr; 23 u8 mask[ETH_ALEN];
24}; 24};
25 25
26static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 26static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
27{ 27{
28 struct ath9k_vif_iter_data *iter_data = data; 28 struct ath9k_vif_iter_data *iter_data = data;
29 u8 *nbuf; 29 int i;
30
31 nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
32 GFP_ATOMIC);
33 if (nbuf == NULL)
34 return;
35 30
36 memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN); 31 for (i = 0; i < ETH_ALEN; i++)
37 iter_data->addr = nbuf; 32 iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
38 iter_data->count++;
39} 33}
40 34
41void ath9k_set_bssid_mask(struct ieee80211_hw *hw) 35void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
42{ 36{
43 struct ath_wiphy *aphy = hw->priv; 37 struct ath_wiphy *aphy = hw->priv;
44 struct ath_softc *sc = aphy->sc; 38 struct ath_softc *sc = aphy->sc;
45 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 39 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
46 struct ath9k_vif_iter_data iter_data; 40 struct ath9k_vif_iter_data iter_data;
47 int i, j; 41 int i;
48 u8 mask[ETH_ALEN];
49 42
50 /* 43 /*
51 * Add primary MAC address even if it is not in active use since it 44 * Use the hardware MAC address as reference, the hardware uses it
52 * will be configured to the hardware as the starting point and the 45 * together with the BSSID mask when matching addresses.
53 * BSSID mask will need to be changed if another address is active.
54 */ 46 */
55 iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC); 47 iter_data.hw_macaddr = common->macaddr;
56 if (iter_data.addr) { 48 memset(&iter_data.mask, 0xff, ETH_ALEN);
57 memcpy(iter_data.addr, common->macaddr, ETH_ALEN); 49
58 iter_data.count = 1; 50 if (vif)
59 } else 51 ath9k_vif_iter(&iter_data, vif->addr, vif);
60 iter_data.count = 0;
61 52
62 /* Get list of all active MAC addresses */ 53 /* Get list of all active MAC addresses */
63 spin_lock_bh(&sc->wiphy_lock); 54 spin_lock_bh(&sc->wiphy_lock);
@@ -71,31 +62,7 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
71 } 62 }
72 spin_unlock_bh(&sc->wiphy_lock); 63 spin_unlock_bh(&sc->wiphy_lock);
73 64
74 /* Generate an address mask to cover all active addresses */ 65 memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
75 memset(mask, 0, ETH_ALEN);
76 for (i = 0; i < iter_data.count; i++) {
77 u8 *a1 = iter_data.addr + i * ETH_ALEN;
78 for (j = i + 1; j < iter_data.count; j++) {
79 u8 *a2 = iter_data.addr + j * ETH_ALEN;
80 mask[0] |= a1[0] ^ a2[0];
81 mask[1] |= a1[1] ^ a2[1];
82 mask[2] |= a1[2] ^ a2[2];
83 mask[3] |= a1[3] ^ a2[3];
84 mask[4] |= a1[4] ^ a2[4];
85 mask[5] |= a1[5] ^ a2[5];
86 }
87 }
88
89 kfree(iter_data.addr);
90
91 /* Invert the mask and configure hardware */
92 common->bssidmask[0] = ~mask[0];
93 common->bssidmask[1] = ~mask[1];
94 common->bssidmask[2] = ~mask[2];
95 common->bssidmask[3] = ~mask[3];
96 common->bssidmask[4] = ~mask[4];
97 common->bssidmask[5] = ~mask[5];
98
99 ath_hw_setbssidmask(common); 66 ath_hw_setbssidmask(common);
100} 67}
101 68