aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2011-09-08 08:38:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-14 13:56:56 -0400
commita2b1328a23c57fbb9c51e6660a11049c35d151f9 (patch)
tree65468f09963cdeffe674d6d2e977aeadc3352a5f /drivers/net/wireless/rt2x00
parentead2bb64a38c471ad0a769f61921f330f062dd50 (diff)
rt2x00: Make use of sta_add/remove callbacks in rt2800
This allows us to assign a WCID to each STA even for STAs without crypto key. To achieve this search for an unused WCID in the HW WCID table and assign it to the according STA. When configuring a pairwise key for this STA we don't need to write the MAC address and BSSIDX anymore but just update the crypto related fields in the WCID_ATTR table. This has two advantages: 1) Setting a new key for an already available STA (PTK rekeying) is slightly less expensive and should improve performance in situations where a lot of rekeying happens (e.g. a huge number of stations and/or a small rekeying interval) 2) The TXWI now gets a WCID assigned for unencrypted frames which will be reflected in the corresponding tx status report. This should make tx status reports in unencrypted AP mode more reliable as we can distinguish between multiple key-less STAs. Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c153
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h3
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c4
4 files changed, 134 insertions, 30 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index cdb0133afc33..0e21aaf53bb4 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -493,7 +493,7 @@ void rt2800_write_tx_data(struct queue_entry *entry,
493 rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size); 493 rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size);
494 rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, 494 rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
495 test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? 495 test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
496 txdesc->key_idx : 0xff); 496 txdesc->key_idx : txdesc->u.ht.wcid);
497 rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, 497 rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
498 txdesc->length); 498 txdesc->length);
499 rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid); 499 rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid);
@@ -910,11 +910,51 @@ static void rt2800_init_led(struct rt2x00_dev *rt2x00dev,
910/* 910/*
911 * Configuration handlers. 911 * Configuration handlers.
912 */ 912 */
913static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, 913static void rt2800_config_wcid(struct rt2x00_dev *rt2x00dev,
914 struct rt2x00lib_crypto *crypto, 914 const u8 *address,
915 struct ieee80211_key_conf *key) 915 int wcid)
916{ 916{
917 struct mac_wcid_entry wcid_entry; 917 struct mac_wcid_entry wcid_entry;
918 u32 offset;
919
920 offset = MAC_WCID_ENTRY(wcid);
921
922 memset(&wcid_entry, 0xff, sizeof(wcid_entry));
923 if (address)
924 memcpy(wcid_entry.mac, address, ETH_ALEN);
925
926 rt2800_register_multiwrite(rt2x00dev, offset,
927 &wcid_entry, sizeof(wcid_entry));
928}
929
930static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid)
931{
932 u32 offset;
933 offset = MAC_WCID_ATTR_ENTRY(wcid);
934 rt2800_register_write(rt2x00dev, offset, 0);
935}
936
937static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev,
938 int wcid, u32 bssidx)
939{
940 u32 offset = MAC_WCID_ATTR_ENTRY(wcid);
941 u32 reg;
942
943 /*
944 * The BSS Idx numbers is split in a main value of 3 bits,
945 * and a extended field for adding one additional bit to the value.
946 */
947 rt2800_register_read(rt2x00dev, offset, &reg);
948 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7));
949 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
950 (bssidx & 0x8) >> 3);
951 rt2800_register_write(rt2x00dev, offset, reg);
952}
953
954static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev,
955 struct rt2x00lib_crypto *crypto,
956 struct ieee80211_key_conf *key)
957{
918 struct mac_iveiv_entry iveiv_entry; 958 struct mac_iveiv_entry iveiv_entry;
919 u32 offset; 959 u32 offset;
920 u32 reg; 960 u32 reg;
@@ -934,14 +974,16 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
934 (crypto->cipher & 0x7)); 974 (crypto->cipher & 0x7));
935 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 975 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT,
936 (crypto->cipher & 0x8) >> 3); 976 (crypto->cipher & 0x8) >> 3);
937 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX,
938 (crypto->bssidx & 0x7));
939 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT,
940 (crypto->bssidx & 0x8) >> 3);
941 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); 977 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher);
942 rt2800_register_write(rt2x00dev, offset, reg); 978 rt2800_register_write(rt2x00dev, offset, reg);
943 } else { 979 } else {
944 rt2800_register_write(rt2x00dev, offset, 0); 980 /* Delete the cipher without touching the bssidx */
981 rt2800_register_read(rt2x00dev, offset, &reg);
982 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_KEYTAB, 0);
983 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER, 0);
984 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0);
985 rt2x00_set_field32(&reg, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0);
986 rt2800_register_write(rt2x00dev, offset, reg);
945 } 987 }
946 988
947 offset = MAC_IVEIV_ENTRY(key->hw_key_idx); 989 offset = MAC_IVEIV_ENTRY(key->hw_key_idx);
@@ -954,14 +996,6 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev,
954 iveiv_entry.iv[3] |= key->keyidx << 6; 996 iveiv_entry.iv[3] |= key->keyidx << 6;
955 rt2800_register_multiwrite(rt2x00dev, offset, 997 rt2800_register_multiwrite(rt2x00dev, offset,
956 &iveiv_entry, sizeof(iveiv_entry)); 998 &iveiv_entry, sizeof(iveiv_entry));
957
958 offset = MAC_WCID_ENTRY(key->hw_key_idx);
959
960 memset(&wcid_entry, 0, sizeof(wcid_entry));
961 if (crypto->cmd == SET_KEY)
962 memcpy(wcid_entry.mac, crypto->address, ETH_ALEN);
963 rt2800_register_multiwrite(rt2x00dev, offset,
964 &wcid_entry, sizeof(wcid_entry));
965} 999}
966 1000
967int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, 1001int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
@@ -1008,20 +1042,24 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
1008 /* 1042 /*
1009 * Update WCID information 1043 * Update WCID information
1010 */ 1044 */
1011 rt2800_config_wcid_attr(rt2x00dev, crypto, key); 1045 rt2800_config_wcid(rt2x00dev, crypto->address, key->hw_key_idx);
1046 rt2800_config_wcid_attr_bssidx(rt2x00dev, key->hw_key_idx,
1047 crypto->bssidx);
1048 rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);
1012 1049
1013 return 0; 1050 return 0;
1014} 1051}
1015EXPORT_SYMBOL_GPL(rt2800_config_shared_key); 1052EXPORT_SYMBOL_GPL(rt2800_config_shared_key);
1016 1053
1017static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev) 1054static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev)
1018{ 1055{
1056 struct mac_wcid_entry wcid_entry;
1019 int idx; 1057 int idx;
1020 u32 offset, reg; 1058 u32 offset;
1021 1059
1022 /* 1060 /*
1023 * Search for the first free pairwise key entry and return the 1061 * Search for the first free WCID entry and return the corresponding
1024 * corresponding index. 1062 * index.
1025 * 1063 *
1026 * Make sure the WCID starts _after_ the last possible shared key 1064 * Make sure the WCID starts _after_ the last possible shared key
1027 * entry (>32). 1065 * entry (>32).
@@ -1031,11 +1069,17 @@ static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev)
1031 * first 222 entries. 1069 * first 222 entries.
1032 */ 1070 */
1033 for (idx = 33; idx <= 222; idx++) { 1071 for (idx = 33; idx <= 222; idx++) {
1034 offset = MAC_WCID_ATTR_ENTRY(idx); 1072 offset = MAC_WCID_ENTRY(idx);
1035 rt2800_register_read(rt2x00dev, offset, &reg); 1073 rt2800_register_multiread(rt2x00dev, offset, &wcid_entry,
1036 if (!reg) 1074 sizeof(wcid_entry));
1075 if (is_broadcast_ether_addr(wcid_entry.mac))
1037 return idx; 1076 return idx;
1038 } 1077 }
1078
1079 /*
1080 * Use -1 to indicate that we don't have any more space in the WCID
1081 * table.
1082 */
1039 return -1; 1083 return -1;
1040} 1084}
1041 1085
@@ -1045,13 +1089,15 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
1045{ 1089{
1046 struct hw_key_entry key_entry; 1090 struct hw_key_entry key_entry;
1047 u32 offset; 1091 u32 offset;
1048 int idx;
1049 1092
1050 if (crypto->cmd == SET_KEY) { 1093 if (crypto->cmd == SET_KEY) {
1051 idx = rt2800_find_pairwise_keyslot(rt2x00dev); 1094 /*
1052 if (idx < 0) 1095 * Allow key configuration only for STAs that are
1096 * known by the hw.
1097 */
1098 if (crypto->wcid < 0)
1053 return -ENOSPC; 1099 return -ENOSPC;
1054 key->hw_key_idx = idx; 1100 key->hw_key_idx = crypto->wcid;
1055 1101
1056 memcpy(key_entry.key, crypto->key, 1102 memcpy(key_entry.key, crypto->key,
1057 sizeof(key_entry.key)); 1103 sizeof(key_entry.key));
@@ -1068,12 +1114,59 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
1068 /* 1114 /*
1069 * Update WCID information 1115 * Update WCID information
1070 */ 1116 */
1071 rt2800_config_wcid_attr(rt2x00dev, crypto, key); 1117 rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key);
1072 1118
1073 return 0; 1119 return 0;
1074} 1120}
1075EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key); 1121EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key);
1076 1122
1123int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
1124 struct ieee80211_sta *sta)
1125{
1126 int wcid;
1127 struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta);
1128
1129 /*
1130 * Find next free WCID.
1131 */
1132 wcid = rt2800_find_wcid(rt2x00dev);
1133
1134 /*
1135 * Store selected wcid even if it is invalid so that we can
1136 * later decide if the STA is uploaded into the hw.
1137 */
1138 sta_priv->wcid = wcid;
1139
1140 /*
1141 * No space left in the device, however, we can still communicate
1142 * with the STA -> No error.
1143 */
1144 if (wcid < 0)
1145 return 0;
1146
1147 /*
1148 * Clean up WCID attributes and write STA address to the device.
1149 */
1150 rt2800_delete_wcid_attr(rt2x00dev, wcid);
1151 rt2800_config_wcid(rt2x00dev, sta->addr, wcid);
1152 rt2800_config_wcid_attr_bssidx(rt2x00dev, wcid,
1153 rt2x00lib_get_bssidx(rt2x00dev, vif));
1154 return 0;
1155}
1156EXPORT_SYMBOL_GPL(rt2800_sta_add);
1157
1158int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid)
1159{
1160 /*
1161 * Remove WCID entry, no need to clean the attributes as they will
1162 * get renewed when the WCID is reused.
1163 */
1164 rt2800_config_wcid(rt2x00dev, NULL, wcid);
1165
1166 return 0;
1167}
1168EXPORT_SYMBOL_GPL(rt2800_sta_remove);
1169
1077void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, 1170void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
1078 const unsigned int filter_flags) 1171 const unsigned int filter_flags)
1079{ 1172{
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index bef071cd911f..7a2511f6785c 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -166,6 +166,9 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev,
166int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, 166int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
167 struct rt2x00lib_crypto *crypto, 167 struct rt2x00lib_crypto *crypto,
168 struct ieee80211_key_conf *key); 168 struct ieee80211_key_conf *key);
169int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif,
170 struct ieee80211_sta *sta);
171int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid);
169void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, 172void rt2800_config_filter(struct rt2x00_dev *rt2x00dev,
170 const unsigned int filter_flags); 173 const unsigned int filter_flags);
171void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, 174void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index a716d1dd0754..da48c8ac27bd 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1015,6 +1015,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
1015 .get_stats = rt2x00mac_get_stats, 1015 .get_stats = rt2x00mac_get_stats,
1016 .get_tkip_seq = rt2800_get_tkip_seq, 1016 .get_tkip_seq = rt2800_get_tkip_seq,
1017 .set_rts_threshold = rt2800_set_rts_threshold, 1017 .set_rts_threshold = rt2800_set_rts_threshold,
1018 .sta_add = rt2x00mac_sta_add,
1019 .sta_remove = rt2x00mac_sta_remove,
1018 .bss_info_changed = rt2x00mac_bss_info_changed, 1020 .bss_info_changed = rt2x00mac_bss_info_changed,
1019 .conf_tx = rt2800_conf_tx, 1021 .conf_tx = rt2800_conf_tx,
1020 .get_tsf = rt2800_get_tsf, 1022 .get_tsf = rt2800_get_tsf,
@@ -1076,6 +1078,8 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
1076 .config_erp = rt2800_config_erp, 1078 .config_erp = rt2800_config_erp,
1077 .config_ant = rt2800_config_ant, 1079 .config_ant = rt2800_config_ant,
1078 .config = rt2800_config, 1080 .config = rt2800_config,
1081 .sta_add = rt2800_sta_add,
1082 .sta_remove = rt2800_sta_remove,
1079}; 1083};
1080 1084
1081static const struct data_queue_desc rt2800pci_queue_rx = { 1085static const struct data_queue_desc rt2800pci_queue_rx = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 7917614dbd50..4b907a53f97c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -750,6 +750,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
750 .get_stats = rt2x00mac_get_stats, 750 .get_stats = rt2x00mac_get_stats,
751 .get_tkip_seq = rt2800_get_tkip_seq, 751 .get_tkip_seq = rt2800_get_tkip_seq,
752 .set_rts_threshold = rt2800_set_rts_threshold, 752 .set_rts_threshold = rt2800_set_rts_threshold,
753 .sta_add = rt2x00mac_sta_add,
754 .sta_remove = rt2x00mac_sta_remove,
753 .bss_info_changed = rt2x00mac_bss_info_changed, 755 .bss_info_changed = rt2x00mac_bss_info_changed,
754 .conf_tx = rt2800_conf_tx, 756 .conf_tx = rt2800_conf_tx,
755 .get_tsf = rt2800_get_tsf, 757 .get_tsf = rt2800_get_tsf,
@@ -807,6 +809,8 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
807 .config_erp = rt2800_config_erp, 809 .config_erp = rt2800_config_erp,
808 .config_ant = rt2800_config_ant, 810 .config_ant = rt2800_config_ant,
809 .config = rt2800_config, 811 .config = rt2800_config,
812 .sta_add = rt2800_sta_add,
813 .sta_remove = rt2800_sta_remove,
810}; 814};
811 815
812static const struct data_queue_desc rt2800usb_queue_rx = { 816static const struct data_queue_desc rt2800usb_queue_rx = {