diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/common.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common.c | 299 |
1 files changed, 27 insertions, 272 deletions
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index c86f7d3593ab..fa6bd2d189e5 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2009 Atheros Communications Inc. | 2 | * Copyright (c) 2009-2011 Atheros Communications Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 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 | 5 | * purpose with or without fee is hereby granted, provided that the above |
@@ -46,12 +46,17 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) | |||
46 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 46 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
47 | 47 | ||
48 | if (tx_info->control.hw_key) { | 48 | if (tx_info->control.hw_key) { |
49 | if (tx_info->control.hw_key->alg == ALG_WEP) | 49 | switch (tx_info->control.hw_key->cipher) { |
50 | case WLAN_CIPHER_SUITE_WEP40: | ||
51 | case WLAN_CIPHER_SUITE_WEP104: | ||
50 | return ATH9K_KEY_TYPE_WEP; | 52 | return ATH9K_KEY_TYPE_WEP; |
51 | else if (tx_info->control.hw_key->alg == ALG_TKIP) | 53 | case WLAN_CIPHER_SUITE_TKIP: |
52 | return ATH9K_KEY_TYPE_TKIP; | 54 | return ATH9K_KEY_TYPE_TKIP; |
53 | else if (tx_info->control.hw_key->alg == ALG_CCMP) | 55 | case WLAN_CIPHER_SUITE_CCMP: |
54 | return ATH9K_KEY_TYPE_AES; | 56 | return ATH9K_KEY_TYPE_AES; |
57 | default: | ||
58 | break; | ||
59 | } | ||
55 | } | 60 | } |
56 | 61 | ||
57 | return ATH9K_KEY_TYPE_CLEAR; | 62 | return ATH9K_KEY_TYPE_CLEAR; |
@@ -102,26 +107,23 @@ static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, | |||
102 | /* | 107 | /* |
103 | * Update internal channel flags. | 108 | * Update internal channel flags. |
104 | */ | 109 | */ |
105 | void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, | 110 | void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, |
106 | struct ath9k_channel *ichan) | 111 | struct ieee80211_channel *chan, |
112 | enum nl80211_channel_type channel_type) | ||
107 | { | 113 | { |
108 | struct ieee80211_channel *chan = hw->conf.channel; | ||
109 | struct ieee80211_conf *conf = &hw->conf; | ||
110 | |||
111 | ichan->channel = chan->center_freq; | 114 | ichan->channel = chan->center_freq; |
112 | ichan->chan = chan; | 115 | ichan->chan = chan; |
113 | 116 | ||
114 | if (chan->band == IEEE80211_BAND_2GHZ) { | 117 | if (chan->band == IEEE80211_BAND_2GHZ) { |
115 | ichan->chanmode = CHANNEL_G; | 118 | ichan->chanmode = CHANNEL_G; |
116 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; | 119 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM; |
117 | } else { | 120 | } else { |
118 | ichan->chanmode = CHANNEL_A; | 121 | ichan->chanmode = CHANNEL_A; |
119 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; | 122 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; |
120 | } | 123 | } |
121 | 124 | ||
122 | if (conf_is_ht(conf)) | 125 | if (channel_type != NL80211_CHAN_NO_HT) |
123 | ichan->chanmode = ath9k_get_extchanmode(chan, | 126 | ichan->chanmode = ath9k_get_extchanmode(chan, channel_type); |
124 | conf->channel_type); | ||
125 | } | 127 | } |
126 | EXPORT_SYMBOL(ath9k_cmn_update_ichannel); | 128 | EXPORT_SYMBOL(ath9k_cmn_update_ichannel); |
127 | 129 | ||
@@ -137,270 +139,12 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, | |||
137 | 139 | ||
138 | chan_idx = curchan->hw_value; | 140 | chan_idx = curchan->hw_value; |
139 | channel = &ah->channels[chan_idx]; | 141 | channel = &ah->channels[chan_idx]; |
140 | ath9k_cmn_update_ichannel(hw, channel); | 142 | ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type); |
141 | 143 | ||
142 | return channel; | 144 | return channel; |
143 | } | 145 | } |
144 | EXPORT_SYMBOL(ath9k_cmn_get_curchannel); | 146 | EXPORT_SYMBOL(ath9k_cmn_get_curchannel); |
145 | 147 | ||
146 | static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, | ||
147 | struct ath9k_keyval *hk, const u8 *addr, | ||
148 | bool authenticator) | ||
149 | { | ||
150 | struct ath_hw *ah = common->ah; | ||
151 | const u8 *key_rxmic; | ||
152 | const u8 *key_txmic; | ||
153 | |||
154 | key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | ||
155 | key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | ||
156 | |||
157 | if (addr == NULL) { | ||
158 | /* | ||
159 | * Group key installation - only two key cache entries are used | ||
160 | * regardless of splitmic capability since group key is only | ||
161 | * used either for TX or RX. | ||
162 | */ | ||
163 | if (authenticator) { | ||
164 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
165 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); | ||
166 | } else { | ||
167 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
168 | memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); | ||
169 | } | ||
170 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
171 | } | ||
172 | if (!common->splitmic) { | ||
173 | /* TX and RX keys share the same key cache entry. */ | ||
174 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
175 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); | ||
176 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
177 | } | ||
178 | |||
179 | /* Separate key cache entries for TX and RX */ | ||
180 | |||
181 | /* TX key goes at first index, RX key at +32. */ | ||
182 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
183 | if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { | ||
184 | /* TX MIC entry failed. No need to proceed further */ | ||
185 | ath_print(common, ATH_DBG_FATAL, | ||
186 | "Setting TX MIC Key Failed\n"); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
191 | /* XXX delete tx key on failure? */ | ||
192 | return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); | ||
193 | } | ||
194 | |||
195 | static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) | ||
196 | { | ||
197 | int i; | ||
198 | |||
199 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
200 | if (test_bit(i, common->keymap) || | ||
201 | test_bit(i + 64, common->keymap)) | ||
202 | continue; /* At least one part of TKIP key allocated */ | ||
203 | if (common->splitmic && | ||
204 | (test_bit(i + 32, common->keymap) || | ||
205 | test_bit(i + 64 + 32, common->keymap))) | ||
206 | continue; /* At least one part of TKIP key allocated */ | ||
207 | |||
208 | /* Found a free slot for a TKIP key */ | ||
209 | return i; | ||
210 | } | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | static int ath_reserve_key_cache_slot(struct ath_common *common, | ||
215 | enum ieee80211_key_alg alg) | ||
216 | { | ||
217 | int i; | ||
218 | |||
219 | if (alg == ALG_TKIP) | ||
220 | return ath_reserve_key_cache_slot_tkip(common); | ||
221 | |||
222 | /* First, try to find slots that would not be available for TKIP. */ | ||
223 | if (common->splitmic) { | ||
224 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { | ||
225 | if (!test_bit(i, common->keymap) && | ||
226 | (test_bit(i + 32, common->keymap) || | ||
227 | test_bit(i + 64, common->keymap) || | ||
228 | test_bit(i + 64 + 32, common->keymap))) | ||
229 | return i; | ||
230 | if (!test_bit(i + 32, common->keymap) && | ||
231 | (test_bit(i, common->keymap) || | ||
232 | test_bit(i + 64, common->keymap) || | ||
233 | test_bit(i + 64 + 32, common->keymap))) | ||
234 | return i + 32; | ||
235 | if (!test_bit(i + 64, common->keymap) && | ||
236 | (test_bit(i , common->keymap) || | ||
237 | test_bit(i + 32, common->keymap) || | ||
238 | test_bit(i + 64 + 32, common->keymap))) | ||
239 | return i + 64; | ||
240 | if (!test_bit(i + 64 + 32, common->keymap) && | ||
241 | (test_bit(i, common->keymap) || | ||
242 | test_bit(i + 32, common->keymap) || | ||
243 | test_bit(i + 64, common->keymap))) | ||
244 | return i + 64 + 32; | ||
245 | } | ||
246 | } else { | ||
247 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
248 | if (!test_bit(i, common->keymap) && | ||
249 | test_bit(i + 64, common->keymap)) | ||
250 | return i; | ||
251 | if (test_bit(i, common->keymap) && | ||
252 | !test_bit(i + 64, common->keymap)) | ||
253 | return i + 64; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* No partially used TKIP slots, pick any available slot */ | ||
258 | for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { | ||
259 | /* Do not allow slots that could be needed for TKIP group keys | ||
260 | * to be used. This limitation could be removed if we know that | ||
261 | * TKIP will not be used. */ | ||
262 | if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) | ||
263 | continue; | ||
264 | if (common->splitmic) { | ||
265 | if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) | ||
266 | continue; | ||
267 | if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) | ||
268 | continue; | ||
269 | } | ||
270 | |||
271 | if (!test_bit(i, common->keymap)) | ||
272 | return i; /* Found a free slot for a key */ | ||
273 | } | ||
274 | |||
275 | /* No free slot found */ | ||
276 | return -1; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * Configure encryption in the HW. | ||
281 | */ | ||
282 | int ath9k_cmn_key_config(struct ath_common *common, | ||
283 | struct ieee80211_vif *vif, | ||
284 | struct ieee80211_sta *sta, | ||
285 | struct ieee80211_key_conf *key) | ||
286 | { | ||
287 | struct ath_hw *ah = common->ah; | ||
288 | struct ath9k_keyval hk; | ||
289 | const u8 *mac = NULL; | ||
290 | u8 gmac[ETH_ALEN]; | ||
291 | int ret = 0; | ||
292 | int idx; | ||
293 | |||
294 | memset(&hk, 0, sizeof(hk)); | ||
295 | |||
296 | switch (key->alg) { | ||
297 | case ALG_WEP: | ||
298 | hk.kv_type = ATH9K_CIPHER_WEP; | ||
299 | break; | ||
300 | case ALG_TKIP: | ||
301 | hk.kv_type = ATH9K_CIPHER_TKIP; | ||
302 | break; | ||
303 | case ALG_CCMP: | ||
304 | hk.kv_type = ATH9K_CIPHER_AES_CCM; | ||
305 | break; | ||
306 | default: | ||
307 | return -EOPNOTSUPP; | ||
308 | } | ||
309 | |||
310 | hk.kv_len = key->keylen; | ||
311 | memcpy(hk.kv_val, key->key, key->keylen); | ||
312 | |||
313 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | ||
314 | switch (vif->type) { | ||
315 | case NL80211_IFTYPE_AP: | ||
316 | memcpy(gmac, vif->addr, ETH_ALEN); | ||
317 | gmac[0] |= 0x01; | ||
318 | mac = gmac; | ||
319 | idx = ath_reserve_key_cache_slot(common, key->alg); | ||
320 | break; | ||
321 | case NL80211_IFTYPE_ADHOC: | ||
322 | if (!sta) { | ||
323 | idx = key->keyidx; | ||
324 | break; | ||
325 | } | ||
326 | memcpy(gmac, sta->addr, ETH_ALEN); | ||
327 | gmac[0] |= 0x01; | ||
328 | mac = gmac; | ||
329 | idx = ath_reserve_key_cache_slot(common, key->alg); | ||
330 | break; | ||
331 | default: | ||
332 | idx = key->keyidx; | ||
333 | break; | ||
334 | } | ||
335 | } else if (key->keyidx) { | ||
336 | if (WARN_ON(!sta)) | ||
337 | return -EOPNOTSUPP; | ||
338 | mac = sta->addr; | ||
339 | |||
340 | if (vif->type != NL80211_IFTYPE_AP) { | ||
341 | /* Only keyidx 0 should be used with unicast key, but | ||
342 | * allow this for client mode for now. */ | ||
343 | idx = key->keyidx; | ||
344 | } else | ||
345 | return -EIO; | ||
346 | } else { | ||
347 | if (WARN_ON(!sta)) | ||
348 | return -EOPNOTSUPP; | ||
349 | mac = sta->addr; | ||
350 | |||
351 | idx = ath_reserve_key_cache_slot(common, key->alg); | ||
352 | } | ||
353 | |||
354 | if (idx < 0) | ||
355 | return -ENOSPC; /* no free key cache entries */ | ||
356 | |||
357 | if (key->alg == ALG_TKIP) | ||
358 | ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, | ||
359 | vif->type == NL80211_IFTYPE_AP); | ||
360 | else | ||
361 | ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); | ||
362 | |||
363 | if (!ret) | ||
364 | return -EIO; | ||
365 | |||
366 | set_bit(idx, common->keymap); | ||
367 | if (key->alg == ALG_TKIP) { | ||
368 | set_bit(idx + 64, common->keymap); | ||
369 | if (common->splitmic) { | ||
370 | set_bit(idx + 32, common->keymap); | ||
371 | set_bit(idx + 64 + 32, common->keymap); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | return idx; | ||
376 | } | ||
377 | EXPORT_SYMBOL(ath9k_cmn_key_config); | ||
378 | |||
379 | /* | ||
380 | * Delete Key. | ||
381 | */ | ||
382 | void ath9k_cmn_key_delete(struct ath_common *common, | ||
383 | struct ieee80211_key_conf *key) | ||
384 | { | ||
385 | struct ath_hw *ah = common->ah; | ||
386 | |||
387 | ath9k_hw_keyreset(ah, key->hw_key_idx); | ||
388 | if (key->hw_key_idx < IEEE80211_WEP_NKID) | ||
389 | return; | ||
390 | |||
391 | clear_bit(key->hw_key_idx, common->keymap); | ||
392 | if (key->alg != ALG_TKIP) | ||
393 | return; | ||
394 | |||
395 | clear_bit(key->hw_key_idx + 64, common->keymap); | ||
396 | if (common->splitmic) { | ||
397 | ath9k_hw_keyreset(ah, key->hw_key_idx + 32); | ||
398 | clear_bit(key->hw_key_idx + 32, common->keymap); | ||
399 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); | ||
400 | } | ||
401 | } | ||
402 | EXPORT_SYMBOL(ath9k_cmn_key_delete); | ||
403 | |||
404 | int ath9k_cmn_count_streams(unsigned int chainmask, int max) | 148 | int ath9k_cmn_count_streams(unsigned int chainmask, int max) |
405 | { | 149 | { |
406 | int streams = 0; | 150 | int streams = 0; |
@@ -414,6 +158,17 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max) | |||
414 | } | 158 | } |
415 | EXPORT_SYMBOL(ath9k_cmn_count_streams); | 159 | EXPORT_SYMBOL(ath9k_cmn_count_streams); |
416 | 160 | ||
161 | void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, | ||
162 | u16 new_txpow, u16 *txpower) | ||
163 | { | ||
164 | if (cur_txpow != new_txpow) { | ||
165 | ath9k_hw_set_txpowerlimit(ah, new_txpow, false); | ||
166 | /* read back in case value is clamped */ | ||
167 | *txpower = ath9k_hw_regulatory(ah)->power_limit; | ||
168 | } | ||
169 | } | ||
170 | EXPORT_SYMBOL(ath9k_cmn_update_txpow); | ||
171 | |||
417 | static int __init ath9k_cmn_init(void) | 172 | static int __init ath9k_cmn_init(void) |
418 | { | 173 | { |
419 | return 0; | 174 | return 0; |