diff options
author | Jouni Malinen <jouni.malinen@atheros.com> | 2009-03-03 12:23:29 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:45 -0500 |
commit | c52f33d05e5f8d59f02722fbc308f5f391575ca5 (patch) | |
tree | 19c6d56f3594e8b43d725b5d919bb775921fde38 /drivers/net/wireless/ath9k/virtual.c | |
parent | bce048d77dff3dcfd75d54dc38580c81baa95853 (diff) |
ath9k: Add support for multiple secondary virtual wiphys
The new struct ath_softc::sec_wiphy array is used to store information
about virtual wiphys and select which wiphy is used in calls to
mac80211. Each virtual wiphy will be assigned a different MAC address
based on the virtual wiphy index.
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/virtual.c')
-rw-r--r-- | drivers/net/wireless/ath9k/virtual.c | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c index a91f2f1c911b..67bcb9343ca6 100644 --- a/drivers/net/wireless/ath9k/virtual.c +++ b/drivers/net/wireless/ath9k/virtual.c | |||
@@ -57,8 +57,16 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
57 | iter_data.count = 0; | 57 | iter_data.count = 0; |
58 | 58 | ||
59 | /* Get list of all active MAC addresses */ | 59 | /* Get list of all active MAC addresses */ |
60 | ieee80211_iterate_active_interfaces_atomic(hw, ath9k_vif_iter, | 60 | spin_lock_bh(&sc->wiphy_lock); |
61 | ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter, | ||
61 | &iter_data); | 62 | &iter_data); |
63 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
64 | if (sc->sec_wiphy[i] == NULL) | ||
65 | continue; | ||
66 | ieee80211_iterate_active_interfaces_atomic( | ||
67 | sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data); | ||
68 | } | ||
69 | spin_unlock_bh(&sc->wiphy_lock); | ||
62 | 70 | ||
63 | /* Generate an address mask to cover all active addresses */ | 71 | /* Generate an address mask to cover all active addresses */ |
64 | memset(mask, 0, ETH_ALEN); | 72 | memset(mask, 0, ETH_ALEN); |
@@ -87,3 +95,83 @@ void ath9k_set_bssid_mask(struct ieee80211_hw *hw) | |||
87 | 95 | ||
88 | ath9k_hw_setbssidmask(sc); | 96 | ath9k_hw_setbssidmask(sc); |
89 | } | 97 | } |
98 | |||
99 | int ath9k_wiphy_add(struct ath_softc *sc) | ||
100 | { | ||
101 | int i, error; | ||
102 | struct ath_wiphy *aphy; | ||
103 | struct ieee80211_hw *hw; | ||
104 | u8 addr[ETH_ALEN]; | ||
105 | |||
106 | hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops); | ||
107 | if (hw == NULL) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | spin_lock_bh(&sc->wiphy_lock); | ||
111 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
112 | if (sc->sec_wiphy[i] == NULL) | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | if (i == sc->num_sec_wiphy) { | ||
117 | /* No empty slot available; increase array length */ | ||
118 | struct ath_wiphy **n; | ||
119 | n = krealloc(sc->sec_wiphy, | ||
120 | (sc->num_sec_wiphy + 1) * | ||
121 | sizeof(struct ath_wiphy *), | ||
122 | GFP_ATOMIC); | ||
123 | if (n == NULL) { | ||
124 | spin_unlock_bh(&sc->wiphy_lock); | ||
125 | ieee80211_free_hw(hw); | ||
126 | return -ENOMEM; | ||
127 | } | ||
128 | n[i] = NULL; | ||
129 | sc->sec_wiphy = n; | ||
130 | sc->num_sec_wiphy++; | ||
131 | } | ||
132 | |||
133 | SET_IEEE80211_DEV(hw, sc->dev); | ||
134 | |||
135 | aphy = hw->priv; | ||
136 | aphy->sc = sc; | ||
137 | aphy->hw = hw; | ||
138 | sc->sec_wiphy[i] = aphy; | ||
139 | spin_unlock_bh(&sc->wiphy_lock); | ||
140 | |||
141 | memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN); | ||
142 | addr[0] |= 0x02; /* Locally managed address */ | ||
143 | /* | ||
144 | * XOR virtual wiphy index into the least significant bits to generate | ||
145 | * a different MAC address for each virtual wiphy. | ||
146 | */ | ||
147 | addr[5] ^= i & 0xff; | ||
148 | addr[4] ^= (i & 0xff00) >> 8; | ||
149 | addr[3] ^= (i & 0xff0000) >> 16; | ||
150 | |||
151 | SET_IEEE80211_PERM_ADDR(hw, addr); | ||
152 | |||
153 | ath_set_hw_capab(sc, hw); | ||
154 | |||
155 | error = ieee80211_register_hw(hw); | ||
156 | |||
157 | return error; | ||
158 | } | ||
159 | |||
160 | int ath9k_wiphy_del(struct ath_wiphy *aphy) | ||
161 | { | ||
162 | struct ath_softc *sc = aphy->sc; | ||
163 | int i; | ||
164 | |||
165 | spin_lock_bh(&sc->wiphy_lock); | ||
166 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
167 | if (aphy == sc->sec_wiphy[i]) { | ||
168 | sc->sec_wiphy[i] = NULL; | ||
169 | spin_unlock_bh(&sc->wiphy_lock); | ||
170 | ieee80211_unregister_hw(aphy->hw); | ||
171 | ieee80211_free_hw(aphy->hw); | ||
172 | return 0; | ||
173 | } | ||
174 | } | ||
175 | spin_unlock_bh(&sc->wiphy_lock); | ||
176 | return -ENOENT; | ||
177 | } | ||