aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath9k
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-03-03 12:23:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-03-05 14:39:44 -0500
commit8ca21f0185a606c490867f7471196aa29639e638 (patch)
treed16405f88eb894c6805bbaae4c2a5fba81b2baef /drivers/net/wireless/ath9k
parent2c3db3d51ee1fcf84f5828788905a4c091b9ae27 (diff)
ath9k: Set BSSID mask based on configured interfaces
Instead of using a hardcoded BSSID mask (mask for own addresses), iterate through all active interfaces and determine the minimal mask that covers all local addresses. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k')
-rw-r--r--drivers/net/wireless/ath9k/Makefile1
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h14
-rw-r--r--drivers/net/wireless/ath9k/main.c15
-rw-r--r--drivers/net/wireless/ath9k/virtual.c88
4 files changed, 103 insertions, 15 deletions
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
index 00629587b790..1a4d4eab6fe8 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -9,6 +9,7 @@ ath9k-y += hw.o \
9 main.o \ 9 main.o \
10 recv.o \ 10 recv.o \
11 xmit.o \ 11 xmit.o \
12 virtual.o \
12 rc.o 13 rc.o
13 14
14ath9k-$(CONFIG_PCI) += pci.o 15ath9k-$(CONFIG_PCI) += pci.o
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 09b2b008feba..1598bac9242d 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -387,17 +387,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
387/* VIFs */ 387/* VIFs */
388/********/ 388/********/
389 389
390/*
391 * Define the scheme that we select MAC address for multiple
392 * BSS on the same radio. The very first VIF will just use the MAC
393 * address from the EEPROM. For the next 3 VIFs, we set the
394 * U/L bit (bit 1) in MAC address, and use the next two bits as the
395 * index of the VIF.
396 */
397
398#define ATH_SET_VIF_BSSID_MASK(bssid_mask) \
399 ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
400
401struct ath_vif { 390struct ath_vif {
402 int av_bslot; 391 int av_bslot;
403 enum nl80211_iftype av_opmode; 392 enum nl80211_iftype av_opmode;
@@ -676,4 +665,7 @@ static inline void ath9k_ps_restore(struct ath_softc *sc)
676 sc->sc_ah->restore_mode); 665 sc->sc_ah->restore_mode);
677} 666}
678 667
668
669void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
670
679#endif /* ATH9K_H */ 671#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index e43cee7907b2..599218def799 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -1514,11 +1514,8 @@ static int ath_init(u16 devid, struct ath_softc *sc)
1514 ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); 1514 ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
1515 sc->rx.defant = ath9k_hw_getdefantenna(ah); 1515 sc->rx.defant = ath9k_hw_getdefantenna(ah);
1516 1516
1517 if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { 1517 if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
1518 memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN); 1518 memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
1519 ATH_SET_VIF_BSSID_MASK(sc->bssidmask);
1520 ath9k_hw_setbssidmask(sc);
1521 }
1522 1519
1523 sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ 1520 sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
1524 1521
@@ -2128,6 +2125,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
2128 2125
2129 mutex_lock(&sc->mutex); 2126 mutex_lock(&sc->mutex);
2130 2127
2128 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
2129 sc->nvifs > 0) {
2130 ret = -ENOBUFS;
2131 goto out;
2132 }
2133
2131 switch (conf->type) { 2134 switch (conf->type) {
2132 case NL80211_IFTYPE_STATION: 2135 case NL80211_IFTYPE_STATION:
2133 ic_opmode = NL80211_IFTYPE_STATION; 2136 ic_opmode = NL80211_IFTYPE_STATION;
@@ -2160,6 +2163,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
2160 avp->av_bslot = -1; 2163 avp->av_bslot = -1;
2161 2164
2162 sc->nvifs++; 2165 sc->nvifs++;
2166
2167 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
2168 ath9k_set_bssid_mask(hw);
2169
2163 if (sc->nvifs > 1) 2170 if (sc->nvifs > 1)
2164 goto out; /* skip global settings for secondary vif */ 2171 goto out; /* skip global settings for secondary vif */
2165 2172
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c
new file mode 100644
index 000000000000..52d5021f39f9
--- /dev/null
+++ b/drivers/net/wireless/ath9k/virtual.c
@@ -0,0 +1,88 @@
1/*
2 * Copyright (c) 2008-2009 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "ath9k.h"
18
19struct ath9k_vif_iter_data {
20 int count;
21 u8 *addr;
22};
23
24static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
25{
26 struct ath9k_vif_iter_data *iter_data = data;
27 u8 *nbuf;
28
29 nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
30 GFP_ATOMIC);
31 if (nbuf == NULL)
32 return;
33
34 memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
35 iter_data->addr = nbuf;
36 iter_data->count++;
37}
38
39void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
40{
41 struct ath_softc *sc = hw->priv;
42 struct ath9k_vif_iter_data iter_data;
43 int i, j;
44 u8 mask[ETH_ALEN];
45
46 /*
47 * Add primary MAC address even if it is not in active use since it
48 * will be configured to the hardware as the starting point and the
49 * BSSID mask will need to be changed if another address is active.
50 */
51 iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
52 if (iter_data.addr) {
53 memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN);
54 iter_data.count = 1;
55 } else
56 iter_data.count = 0;
57
58 /* Get list of all active MAC addresses */
59 ieee80211_iterate_active_interfaces_atomic(hw, ath9k_vif_iter,
60 &iter_data);
61
62 /* Generate an address mask to cover all active addresses */
63 memset(mask, 0, ETH_ALEN);
64 for (i = 0; i < iter_data.count; i++) {
65 u8 *a1 = iter_data.addr + i * ETH_ALEN;
66 for (j = i + 1; j < iter_data.count; j++) {
67 u8 *a2 = iter_data.addr + j * ETH_ALEN;
68 mask[0] |= a1[0] ^ a2[0];
69 mask[1] |= a1[1] ^ a2[1];
70 mask[2] |= a1[2] ^ a2[2];
71 mask[3] |= a1[3] ^ a2[3];
72 mask[4] |= a1[4] ^ a2[4];
73 mask[5] |= a1[5] ^ a2[5];
74 }
75 }
76
77 kfree(iter_data.addr);
78
79 /* Invert the mask and configure hardware */
80 sc->bssidmask[0] = ~mask[0];
81 sc->bssidmask[1] = ~mask[1];
82 sc->bssidmask[2] = ~mask[2];
83 sc->bssidmask[3] = ~mask[3];
84 sc->bssidmask[4] = ~mask[4];
85 sc->bssidmask[5] = ~mask[5];
86
87 ath9k_hw_setbssidmask(sc);
88}