diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2010-03-17 04:55:25 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-03-23 16:50:17 -0400 |
commit | fb9987d0f748c983bb795a86f47522313f701a08 (patch) | |
tree | e70d809b887ba25ed1a5da018e8baae829d0b8ad /drivers/net/wireless/ath/ath9k/common.c | |
parent | 736b3a27b3c50c4a23717b802240435a69e8d0ff (diff) |
ath9k_htc: Support for AR9271 chipset.
Features:
* Station mode
* IBSS mode
* Monitor mode
* Legacy support
* HT support
* TX/RX 11n Aggregation
* HW encryption
* LED
* Suspend/Resume
For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: Senthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/common.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 4d775ae141db..7902d287f671 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c | |||
@@ -286,6 +286,427 @@ int ath9k_cmn_padpos(__le16 frame_control) | |||
286 | } | 286 | } |
287 | EXPORT_SYMBOL(ath9k_cmn_padpos); | 287 | EXPORT_SYMBOL(ath9k_cmn_padpos); |
288 | 288 | ||
289 | int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb) | ||
290 | { | ||
291 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | ||
292 | |||
293 | if (tx_info->control.hw_key) { | ||
294 | if (tx_info->control.hw_key->alg == ALG_WEP) | ||
295 | return ATH9K_KEY_TYPE_WEP; | ||
296 | else if (tx_info->control.hw_key->alg == ALG_TKIP) | ||
297 | return ATH9K_KEY_TYPE_TKIP; | ||
298 | else if (tx_info->control.hw_key->alg == ALG_CCMP) | ||
299 | return ATH9K_KEY_TYPE_AES; | ||
300 | } | ||
301 | |||
302 | return ATH9K_KEY_TYPE_CLEAR; | ||
303 | } | ||
304 | EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype); | ||
305 | |||
306 | /* | ||
307 | * Calculate the RX filter to be set in the HW. | ||
308 | */ | ||
309 | u32 ath9k_cmn_calcrxfilter(struct ieee80211_hw *hw, struct ath_hw *ah, | ||
310 | unsigned int rxfilter) | ||
311 | { | ||
312 | #define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) | ||
313 | |||
314 | u32 rfilt; | ||
315 | |||
316 | rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) | ||
317 | | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ||
318 | | ATH9K_RX_FILTER_MCAST; | ||
319 | |||
320 | /* If not a STA, enable processing of Probe Requests */ | ||
321 | if (ah->opmode != NL80211_IFTYPE_STATION) | ||
322 | rfilt |= ATH9K_RX_FILTER_PROBEREQ; | ||
323 | |||
324 | /* | ||
325 | * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station | ||
326 | * mode interface or when in monitor mode. AP mode does not need this | ||
327 | * since it receives all in-BSS frames anyway. | ||
328 | */ | ||
329 | if (((ah->opmode != NL80211_IFTYPE_AP) && | ||
330 | (rxfilter & FIF_PROMISC_IN_BSS)) || | ||
331 | (ah->opmode == NL80211_IFTYPE_MONITOR)) | ||
332 | rfilt |= ATH9K_RX_FILTER_PROM; | ||
333 | |||
334 | if (rxfilter & FIF_CONTROL) | ||
335 | rfilt |= ATH9K_RX_FILTER_CONTROL; | ||
336 | |||
337 | if ((ah->opmode == NL80211_IFTYPE_STATION) && | ||
338 | !(rxfilter & FIF_BCN_PRBRESP_PROMISC)) | ||
339 | rfilt |= ATH9K_RX_FILTER_MYBEACON; | ||
340 | else | ||
341 | rfilt |= ATH9K_RX_FILTER_BEACON; | ||
342 | |||
343 | if ((AR_SREV_9280_10_OR_LATER(ah) || | ||
344 | AR_SREV_9285_10_OR_LATER(ah)) && | ||
345 | (ah->opmode == NL80211_IFTYPE_AP) && | ||
346 | (rxfilter & FIF_PSPOLL)) | ||
347 | rfilt |= ATH9K_RX_FILTER_PSPOLL; | ||
348 | |||
349 | if (conf_is_ht(&hw->conf)) | ||
350 | rfilt |= ATH9K_RX_FILTER_COMP_BAR; | ||
351 | |||
352 | return rfilt; | ||
353 | |||
354 | #undef RX_FILTER_PRESERVE | ||
355 | } | ||
356 | EXPORT_SYMBOL(ath9k_cmn_calcrxfilter); | ||
357 | |||
358 | /* | ||
359 | * Recv initialization for opmode change. | ||
360 | */ | ||
361 | void ath9k_cmn_opmode_init(struct ieee80211_hw *hw, struct ath_hw *ah, | ||
362 | unsigned int rxfilter) | ||
363 | { | ||
364 | struct ath_common *common = ath9k_hw_common(ah); | ||
365 | |||
366 | u32 rfilt, mfilt[2]; | ||
367 | |||
368 | /* configure rx filter */ | ||
369 | rfilt = ath9k_cmn_calcrxfilter(hw, ah, rxfilter); | ||
370 | ath9k_hw_setrxfilter(ah, rfilt); | ||
371 | |||
372 | /* configure bssid mask */ | ||
373 | if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) | ||
374 | ath_hw_setbssidmask(common); | ||
375 | |||
376 | /* configure operational mode */ | ||
377 | ath9k_hw_setopmode(ah); | ||
378 | |||
379 | /* Handle any link-level address change. */ | ||
380 | ath9k_hw_setmac(ah, common->macaddr); | ||
381 | |||
382 | /* calculate and install multicast filter */ | ||
383 | mfilt[0] = mfilt[1] = ~0; | ||
384 | ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); | ||
385 | } | ||
386 | EXPORT_SYMBOL(ath9k_cmn_opmode_init); | ||
387 | |||
388 | static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, | ||
389 | enum nl80211_channel_type channel_type) | ||
390 | { | ||
391 | u32 chanmode = 0; | ||
392 | |||
393 | switch (chan->band) { | ||
394 | case IEEE80211_BAND_2GHZ: | ||
395 | switch (channel_type) { | ||
396 | case NL80211_CHAN_NO_HT: | ||
397 | case NL80211_CHAN_HT20: | ||
398 | chanmode = CHANNEL_G_HT20; | ||
399 | break; | ||
400 | case NL80211_CHAN_HT40PLUS: | ||
401 | chanmode = CHANNEL_G_HT40PLUS; | ||
402 | break; | ||
403 | case NL80211_CHAN_HT40MINUS: | ||
404 | chanmode = CHANNEL_G_HT40MINUS; | ||
405 | break; | ||
406 | } | ||
407 | break; | ||
408 | case IEEE80211_BAND_5GHZ: | ||
409 | switch (channel_type) { | ||
410 | case NL80211_CHAN_NO_HT: | ||
411 | case NL80211_CHAN_HT20: | ||
412 | chanmode = CHANNEL_A_HT20; | ||
413 | break; | ||
414 | case NL80211_CHAN_HT40PLUS: | ||
415 | chanmode = CHANNEL_A_HT40PLUS; | ||
416 | break; | ||
417 | case NL80211_CHAN_HT40MINUS: | ||
418 | chanmode = CHANNEL_A_HT40MINUS; | ||
419 | break; | ||
420 | } | ||
421 | break; | ||
422 | default: | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | return chanmode; | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * Update internal channel flags. | ||
431 | */ | ||
432 | void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, | ||
433 | struct ath9k_channel *ichan) | ||
434 | { | ||
435 | struct ieee80211_channel *chan = hw->conf.channel; | ||
436 | struct ieee80211_conf *conf = &hw->conf; | ||
437 | |||
438 | ichan->channel = chan->center_freq; | ||
439 | ichan->chan = chan; | ||
440 | |||
441 | if (chan->band == IEEE80211_BAND_2GHZ) { | ||
442 | ichan->chanmode = CHANNEL_G; | ||
443 | ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G; | ||
444 | } else { | ||
445 | ichan->chanmode = CHANNEL_A; | ||
446 | ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; | ||
447 | } | ||
448 | |||
449 | if (conf_is_ht(conf)) | ||
450 | ichan->chanmode = ath9k_get_extchanmode(chan, | ||
451 | conf->channel_type); | ||
452 | } | ||
453 | EXPORT_SYMBOL(ath9k_cmn_update_ichannel); | ||
454 | |||
455 | /* | ||
456 | * Get the internal channel reference. | ||
457 | */ | ||
458 | struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, | ||
459 | struct ath_hw *ah) | ||
460 | { | ||
461 | struct ieee80211_channel *curchan = hw->conf.channel; | ||
462 | struct ath9k_channel *channel; | ||
463 | u8 chan_idx; | ||
464 | |||
465 | chan_idx = curchan->hw_value; | ||
466 | channel = &ah->channels[chan_idx]; | ||
467 | ath9k_cmn_update_ichannel(hw, channel); | ||
468 | |||
469 | return channel; | ||
470 | } | ||
471 | EXPORT_SYMBOL(ath9k_cmn_get_curchannel); | ||
472 | |||
473 | static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, | ||
474 | struct ath9k_keyval *hk, const u8 *addr, | ||
475 | bool authenticator) | ||
476 | { | ||
477 | struct ath_hw *ah = common->ah; | ||
478 | const u8 *key_rxmic; | ||
479 | const u8 *key_txmic; | ||
480 | |||
481 | key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | ||
482 | key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | ||
483 | |||
484 | if (addr == NULL) { | ||
485 | /* | ||
486 | * Group key installation - only two key cache entries are used | ||
487 | * regardless of splitmic capability since group key is only | ||
488 | * used either for TX or RX. | ||
489 | */ | ||
490 | if (authenticator) { | ||
491 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
492 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); | ||
493 | } else { | ||
494 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
495 | memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); | ||
496 | } | ||
497 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
498 | } | ||
499 | if (!common->splitmic) { | ||
500 | /* TX and RX keys share the same key cache entry. */ | ||
501 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
502 | memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); | ||
503 | return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr); | ||
504 | } | ||
505 | |||
506 | /* Separate key cache entries for TX and RX */ | ||
507 | |||
508 | /* TX key goes at first index, RX key at +32. */ | ||
509 | memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); | ||
510 | if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) { | ||
511 | /* TX MIC entry failed. No need to proceed further */ | ||
512 | ath_print(common, ATH_DBG_FATAL, | ||
513 | "Setting TX MIC Key Failed\n"); | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); | ||
518 | /* XXX delete tx key on failure? */ | ||
519 | return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr); | ||
520 | } | ||
521 | |||
522 | static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) | ||
523 | { | ||
524 | int i; | ||
525 | |||
526 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
527 | if (test_bit(i, common->keymap) || | ||
528 | test_bit(i + 64, common->keymap)) | ||
529 | continue; /* At least one part of TKIP key allocated */ | ||
530 | if (common->splitmic && | ||
531 | (test_bit(i + 32, common->keymap) || | ||
532 | test_bit(i + 64 + 32, common->keymap))) | ||
533 | continue; /* At least one part of TKIP key allocated */ | ||
534 | |||
535 | /* Found a free slot for a TKIP key */ | ||
536 | return i; | ||
537 | } | ||
538 | return -1; | ||
539 | } | ||
540 | |||
541 | static int ath_reserve_key_cache_slot(struct ath_common *common) | ||
542 | { | ||
543 | int i; | ||
544 | |||
545 | /* First, try to find slots that would not be available for TKIP. */ | ||
546 | if (common->splitmic) { | ||
547 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { | ||
548 | if (!test_bit(i, common->keymap) && | ||
549 | (test_bit(i + 32, common->keymap) || | ||
550 | test_bit(i + 64, common->keymap) || | ||
551 | test_bit(i + 64 + 32, common->keymap))) | ||
552 | return i; | ||
553 | if (!test_bit(i + 32, common->keymap) && | ||
554 | (test_bit(i, common->keymap) || | ||
555 | test_bit(i + 64, common->keymap) || | ||
556 | test_bit(i + 64 + 32, common->keymap))) | ||
557 | return i + 32; | ||
558 | if (!test_bit(i + 64, common->keymap) && | ||
559 | (test_bit(i , common->keymap) || | ||
560 | test_bit(i + 32, common->keymap) || | ||
561 | test_bit(i + 64 + 32, common->keymap))) | ||
562 | return i + 64; | ||
563 | if (!test_bit(i + 64 + 32, common->keymap) && | ||
564 | (test_bit(i, common->keymap) || | ||
565 | test_bit(i + 32, common->keymap) || | ||
566 | test_bit(i + 64, common->keymap))) | ||
567 | return i + 64 + 32; | ||
568 | } | ||
569 | } else { | ||
570 | for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { | ||
571 | if (!test_bit(i, common->keymap) && | ||
572 | test_bit(i + 64, common->keymap)) | ||
573 | return i; | ||
574 | if (test_bit(i, common->keymap) && | ||
575 | !test_bit(i + 64, common->keymap)) | ||
576 | return i + 64; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | /* No partially used TKIP slots, pick any available slot */ | ||
581 | for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { | ||
582 | /* Do not allow slots that could be needed for TKIP group keys | ||
583 | * to be used. This limitation could be removed if we know that | ||
584 | * TKIP will not be used. */ | ||
585 | if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) | ||
586 | continue; | ||
587 | if (common->splitmic) { | ||
588 | if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) | ||
589 | continue; | ||
590 | if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) | ||
591 | continue; | ||
592 | } | ||
593 | |||
594 | if (!test_bit(i, common->keymap)) | ||
595 | return i; /* Found a free slot for a key */ | ||
596 | } | ||
597 | |||
598 | /* No free slot found */ | ||
599 | return -1; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * Configure encryption in the HW. | ||
604 | */ | ||
605 | int ath9k_cmn_key_config(struct ath_common *common, | ||
606 | struct ieee80211_vif *vif, | ||
607 | struct ieee80211_sta *sta, | ||
608 | struct ieee80211_key_conf *key) | ||
609 | { | ||
610 | struct ath_hw *ah = common->ah; | ||
611 | struct ath9k_keyval hk; | ||
612 | const u8 *mac = NULL; | ||
613 | int ret = 0; | ||
614 | int idx; | ||
615 | |||
616 | memset(&hk, 0, sizeof(hk)); | ||
617 | |||
618 | switch (key->alg) { | ||
619 | case ALG_WEP: | ||
620 | hk.kv_type = ATH9K_CIPHER_WEP; | ||
621 | break; | ||
622 | case ALG_TKIP: | ||
623 | hk.kv_type = ATH9K_CIPHER_TKIP; | ||
624 | break; | ||
625 | case ALG_CCMP: | ||
626 | hk.kv_type = ATH9K_CIPHER_AES_CCM; | ||
627 | break; | ||
628 | default: | ||
629 | return -EOPNOTSUPP; | ||
630 | } | ||
631 | |||
632 | hk.kv_len = key->keylen; | ||
633 | memcpy(hk.kv_val, key->key, key->keylen); | ||
634 | |||
635 | if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { | ||
636 | /* For now, use the default keys for broadcast keys. This may | ||
637 | * need to change with virtual interfaces. */ | ||
638 | idx = key->keyidx; | ||
639 | } else if (key->keyidx) { | ||
640 | if (WARN_ON(!sta)) | ||
641 | return -EOPNOTSUPP; | ||
642 | mac = sta->addr; | ||
643 | |||
644 | if (vif->type != NL80211_IFTYPE_AP) { | ||
645 | /* Only keyidx 0 should be used with unicast key, but | ||
646 | * allow this for client mode for now. */ | ||
647 | idx = key->keyidx; | ||
648 | } else | ||
649 | return -EIO; | ||
650 | } else { | ||
651 | if (WARN_ON(!sta)) | ||
652 | return -EOPNOTSUPP; | ||
653 | mac = sta->addr; | ||
654 | |||
655 | if (key->alg == ALG_TKIP) | ||
656 | idx = ath_reserve_key_cache_slot_tkip(common); | ||
657 | else | ||
658 | idx = ath_reserve_key_cache_slot(common); | ||
659 | if (idx < 0) | ||
660 | return -ENOSPC; /* no free key cache entries */ | ||
661 | } | ||
662 | |||
663 | if (key->alg == ALG_TKIP) | ||
664 | ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, | ||
665 | vif->type == NL80211_IFTYPE_AP); | ||
666 | else | ||
667 | ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac); | ||
668 | |||
669 | if (!ret) | ||
670 | return -EIO; | ||
671 | |||
672 | set_bit(idx, common->keymap); | ||
673 | if (key->alg == ALG_TKIP) { | ||
674 | set_bit(idx + 64, common->keymap); | ||
675 | if (common->splitmic) { | ||
676 | set_bit(idx + 32, common->keymap); | ||
677 | set_bit(idx + 64 + 32, common->keymap); | ||
678 | } | ||
679 | } | ||
680 | |||
681 | return idx; | ||
682 | } | ||
683 | EXPORT_SYMBOL(ath9k_cmn_key_config); | ||
684 | |||
685 | /* | ||
686 | * Delete Key. | ||
687 | */ | ||
688 | void ath9k_cmn_key_delete(struct ath_common *common, | ||
689 | struct ieee80211_key_conf *key) | ||
690 | { | ||
691 | struct ath_hw *ah = common->ah; | ||
692 | |||
693 | ath9k_hw_keyreset(ah, key->hw_key_idx); | ||
694 | if (key->hw_key_idx < IEEE80211_WEP_NKID) | ||
695 | return; | ||
696 | |||
697 | clear_bit(key->hw_key_idx, common->keymap); | ||
698 | if (key->alg != ALG_TKIP) | ||
699 | return; | ||
700 | |||
701 | clear_bit(key->hw_key_idx + 64, common->keymap); | ||
702 | if (common->splitmic) { | ||
703 | ath9k_hw_keyreset(ah, key->hw_key_idx + 32); | ||
704 | clear_bit(key->hw_key_idx + 32, common->keymap); | ||
705 | clear_bit(key->hw_key_idx + 64 + 32, common->keymap); | ||
706 | } | ||
707 | } | ||
708 | EXPORT_SYMBOL(ath9k_cmn_key_delete); | ||
709 | |||
289 | static int __init ath9k_cmn_init(void) | 710 | static int __init ath9k_cmn_init(void) |
290 | { | 711 | { |
291 | return 0; | 712 | return 0; |