diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/common.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common.c | 392 |
1 files changed, 375 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 4d775ae141db..7707341cd0d3 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -57,13 +57,19 @@ static bool ath9k_rx_accept(struct ath_common *common, | |||
57 | * rs_more indicates chained descriptors which can be used | 57 | * rs_more indicates chained descriptors which can be used |
58 | * to link buffers together for a sort of scatter-gather | 58 | * to link buffers together for a sort of scatter-gather |
59 | * operation. | 59 | * operation. |
60 | * | 60 | * reject the frame, we don't support scatter-gather yet and |
61 | * the frame is probably corrupt anyway | ||
62 | */ | ||
63 | if (rx_stats->rs_more) | ||
64 | return false; | ||
65 | |||
66 | /* | ||
61 | * The rx_stats->rs_status will not be set until the end of the | 67 | * The rx_stats->rs_status will not be set until the end of the |
62 | * chained descriptors so it can be ignored if rs_more is set. The | 68 | * chained descriptors so it can be ignored if rs_more is set. The |
63 | * rs_more will be false at the last element of the chained | 69 | * rs_more will be false at the last element of the chained |
64 | * descriptors. | 70 | * descriptors. |
65 | */ | 71 | */ |
66 | if (!rx_stats->rs_more && rx_stats->rs_status != 0) { | 72 | if (rx_stats->rs_status != 0) { |
67 | if (rx_stats->rs_status & ATH9K_RXERR_CRC) | 73 | if (rx_stats->rs_status & ATH9K_RXERR_CRC) |
68 | rxs->flag |= RX_FLAG_FAILED_FCS_CRC; | 74 | rxs->flag |= RX_FLAG_FAILED_FCS_CRC; |
69 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) | 75 | if (rx_stats->rs_status & ATH9K_RXERR_PHY) |
@@ -102,11 +108,11 @@ static bool ath9k_rx_accept(struct ath_common *common, | |||
102 | return true; | 108 | return true; |
103 | } | 109 | } |
104 | 110 | ||
105 | static u8 ath9k_process_rate(struct ath_common *common, | 111 | static int ath9k_process_rate(struct ath_common *common, |
106 | struct ieee80211_hw *hw, | 112 | struct ieee80211_hw *hw, |
107 | struct ath_rx_status *rx_stats, | 113 | struct ath_rx_status *rx_stats, |
108 | struct ieee80211_rx_status *rxs, | 114 | struct ieee80211_rx_status *rxs, |
109 | struct sk_buff *skb) | 115 | struct sk_buff *skb) |
110 | { | 116 | { |
111 | struct ieee80211_supported_band *sband; | 117 | struct ieee80211_supported_band *sband; |
112 | enum ieee80211_band band; | 118 | enum ieee80211_band band; |
@@ -122,25 +128,32 @@ static u8 ath9k_process_rate(struct ath_common *common, | |||
122 | rxs->flag |= RX_FLAG_40MHZ; | 128 | rxs->flag |= RX_FLAG_40MHZ; |
123 | if (rx_stats->rs_flags & ATH9K_RX_GI) | 129 | if (rx_stats->rs_flags & ATH9K_RX_GI) |
124 | rxs->flag |= RX_FLAG_SHORT_GI; | 130 | rxs->flag |= RX_FLAG_SHORT_GI; |
125 | return rx_stats->rs_rate & 0x7f; | 131 | rxs->rate_idx = rx_stats->rs_rate & 0x7f; |
132 | return 0; | ||
126 | } | 133 | } |
127 | 134 | ||
128 | for (i = 0; i < sband->n_bitrates; i++) { | 135 | for (i = 0; i < sband->n_bitrates; i++) { |
129 | if (sband->bitrates[i].hw_value == rx_stats->rs_rate) | 136 | if (sband->bitrates[i].hw_value == rx_stats->rs_rate) { |
130 | return i; | 137 | rxs->rate_idx = i; |
138 | return 0; | ||
139 | } | ||
131 | if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { | 140 | if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) { |
132 | rxs->flag |= RX_FLAG_SHORTPRE; | 141 | rxs->flag |= RX_FLAG_SHORTPRE; |
133 | return i; | 142 | rxs->rate_idx = i; |
143 | return 0; | ||
134 | } | 144 | } |
135 | } | 145 | } |
136 | 146 | ||
137 | /* No valid hardware bitrate found -- we should not get here */ | 147 | /* |
148 | * No valid hardware bitrate found -- we should not get here | ||
149 | * because hardware has already validated this frame as OK. | ||
150 | */ | ||
138 | ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected " | 151 | ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected " |
139 | "0x%02x using 1 Mbit\n", rx_stats->rs_rate); | 152 | "0x%02x using 1 Mbit\n", rx_stats->rs_rate); |
140 | if ((common->debug_mask & ATH_DBG_XMIT)) | 153 | if ((common->debug_mask & ATH_DBG_XMIT)) |
141 | print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len); | 154 | print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len); |
142 | 155 | ||
143 | return 0; | 156 | return -EINVAL; |
144 | } | 157 | } |
145 | 158 | ||
146 | static void ath9k_process_rssi(struct ath_common *common, | 159 | static void ath9k_process_rssi(struct ath_common *common, |
@@ -202,17 +215,22 @@ int ath9k_cmn_rx_skb_preprocess(struct ath_common *common, | |||
202 | struct ath_hw *ah = common->ah; | 215 | struct ath_hw *ah = common->ah; |
203 | 216 | ||
204 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); | 217 | memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); |
218 | |||
219 | /* | ||
220 | * everything but the rate is checked here, the rate check is done | ||
221 | * separately to avoid doing two lookups for a rate for each frame. | ||
222 | */ | ||
205 | if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) | 223 | if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error)) |
206 | return -EINVAL; | 224 | return -EINVAL; |
207 | 225 | ||
208 | ath9k_process_rssi(common, hw, skb, rx_stats); | 226 | ath9k_process_rssi(common, hw, skb, rx_stats); |
209 | 227 | ||
210 | rx_status->rate_idx = ath9k_process_rate(common, hw, | 228 | if (ath9k_process_rate(common, hw, rx_stats, rx_status, skb)) |
211 | rx_stats, rx_status, skb); | 229 | return -EINVAL; |
230 | |||
212 | rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); | 231 | rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp); |
213 | rx_status->band = hw->conf.channel->band; | 232 | rx_status->band = hw->conf.channel->band; |
214 | rx_status->freq = hw->conf.channel->center_freq; | 233 | rx_status->freq = hw->conf.channel->center_freq; |
215 | rx_status->noise = common->ani.noise_floor; | ||
216 | rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; | 234 | rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; |
217 | rx_status->antenna = rx_stats->rs_antenna; | 235 | rx_status->antenna = rx_stats->rs_antenna; |
218 | rx_status->flag |= RX_FLAG_TSFT; | 236 | rx_status->flag |= RX_FLAG_TSFT; |
@@ -255,7 +273,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, | |||
255 | 273 | ||
256 | keyix = rx_stats->rs_keyix; | 274 | keyix = rx_stats->rs_keyix; |
257 | 275 | ||
258 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { | 276 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error && |
277 | ieee80211_has_protected(fc)) { | ||
259 | rxs->flag |= RX_FLAG_DECRYPTED; | 278 | rxs->flag |= RX_FLAG_DECRYPTED; |
260 | } else if (ieee80211_has_protected(fc) | 279 | } else if (ieee80211_has_protected(fc) |
261 | && !decrypt_error && skb->len >= hdrlen + 4) { | 280 | && !decrypt_error && skb->len >= hdrlen + 4) { |
@@ -286,6 +305,345 @@ int ath9k_cmn_padpos(__le16 frame_control) | |||
286 | } | 305 | } |
287 | EXPORT_SYMBOL(ath9k_cmn_padpos); | 306 | EXPORT_SYMBOL(ath9k_cmn_padpos); |
288 | 307 | ||
308 | int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) | ||
309 | { | ||
310 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
311 | |||
312 | if (tx_info->control.hw_key) { | ||
313 | if (tx_info->control.hw_key->alg == ALG_WEP) | ||
314 | return ATH9K_KEY_TYPE_WEP; | ||
315 | else if (tx_info->control.hw_key->alg == ALG_TKIP) | ||
316 | return ATH9K_KEY_TYPE_TKIP; | ||
317 | else if (tx_info->control.hw_key->alg == ALG_CCMP) | ||
318 | return ATH9K_KEY_TYPE_AES; | ||
319 | } | ||
320 | |||
321 | return ATH9K_KEY_TYPE_CLEAR; | ||
322 | } | ||
323 | EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); | ||
324 | |||
325 | static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, | ||
326 | enum nl80211_channel_type channel_type) | ||
327 | { | ||
328 | u32 chanmode = 0; | ||
329 | |||
330 | switch (chan->band) { | ||
331 | case IEEE80211_BAND_2GHZ: | ||
332 | switch (channel_type) { | ||
333 | case NL80211_CHAN_NO_HT: | ||
334 | case NL80211_CHAN_HT20: | ||
335 | chanmode = CHANNEL_G_HT20; | ||
336 | break; | ||
337 | case NL80211_CHAN_HT40PLUS: | ||
338 | chanmode = CHANNEL_G_HT40PLUS; | ||
339 | break; | ||
340 | case NL80211_CHAN_HT40MINUS: | ||
341 | chanmode = CHANNEL_G_HT40MINUS; | ||
342 | break; | ||
343 | } | ||
344 | break; | ||
345 | case IEEE80211_BAND_5GHZ: | ||
346 | switch (channel_type) { | ||
347 | case NL80211_CHAN_NO_HT: | ||
348 | case NL80211_CHAN_HT20: | ||
349 | chanmode = CHANNEL_A_HT20; | ||
350 | break; | ||
351 | case NL80211_CHAN_HT40PLUS: | ||
352 | chanmode = CHANNEL_A_HT40PLUS; | ||
353 | break; | ||
354 | case NL80211_CHAN_HT40MINUS: | ||
355 | chanmode = CHANNEL_A_HT40MINUS; | ||
356 | break; | ||
357 | } | ||
358 | break; | ||
359 | default: | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | return chanmode; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * Update internal channel flags. | ||
368 | */ | ||
369 | void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, | ||
370 | struct ath9k_channel *ichan) | ||
371 | { | ||
372 | struct ieee80211_channel *chan = hw->conf.channel; | ||
373 | struct ieee80211_conf *conf = &hw->conf; | ||
374 | |||
375 | ichan->channel = chan->center_freq; | ||
376 | ichan->chan = chan; | ||
377 | |||
378 | if (chan->band == IEEE80211_BAND_2GHZ) { | ||
379 | ichan->chanmode = CHANNEL_G; | ||
380 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; | ||
381 | } else { | ||
382 | ichan->chanmode = CHANNEL_A; | ||
383 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; | ||
384 | } | ||
385 | |||
386 | if (conf_is_ht(conf)) | ||
387 | ichan->chanmode = ath9k_get_extchanmode(chan, | ||
388 | conf->channel_type); | ||
389 | } | ||
390 | EXPORT_SYMBOL(ath9k_cmn_update_ichannel); | ||
391 | |||
392 | /* | ||
393 | * Get the internal channel reference. | ||
394 | */ | ||
395 | struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, | ||
396 | struct ath_hw *ah) | ||
397 | { | ||
398 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
399 | struct ath9k_channel *channel; | ||
400 | u8 chan_idx; | ||
401 | |||
402 | chan_idx = curchan->hw_value; | ||
403 | channel = &ah->channels[chan_idx]; | ||
404 | ath9k_cmn_update_ichannel(hw, channel); | ||
405 | |||
406 | return channel; | ||
407 | } | ||
408 | EXPORT_SYMBOL(ath9k_cmn_get_curchannel); | ||
409 | |||
410 | static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, | ||
411 | struct ath9k_keyval *hk, const u8 *addr, | ||
412 | bool authenticator) | ||
413 | { | ||
414 | struct ath_hw *ah = common->ah; | ||
415 | const u8 *key_rxmic; | ||
416 | const u8 *key_txmic; | ||
417 | |||
418 | key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | ||
419 | key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | ||
420 | |||
421 | if (addr == NULL) { | ||
422 | /* | ||
423 | * Group key installation - only two key cache entries are used | ||
424 | * regardless of splitmic capability since group key is only | ||
425 | * used either for TX or RX. | ||
426 | */ | ||
427 | if (authenticator) { | ||
428 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
429 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); | ||
430 | } else { | ||
431 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
432 | memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); | ||
433 | } | ||
434 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
435 | } | ||
436 | if (!common->splitmic) { | ||
437 | /* TX and RX keys share the same key cache entry. */ | ||
438 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
439 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); | ||
440 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
441 | } | ||
442 | |||
443 | /* Separate key cache entries for TX and RX */ | ||
444 | |||
445 | /* TX key goes at first index, RX key at +32. */ | ||
446 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
447 | if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { | ||
448 | /* TX MIC entry failed. No need to proceed further */ | ||
449 | ath_print(common, ATH_DBG_FATAL, | ||
450 | "Setting TX MIC Key Failed\n"); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
455 | /* XXX delete tx key on failure? */ | ||
456 | return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); | ||
457 | } | ||
458 | |||
459 | static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) | ||
460 | { | ||
461 | int i; | ||
462 | |||
463 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
464 | if (test_bit(i, common->keymap) || | ||
465 | test_bit(i + 64, common->keymap)) | ||
466 | continue; /* At least one part of TKIP key allocated */ | ||
467 | if (common->splitmic && | ||
468 | (test_bit(i + 32, common->keymap) || | ||
469 | test_bit(i + 64 + 32, common->keymap))) | ||
470 | continue; /* At least one part of TKIP key allocated */ | ||
471 | |||
472 | /* Found a free slot for a TKIP key */ | ||
473 | return i; | ||
474 | } | ||
475 | return -1; | ||
476 | } | ||
477 | |||
478 | static int ath_reserve_key_cache_slot(struct ath_common *common) | ||
479 | { | ||
480 | int i; | ||
481 | |||
482 | /* First, try to find slots that would not be available for TKIP. */ | ||
483 | if (common->splitmic) { | ||
484 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { | ||
485 | if (!test_bit(i, common->keymap) && | ||
486 | (test_bit(i + 32, common->keymap) || | ||
487 | test_bit(i + 64, common->keymap) || | ||
488 | test_bit(i + 64 + 32, common->keymap))) | ||
489 | return i; | ||
490 | if (!test_bit(i + 32, common->keymap) && | ||
491 | (test_bit(i, common->keymap) || | ||
492 | test_bit(i + 64, common->keymap) || | ||
493 | test_bit(i + 64 + 32, common->keymap))) | ||
494 | return i + 32; | ||
495 | if (!test_bit(i + 64, common->keymap) && | ||
496 | (test_bit(i , common->keymap) || | ||
497 | test_bit(i + 32, common->keymap) || | ||
498 | test_bit(i + 64 + 32, common->keymap))) | ||
499 | return i + 64; | ||
500 | if (!test_bit(i + 64 + 32, common->keymap) && | ||
501 | (test_bit(i, common->keymap) || | ||
502 | test_bit(i + 32, common->keymap) || | ||
503 | test_bit(i + 64, common->keymap))) | ||
504 | return i + 64 + 32; | ||
505 | } | ||
506 | } else { | ||
507 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
508 | if (!test_bit(i, common->keymap) && | ||
509 | test_bit(i + 64, common->keymap)) | ||
510 | return i; | ||
511 | if (test_bit(i, common->keymap) && | ||
512 | !test_bit(i + 64, common->keymap)) | ||
513 | return i + 64; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* No partially used TKIP slots, pick any available slot */ | ||
518 | for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { | ||
519 | /* Do not allow slots that could be needed for TKIP group keys | ||
520 | * to be used. This limitation could be removed if we know that | ||
521 | * TKIP will not be used. */ | ||
522 | if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) | ||
523 | continue; | ||
524 | if (common->splitmic) { | ||
525 | if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) | ||
526 | continue; | ||
527 | if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) | ||
528 | continue; | ||
529 | } | ||
530 | |||
531 | if (!test_bit(i, common->keymap)) | ||
532 | return i; /* Found a free slot for a key */ | ||
533 | } | ||
534 | |||
535 | /* No free slot found */ | ||
536 | return -1; | ||
537 | } | ||
538 | |||
539 | /* | ||
540 | * Configure encryption in the HW. | ||
541 | */ | ||
542 | int ath9k_cmn_key_config(struct ath_common *common, | ||
543 | struct ieee80211_vif *vif, | ||
544 | struct ieee80211_sta *sta, | ||
545 | struct ieee80211_key_conf *key) | ||
546 | { | ||
547 | struct ath_hw *ah = common->ah; | ||
548 | struct ath9k_keyval hk; | ||
549 | const u8 *mac = NULL; | ||
550 | int ret = 0; | ||
551 | int idx; | ||
552 | |||
553 | memset(&hk, 0, sizeof(hk)); | ||
554 | |||
555 | switch (key->alg) { | ||
556 | case ALG_WEP: | ||
557 | hk.kv_type = ATH9K_CIPHER_WEP; | ||
558 | break; | ||
559 | case ALG_TKIP: | ||
560 | hk.kv_type = ATH9K_CIPHER_TKIP; | ||
561 | break; | ||
562 | case ALG_CCMP: | ||
563 | hk.kv_type = ATH9K_CIPHER_AES_CCM; | ||
564 | break; | ||
565 | default: | ||
566 | return -EOPNOTSUPP; | ||
567 | } | ||
568 | |||
569 | hk.kv_len = key->keylen; | ||
570 | memcpy(hk.kv_val, key->key, key->keylen); | ||
571 | |||
572 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | ||
573 | /* For now, use the default keys for broadcast keys. This may | ||
574 | * need to change with virtual interfaces. */ | ||
575 | idx = key->keyidx; | ||
576 | } else if (key->keyidx) { | ||
577 | if (WARN_ON(!sta)) | ||
578 | return -EOPNOTSUPP; | ||
579 | mac = sta->addr; | ||
580 | |||
581 | if (vif->type != NL80211_IFTYPE_AP) { | ||
582 | /* Only keyidx 0 should be used with unicast key, but | ||
583 | * allow this for client mode for now. */ | ||
584 | idx = key->keyidx; | ||
585 | } else | ||
586 | return -EIO; | ||
587 | } else { | ||
588 | if (WARN_ON(!sta)) | ||
589 | return -EOPNOTSUPP; | ||
590 | mac = sta->addr; | ||
591 | |||
592 | if (key->alg == ALG_TKIP) | ||
593 | idx = ath_reserve_key_cache_slot_tkip(common); | ||
594 | else | ||
595 | idx = ath_reserve_key_cache_slot(common); | ||
596 | if (idx < 0) | ||
597 | return -ENOSPC; /* no free key cache entries */ | ||
598 | } | ||
599 | |||
600 | if (key->alg == ALG_TKIP) | ||
601 | ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, | ||
602 | vif->type == NL80211_IFTYPE_AP); | ||
603 | else | ||
604 | ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); | ||
605 | |||
606 | if (!ret) | ||
607 | return -EIO; | ||
608 | |||
609 | set_bit(idx, common->keymap); | ||
610 | if (key->alg == ALG_TKIP) { | ||
611 | set_bit(idx + 64, common->keymap); | ||
612 | if (common->splitmic) { | ||
613 | set_bit(idx + 32, common->keymap); | ||
614 | set_bit(idx + 64 + 32, common->keymap); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | return idx; | ||
619 | } | ||
620 | EXPORT_SYMBOL(ath9k_cmn_key_config); | ||
621 | |||
622 | /* | ||
623 | * Delete Key. | ||
624 | */ | ||
625 | void ath9k_cmn_key_delete(struct ath_common *common, | ||
626 | struct ieee80211_key_conf *key) | ||
627 | { | ||
628 | struct ath_hw *ah = common->ah; | ||
629 | |||
630 | ath9k_hw_keyreset(ah, key->hw_key_idx); | ||
631 | if (key->hw_key_idx < IEEE80211_WEP_NKID) | ||
632 | return; | ||
633 | |||
634 | clear_bit(key->hw_key_idx, common->keymap); | ||
635 | if (key->alg != ALG_TKIP) | ||
636 | return; | ||
637 | |||
638 | clear_bit(key->hw_key_idx + 64, common->keymap); | ||
639 | if (common->splitmic) { | ||
640 | ath9k_hw_keyreset(ah, key->hw_key_idx + 32); | ||
641 | clear_bit(key->hw_key_idx + 32, common->keymap); | ||
642 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); | ||
643 | } | ||
644 | } | ||
645 | EXPORT_SYMBOL(ath9k_cmn_key_delete); | ||
646 | |||
289 | static int __init ath9k_cmn_init(void) | 647 | static int __init ath9k_cmn_init(void) |
290 | { | 648 | { |
291 | return 0; | 649 | return 0; |