Path: blob/main/sys/dev/ath/ath_hal/ar5212/ar5212_keycache.c
39566 views
/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2002-2008 Sam Leffler, Errno Consulting4* Copyright (c) 2002-2008 Atheros Communications, Inc.5*6* Permission to use, copy, modify, and/or distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/18#include "opt_ah.h"1920#include "ah.h"21#include "ah_internal.h"2223#include "ar5212/ar5212.h"24#include "ar5212/ar5212reg.h"25#include "ar5212/ar5212desc.h"2627/*28* Note: The key cache hardware requires that each double-word29* pair be written in even/odd order (since the destination is30* a 64-bit register). Don't reorder the writes in this code31* w/o considering this!32*/33#define KEY_XOR 0xaa3435#define IS_MIC_ENABLED(ah) \36(AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE)3738/*39* Return the size of the hardware key cache.40*/41uint32_t42ar5212GetKeyCacheSize(struct ath_hal *ah)43{44return AH_PRIVATE(ah)->ah_caps.halKeyCacheSize;45}4647/*48* Return true if the specific key cache entry is valid.49*/50HAL_BOOL51ar5212IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry)52{53if (entry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {54uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));55if (val & AR_KEYTABLE_VALID)56return AH_TRUE;57}58return AH_FALSE;59}6061/*62* Clear the specified key cache entry and any associated MIC entry.63*/64HAL_BOOL65ar5212ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry)66{67uint32_t keyType;6869if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {70HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",71__func__, entry);72return AH_FALSE;73}74keyType = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry));7576/* XXX why not clear key type/valid bit first? */77OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);78OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);79OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);80OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);81OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);82OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);83OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);84OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);85if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) {86uint16_t micentry = entry+64; /* MIC goes at slot+64 */8788HALASSERT(micentry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize);89OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);90OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);91OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);92OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);93/* NB: key type and MAC are known to be ok */94}95return AH_TRUE;96}9798/*99* Sets the mac part of the specified key cache entry (and any100* associated MIC entry) and mark them valid.101*102* Since mac[0] is shifted off and not presented to the hardware,103* it does double duty as a "don't use for unicast, use for multicast104* matching" flag. This interface should later be extended to105* explicitly do that rather than overloading a bit in the MAC106* address.107*/108HAL_BOOL109ar5212SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac)110{111uint32_t macHi, macLo;112uint32_t unicast_flag = AR_KEYTABLE_VALID;113114if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {115HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",116__func__, entry);117return AH_FALSE;118}119/*120* Set MAC address -- shifted right by 1. MacLo is121* the 4 MSBs, and MacHi is the 2 LSBs.122*/123if (mac != AH_NULL) {124/*125* AR_KEYTABLE_VALID indicates that the address is a unicast126* address, which must match the transmitter address for127* decrypting frames.128* Not setting this bit allows the hardware to use the key129* for multicast frame decryption.130*/131if (mac[0] & 0x01)132unicast_flag = 0;133134macHi = (mac[5] << 8) | mac[4];135macLo = (mac[3] << 24)| (mac[2] << 16)136| (mac[1] << 8) | mac[0];137macLo >>= 1;138macLo |= (macHi & 1) << 31; /* carry */139macHi >>= 1;140} else {141macLo = macHi = 0;142}143OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);144OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);145return AH_TRUE;146}147148/*149* Sets the contents of the specified key cache entry150* and any associated MIC entry.151*/152HAL_BOOL153ar5212SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry,154const HAL_KEYVAL *k, const uint8_t *mac,155int xorKey)156{157struct ath_hal_5212 *ahp = AH5212(ah);158const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;159uint32_t key0, key1, key2, key3, key4;160uint32_t keyType;161uint32_t xorMask = xorKey ?162(KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0;163164if (entry >= pCap->halKeyCacheSize) {165HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",166__func__, entry);167return AH_FALSE;168}169switch (k->kv_type) {170case HAL_CIPHER_AES_OCB:171keyType = AR_KEYTABLE_TYPE_AES;172break;173case HAL_CIPHER_AES_CCM:174if (!pCap->halCipherAesCcmSupport) {175HALDEBUG(ah, HAL_DEBUG_ANY,176"%s: AES-CCM not supported by mac rev 0x%x\n",177__func__, AH_PRIVATE(ah)->ah_macRev);178return AH_FALSE;179}180keyType = AR_KEYTABLE_TYPE_CCM;181break;182case HAL_CIPHER_TKIP:183keyType = AR_KEYTABLE_TYPE_TKIP;184if (IS_MIC_ENABLED(ah) && entry+64 >= pCap->halKeyCacheSize) {185HALDEBUG(ah, HAL_DEBUG_ANY,186"%s: entry %u inappropriate for TKIP\n",187__func__, entry);188return AH_FALSE;189}190break;191case HAL_CIPHER_WEP:192if (k->kv_len < 40 / NBBY) {193HALDEBUG(ah, HAL_DEBUG_ANY,194"%s: WEP key length %u too small\n",195__func__, k->kv_len);196return AH_FALSE;197}198if (k->kv_len <= 40 / NBBY)199keyType = AR_KEYTABLE_TYPE_40;200else if (k->kv_len <= 104 / NBBY)201keyType = AR_KEYTABLE_TYPE_104;202else203keyType = AR_KEYTABLE_TYPE_128;204break;205case HAL_CIPHER_CLR:206keyType = AR_KEYTABLE_TYPE_CLR;207break;208default:209HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n",210__func__, k->kv_type);211return AH_FALSE;212}213214key0 = LE_READ_4(k->kv_val+0) ^ xorMask;215key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff;216key2 = LE_READ_4(k->kv_val+6) ^ xorMask;217key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff;218key4 = LE_READ_4(k->kv_val+12) ^ xorMask;219if (k->kv_len <= 104 / NBBY)220key4 &= 0xff;221222/*223* Note: key cache hardware requires that each double-word224* pair be written in even/odd order (since the destination is225* a 64-bit register). Don't reorder these writes w/o226* considering this!227*/228if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) {229uint16_t micentry = entry+64; /* MIC goes at slot+64 */230uint32_t mic0, mic1, mic2, mic3, mic4;231232/*233* Invalidate the encrypt/decrypt key until the MIC234* key is installed so pending rx frames will fail235* with decrypt errors rather than a MIC error.236*/237OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);238OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);239OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);240OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);241OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);242OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);243(void) ar5212SetKeyCacheEntryMac(ah, entry, mac);244245/*246* Write MIC entry according to new or old key layout.247* The MISC_MODE register is assumed already set so248* these writes will be handled properly (happens on249* attach and at every reset).250*/251/* RX mic */252mic0 = LE_READ_4(k->kv_mic+0);253mic2 = LE_READ_4(k->kv_mic+4);254if (ahp->ah_miscMode & AR_MISC_MODE_MIC_NEW_LOC_ENABLE) {255/*256* Both RX and TX mic values can be combined into257* one cache slot entry:258* 8*N + 800 31:0 RX Michael key 0259* 8*N + 804 15:0 TX Michael key 0 [31:16]260* 8*N + 808 31:0 RX Michael key 1261* 8*N + 80C 15:0 TX Michael key 0 [15:0]262* 8*N + 810 31:0 TX Michael key 1263* 8*N + 814 15:0 reserved264* 8*N + 818 31:0 reserved265* 8*N + 81C 14:0 reserved266* 15 key valid == 0267*/268/* TX mic */269mic1 = LE_READ_2(k->kv_txmic+2) & 0xffff;270mic3 = LE_READ_2(k->kv_txmic+0) & 0xffff;271mic4 = LE_READ_4(k->kv_txmic+4);272} else {273mic1 = mic3 = mic4 = 0;274}275OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);276OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);277OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);278OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);279OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);280OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),281AR_KEYTABLE_TYPE_CLR);282/* NB: MIC key is not marked valid and has no MAC address */283OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);284OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);285286/* correct intentionally corrupted key */287OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);288OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);289} else {290OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);291OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);292OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);293OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);294OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);295OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);296297(void) ar5212SetKeyCacheEntryMac(ah, entry, mac);298}299return AH_TRUE;300}301302303