diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-03 12:23:27 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:44 -0500 |
commit | 8ca21f0185a606c490867f7471196aa29639e638 (patch) | |
tree | d16405f88eb894c6805bbaae4c2a5fba81b2baef /drivers/net/wireless/ath9k | |
parent | 2c3db3d51ee1fcf84f5828788905a4c091b9ae27 (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/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/ath9k.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/virtual.c | 88 |
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 | ||
14 | ath9k-$(CONFIG_PCI) += pci.o | 15 | ath9k-$(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 | |||
401 | struct ath_vif { | 390 | struct 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 | |||
669 | void 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 | |||
19 | struct ath9k_vif_iter_data { | ||
20 | int count; | ||
21 | u8 *addr; | ||
22 | }; | ||
23 | |||
24 | static 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 | |||
39 | void 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 | } | ||