/* * Copyright (c) 2009 Atheros Communications Inc. * Copyright (c) 2010 Bruno Randolf <br1@einfach.org> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
if (entry >= common->keymax) {
ath_err(common, "keysetmac: keycache entry %u out of range\n",
entry); returnfalse;
}
if (mac != NULL) { /* * AR_KEYTABLE_VALID indicates that the address is a unicast * address, which must match the transmitter address for * decrypting frames. * Not setting this bit allows the hardware to use the key * for multicast frame decryption.
*/ if (is_multicast_ether_addr(mac))
unicast_flag = 0;
/* * Note: Key cache registers access special memory area that requires * two 32-bit writes to actually update the values in the internal * memory. Consequently, the exact order and pairs used here must be * maintained.
*/
/* * Write inverted key[47:0] first to avoid Michael MIC errors * on frames that could be sent or received at the same time. * The correct key will be written in the end once everything * else is ready.
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
} else { /* * TKIP uses four key cache entries (two for group * keys): * Michael MIC TX/RX keys are in different key cache * entries (idx = main index + 64 for TX and * main index + 32 + 96 for RX): * key0 [31:0] = TX/RX MIC key [31:0] * key1 [31:0] = reserved * key2 [31:0] = TX/RX MIC key [63:32] * key3 [31:0] = reserved * key4 [31:0] = reserved * * Upper layer code will call this function separately * for TX and RX keys when these registers offsets are * used.
*/
u32 mic0, mic2;
/* MAC address registers are reserved for the MIC entry */
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
/* * Write the correct (un-inverted) key[47:0] last to enable * TKIP now that all other registers are set with correct * values.
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
if (addr == NULL) { /* * Group key installation - only two key cache entries are used * regardless of splitmic capability since group key is only * used either for TX or RX.
*/ if (authenticator) {
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
} else {
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
} return ath_hw_set_keycache_entry(common, keyix, hk, addr);
} if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { /* TX and RX keys share the same key cache entry. */
memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); return ath_hw_set_keycache_entry(common, keyix, hk, addr);
}
/* Separate key cache entries for TX and RX */
/* TX key goes at first index, RX key at +32. */
memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */
ath_err(common, "Setting TX MIC Key Failed\n"); return 0;
}
staticint ath_reserve_key_cache_slot_tkip(struct ath_common *common)
{ int i;
for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { if (test_bit(i, common->keymap) ||
test_bit(i + 64, common->keymap)) continue; /* At least one part of TKIP key allocated */ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) &&
(test_bit(i + 32, common->keymap) ||
test_bit(i + 64 + 32, common->keymap))) continue; /* At least one part of TKIP key allocated */
/* Found a free slot for a TKIP key */ return i;
} return -1;
}
staticint ath_reserve_key_cache_slot(struct ath_common *common,
u32 cipher)
{ int i;
if (cipher == WLAN_CIPHER_SUITE_TKIP) return ath_reserve_key_cache_slot_tkip(common);
/* First, try to find slots that would not be available for TKIP. */ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { if (!test_bit(i, common->keymap) &&
(test_bit(i + 32, common->keymap) ||
test_bit(i + 64, common->keymap) ||
test_bit(i + 64 + 32, common->keymap))) return i; if (!test_bit(i + 32, common->keymap) &&
(test_bit(i, common->keymap) ||
test_bit(i + 64, common->keymap) ||
test_bit(i + 64 + 32, common->keymap))) return i + 32; if (!test_bit(i + 64, common->keymap) &&
(test_bit(i , common->keymap) ||
test_bit(i + 32, common->keymap) ||
test_bit(i + 64 + 32, common->keymap))) return i + 64; if (!test_bit(i + 64 + 32, common->keymap) &&
(test_bit(i, common->keymap) ||
test_bit(i + 32, common->keymap) ||
test_bit(i + 64, common->keymap))) return i + 64 + 32;
}
} else { for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { if (!test_bit(i, common->keymap) &&
test_bit(i + 64, common->keymap)) return i; if (test_bit(i, common->keymap) &&
!test_bit(i + 64, common->keymap)) return i + 64;
}
}
/* No partially used TKIP slots, pick any available slot */ for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { /* Do not allow slots that could be needed for TKIP group keys * to be used. This limitation could be removed if we know that
* TKIP will not be used. */ if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) continue; if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) continue; if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) continue;
}
if (!test_bit(i, common->keymap)) return i; /* Found a free slot for a key */
}
/* No free slot found */ return -1;
}
/* * Configure encryption in the HW.
*/ int ath_key_config(struct ath_common *common, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key)
{ struct ath_keyval hk; const u8 *mac = NULL;
u8 gmac[ETH_ALEN]; int ret = 0; int idx;
memset(&hk, 0, sizeof(hk));
switch (key->cipher) { case 0:
hk.kv_type = ATH_CIPHER_CLR; break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104:
hk.kv_type = ATH_CIPHER_WEP; break; case WLAN_CIPHER_SUITE_TKIP:
hk.kv_type = ATH_CIPHER_TKIP; break; case WLAN_CIPHER_SUITE_CCMP:
hk.kv_type = ATH_CIPHER_AES_CCM; break; default: return -EOPNOTSUPP;
}
hk.kv_len = key->keylen; if (key->keylen)
memcpy(&hk.kv_values, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { switch (vif->type) { case NL80211_IFTYPE_AP:
memcpy(gmac, vif->addr, ETH_ALEN);
gmac[0] |= 0x01;
mac = gmac;
idx = ath_reserve_key_cache_slot(common, key->cipher); break; case NL80211_IFTYPE_ADHOC: if (!sta) {
idx = key->keyidx; break;
}
memcpy(gmac, sta->addr, ETH_ALEN);
gmac[0] |= 0x01;
mac = gmac;
idx = ath_reserve_key_cache_slot(common, key->cipher); break; default:
idx = key->keyidx; break;
}
} elseif (key->keyidx) { if (WARN_ON(!sta)) return -EOPNOTSUPP;
mac = sta->addr;
if (vif->type != NL80211_IFTYPE_AP) { /* Only keyidx 0 should be used with unicast key, but
* allow this for client mode for now. */
idx = key->keyidx;
} else return -EIO;
} else { if (WARN_ON(!sta)) return -EOPNOTSUPP;
mac = sta->addr;
/* * Delete Key.
*/ void ath_key_delete(struct ath_common *common, u8 hw_key_idx)
{ /* Leave CCMP and TKIP (main key) configured to avoid disabling * encryption for potentially pending frames already in a TXQ with the * keyix pointing to this key entry. Instead, only clear the MAC address * to prevent RX processing from using this key cache entry.
*/ if (test_bit(hw_key_idx, common->ccmp_keymap) ||
test_bit(hw_key_idx, common->tkip_keymap))
ath_hw_keysetmac(common, hw_key_idx, NULL); else
ath_hw_keyreset(common, hw_key_idx); if (hw_key_idx < IEEE80211_WEP_NKID) return;
clear_bit(hw_key_idx, common->keymap);
clear_bit(hw_key_idx, common->ccmp_keymap); if (!test_bit(hw_key_idx, common->tkip_keymap)) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.