aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2008-12-17 06:32:17 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-19 15:23:46 -0500
commit6ace2891a1d632303283816ae050849da48df142 (patch)
tree87912574efd8120184ce7d618fbd8f1665788cdf /drivers
parentf66000f7a39769b0ce2355fca13c40ac2f1c39db (diff)
ath9k: Key cache allocation for AP mode
Enhance allocation of key cache entries to support multiple pairwise keys to fix AP mode with more than one associated STA. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath9k/main.c200
1 files changed, 132 insertions, 68 deletions
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 11064cae8af6..e768be4669e7 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -664,13 +664,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
664 return chanmode; 664 return chanmode;
665} 665}
666 666
667static void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
668{
669 ath9k_hw_keyreset(sc->sc_ah, keyix);
670 if (freeslot)
671 clear_bit(keyix, sc->sc_keymap);
672}
673
674static int ath_keyset(struct ath_softc *sc, u16 keyix, 667static int ath_keyset(struct ath_softc *sc, u16 keyix,
675 struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) 668 struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
676{ 669{
@@ -682,21 +675,20 @@ static int ath_keyset(struct ath_softc *sc, u16 keyix,
682 return status != false; 675 return status != false;
683} 676}
684 677
685static int ath_setkey_tkip(struct ath_softc *sc, 678static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
686 struct ieee80211_key_conf *key,
687 struct ath9k_keyval *hk, 679 struct ath9k_keyval *hk,
688 const u8 *addr) 680 const u8 *addr)
689{ 681{
690 u8 *key_rxmic = NULL; 682 const u8 *key_rxmic;
691 u8 *key_txmic = NULL; 683 const u8 *key_txmic;
692 684
693 key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; 685 key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
694 key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; 686 key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
695 687
696 if (addr == NULL) { 688 if (addr == NULL) {
697 /* Group key installation */ 689 /* Group key installation */
698 memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 690 memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
699 return ath_keyset(sc, key->keyidx, hk, addr); 691 return ath_keyset(sc, keyix, hk, addr);
700 } 692 }
701 if (!sc->sc_splitmic) { 693 if (!sc->sc_splitmic) {
702 /* 694 /*
@@ -705,14 +697,14 @@ static int ath_setkey_tkip(struct ath_softc *sc,
705 */ 697 */
706 memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 698 memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
707 memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); 699 memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
708 return ath_keyset(sc, key->keyidx, hk, addr); 700 return ath_keyset(sc, keyix, hk, addr);
709 } 701 }
710 /* 702 /*
711 * TX key goes at first index, RX key at +32. 703 * TX key goes at first index, RX key at +32.
712 * The hal handles the MIC keys at index+64. 704 * The hal handles the MIC keys at index+64.
713 */ 705 */
714 memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); 706 memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
715 if (!ath_keyset(sc, key->keyidx, hk, NULL)) { 707 if (!ath_keyset(sc, keyix, hk, NULL)) {
716 /* Txmic entry failed. No need to proceed further */ 708 /* Txmic entry failed. No need to proceed further */
717 DPRINTF(sc, ATH_DBG_KEYCACHE, 709 DPRINTF(sc, ATH_DBG_KEYCACHE,
718 "Setting TX MIC Key Failed\n"); 710 "Setting TX MIC Key Failed\n");
@@ -721,18 +713,85 @@ static int ath_setkey_tkip(struct ath_softc *sc,
721 713
722 memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); 714 memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
723 /* XXX delete tx key on failure? */ 715 /* XXX delete tx key on failure? */
724 return ath_keyset(sc, key->keyidx+32, hk, addr); 716 return ath_keyset(sc, keyix + 32, hk, addr);
717}
718
719static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
720{
721 int i;
722
723 for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
724 if (test_bit(i, sc->sc_keymap) ||
725 test_bit(i + 64, sc->sc_keymap))
726 continue; /* At least one part of TKIP key allocated */
727 if (sc->sc_splitmic &&
728 (test_bit(i + 32, sc->sc_keymap) ||
729 test_bit(i + 64 + 32, sc->sc_keymap)))
730 continue; /* At least one part of TKIP key allocated */
731
732 /* Found a free slot for a TKIP key */
733 return i;
734 }
735 return -1;
736}
737
738static int ath_reserve_key_cache_slot(struct ath_softc *sc)
739{
740 int i;
741
742 /* First, try to find slots that would not be available for TKIP. */
743 if (sc->sc_splitmic) {
744 for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) {
745 if (!test_bit(i, sc->sc_keymap) &&
746 (test_bit(i + 32, sc->sc_keymap) ||
747 test_bit(i + 64, sc->sc_keymap) ||
748 test_bit(i + 64 + 32, sc->sc_keymap)))
749 return i;
750 if (!test_bit(i + 32, sc->sc_keymap) &&
751 (test_bit(i, sc->sc_keymap) ||
752 test_bit(i + 64, sc->sc_keymap) ||
753 test_bit(i + 64 + 32, sc->sc_keymap)))
754 return i + 32;
755 if (!test_bit(i + 64, sc->sc_keymap) &&
756 (test_bit(i , sc->sc_keymap) ||
757 test_bit(i + 32, sc->sc_keymap) ||
758 test_bit(i + 64 + 32, sc->sc_keymap)))
759 return i;
760 if (!test_bit(i + 64 + 32, sc->sc_keymap) &&
761 (test_bit(i, sc->sc_keymap) ||
762 test_bit(i + 32, sc->sc_keymap) ||
763 test_bit(i + 64, sc->sc_keymap)))
764 return i;
765 }
766 } else {
767 for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) {
768 if (!test_bit(i, sc->sc_keymap) &&
769 test_bit(i + 64, sc->sc_keymap))
770 return i;
771 if (test_bit(i, sc->sc_keymap) &&
772 !test_bit(i + 64, sc->sc_keymap))
773 return i + 64;
774 }
775 }
776
777 /* No partially used TKIP slots, pick any available slot */
778 for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) {
779 if (!test_bit(i, sc->sc_keymap))
780 return i; /* Found a free slot for a key */
781 }
782
783 /* No free slot found */
784 return -1;
725} 785}
726 786
727static int ath_key_config(struct ath_softc *sc, 787static int ath_key_config(struct ath_softc *sc,
728 const u8 *addr, 788 const u8 *addr,
729 struct ieee80211_key_conf *key) 789 struct ieee80211_key_conf *key)
730{ 790{
731 struct ieee80211_vif *vif;
732 struct ath9k_keyval hk; 791 struct ath9k_keyval hk;
733 const u8 *mac = NULL; 792 const u8 *mac = NULL;
734 int ret = 0; 793 int ret = 0;
735 enum nl80211_iftype opmode; 794 int idx;
736 795
737 memset(&hk, 0, sizeof(hk)); 796 memset(&hk, 0, sizeof(hk));
738 797
@@ -750,65 +809,69 @@ static int ath_key_config(struct ath_softc *sc,
750 return -EINVAL; 809 return -EINVAL;
751 } 810 }
752 811
753 hk.kv_len = key->keylen; 812 hk.kv_len = key->keylen;
754 memcpy(hk.kv_val, key->key, key->keylen); 813 memcpy(hk.kv_val, key->key, key->keylen);
755 814
756 if (!sc->sc_vaps[0]) 815 if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
757 return -EIO; 816 /* For now, use the default keys for broadcast keys. This may
758 817 * need to change with virtual interfaces. */
759 vif = sc->sc_vaps[0]; 818 idx = key->keyidx;
760 opmode = vif->type; 819 } else if (key->keyidx) {
820 struct ieee80211_vif *vif;
761 821
762 /* 822 mac = addr;
763 * Strategy: 823 vif = sc->sc_vaps[0];
764 * For STA mc tx, we will not setup a key at 824 if (vif->type != NL80211_IFTYPE_AP) {
765 * all since we never tx mc. 825 /* Only keyidx 0 should be used with unicast key, but
766 * 826 * allow this for client mode for now. */
767 * For STA mc rx, we will use the keyID. 827 idx = key->keyidx;
768 * 828 } else
769 * For ADHOC mc tx, we will use the keyID, and no macaddr. 829 return -EIO;
770 *
771 * For ADHOC mc rx, we will alloc a slot and plumb the mac of
772 * the peer node.
773 * BUT we will plumb a cleartext key so that we can do
774 * per-Sta default key table lookup in software.
775 */
776 if (is_broadcast_ether_addr(addr)) {
777 switch (opmode) {
778 case NL80211_IFTYPE_STATION:
779 /* default key: could be group WPA key
780 * or could be static WEP key */
781 mac = NULL;
782 break;
783 case NL80211_IFTYPE_ADHOC:
784 break;
785 case NL80211_IFTYPE_AP:
786 break;
787 default:
788 ASSERT(0);
789 break;
790 }
791 } else { 830 } else {
792 mac = addr; 831 mac = addr;
832 if (key->alg == ALG_TKIP)
833 idx = ath_reserve_key_cache_slot_tkip(sc);
834 else
835 idx = ath_reserve_key_cache_slot(sc);
836 if (idx < 0)
837 return -EIO; /* no free key cache entries */
793 } 838 }
794 839
795 if (key->alg == ALG_TKIP) 840 if (key->alg == ALG_TKIP)
796 ret = ath_setkey_tkip(sc, key, &hk, mac); 841 ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
797 else 842 else
798 ret = ath_keyset(sc, key->keyidx, &hk, mac); 843 ret = ath_keyset(sc, idx, &hk, mac);
799 844
800 if (!ret) 845 if (!ret)
801 return -EIO; 846 return -EIO;
802 847
803 return 0; 848 set_bit(idx, sc->sc_keymap);
849 if (key->alg == ALG_TKIP) {
850 set_bit(idx + 64, sc->sc_keymap);
851 if (sc->sc_splitmic) {
852 set_bit(idx + 32, sc->sc_keymap);
853 set_bit(idx + 64 + 32, sc->sc_keymap);
854 }
855 }
856
857 return idx;
804} 858}
805 859
806static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) 860static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
807{ 861{
808 int freeslot; 862 ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx);
863 if (key->hw_key_idx < IEEE80211_WEP_NKID)
864 return;
865
866 clear_bit(key->hw_key_idx, sc->sc_keymap);
867 if (key->alg != ALG_TKIP)
868 return;
809 869
810 freeslot = (key->keyidx >= 4) ? 1 : 0; 870 clear_bit(key->hw_key_idx + 64, sc->sc_keymap);
811 ath_key_reset(sc, key->keyidx, freeslot); 871 if (sc->sc_splitmic) {
872 clear_bit(key->hw_key_idx + 32, sc->sc_keymap);
873 clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap);
874 }
812} 875}
813 876
814static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) 877static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info)
@@ -1301,13 +1364,15 @@ static int ath_init(u16 devid, struct ath_softc *sc)
1301 * Mark key cache slots associated with global keys 1364 * Mark key cache slots associated with global keys
1302 * as in use. If we knew TKIP was not to be used we 1365 * as in use. If we knew TKIP was not to be used we
1303 * could leave the +32, +64, and +32+64 slots free. 1366 * could leave the +32, +64, and +32+64 slots free.
1304 * XXX only for splitmic.
1305 */ 1367 */
1306 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 1368 for (i = 0; i < IEEE80211_WEP_NKID; i++) {
1307 set_bit(i, sc->sc_keymap); 1369 set_bit(i, sc->sc_keymap);
1308 set_bit(i + 32, sc->sc_keymap);
1309 set_bit(i + 64, sc->sc_keymap); 1370 set_bit(i + 64, sc->sc_keymap);
1310 set_bit(i + 32 + 64, sc->sc_keymap); 1371 if (ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
1372 0, NULL)) {
1373 set_bit(i + 32, sc->sc_keymap);
1374 set_bit(i + 32 + 64, sc->sc_keymap);
1375 }
1311 } 1376 }
1312 1377
1313 /* Collect the channel list using the default country code */ 1378 /* Collect the channel list using the default country code */
@@ -2292,18 +2357,17 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
2292 switch (cmd) { 2357 switch (cmd) {
2293 case SET_KEY: 2358 case SET_KEY:
2294 ret = ath_key_config(sc, addr, key); 2359 ret = ath_key_config(sc, addr, key);
2295 if (!ret) { 2360 if (ret >= 0) {
2296 set_bit(key->keyidx, sc->sc_keymap); 2361 key->hw_key_idx = ret;
2297 key->hw_key_idx = key->keyidx;
2298 /* push IV and Michael MIC generation to stack */ 2362 /* push IV and Michael MIC generation to stack */
2299 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; 2363 key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
2300 if (key->alg == ALG_TKIP) 2364 if (key->alg == ALG_TKIP)
2301 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; 2365 key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
2366 ret = 0;
2302 } 2367 }
2303 break; 2368 break;
2304 case DISABLE_KEY: 2369 case DISABLE_KEY:
2305 ath_key_delete(sc, key); 2370 ath_key_delete(sc, key);
2306 clear_bit(key->keyidx, sc->sc_keymap);
2307 break; 2371 break;
2308 default: 2372 default:
2309 ret = -EINVAL; 2373 ret = -EINVAL;