1*572ff6f6SMatthew Dillon /*
2*572ff6f6SMatthew Dillon  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3*572ff6f6SMatthew Dillon  * Copyright (c) 2002-2008 Atheros Communications, Inc.
4*572ff6f6SMatthew Dillon  *
5*572ff6f6SMatthew Dillon  * Permission to use, copy, modify, and/or distribute this software for any
6*572ff6f6SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
7*572ff6f6SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
8*572ff6f6SMatthew Dillon  *
9*572ff6f6SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*572ff6f6SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*572ff6f6SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*572ff6f6SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*572ff6f6SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*572ff6f6SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*572ff6f6SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*572ff6f6SMatthew Dillon  *
17*572ff6f6SMatthew Dillon  * $FreeBSD$
18*572ff6f6SMatthew Dillon  */
19*572ff6f6SMatthew Dillon #include "opt_ah.h"
20*572ff6f6SMatthew Dillon 
21*572ff6f6SMatthew Dillon #include "ah.h"
22*572ff6f6SMatthew Dillon #include "ah_internal.h"
23*572ff6f6SMatthew Dillon 
24*572ff6f6SMatthew Dillon #include "ar5212/ar5212.h"
25*572ff6f6SMatthew Dillon #include "ar5212/ar5212reg.h"
26*572ff6f6SMatthew Dillon #include "ar5212/ar5212desc.h"
27*572ff6f6SMatthew Dillon 
28*572ff6f6SMatthew Dillon /*
29*572ff6f6SMatthew Dillon  * Note: The key cache hardware requires that each double-word
30*572ff6f6SMatthew Dillon  * pair be written in even/odd order (since the destination is
31*572ff6f6SMatthew Dillon  * a 64-bit register).  Don't reorder the writes in this code
32*572ff6f6SMatthew Dillon  * w/o considering this!
33*572ff6f6SMatthew Dillon  */
34*572ff6f6SMatthew Dillon #define	KEY_XOR			0xaa
35*572ff6f6SMatthew Dillon 
36*572ff6f6SMatthew Dillon #define	IS_MIC_ENABLED(ah) \
37*572ff6f6SMatthew Dillon 	(AH5212(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
38*572ff6f6SMatthew Dillon 
39*572ff6f6SMatthew Dillon /*
40*572ff6f6SMatthew Dillon  * Return the size of the hardware key cache.
41*572ff6f6SMatthew Dillon  */
42*572ff6f6SMatthew Dillon uint32_t
ar5212GetKeyCacheSize(struct ath_hal * ah)43*572ff6f6SMatthew Dillon ar5212GetKeyCacheSize(struct ath_hal *ah)
44*572ff6f6SMatthew Dillon {
45*572ff6f6SMatthew Dillon 	return AH_PRIVATE(ah)->ah_caps.halKeyCacheSize;
46*572ff6f6SMatthew Dillon }
47*572ff6f6SMatthew Dillon 
48*572ff6f6SMatthew Dillon /*
49*572ff6f6SMatthew Dillon  * Return true if the specific key cache entry is valid.
50*572ff6f6SMatthew Dillon  */
51*572ff6f6SMatthew Dillon HAL_BOOL
ar5212IsKeyCacheEntryValid(struct ath_hal * ah,uint16_t entry)52*572ff6f6SMatthew Dillon ar5212IsKeyCacheEntryValid(struct ath_hal *ah, uint16_t entry)
53*572ff6f6SMatthew Dillon {
54*572ff6f6SMatthew Dillon 	if (entry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {
55*572ff6f6SMatthew Dillon 		uint32_t val = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));
56*572ff6f6SMatthew Dillon 		if (val & AR_KEYTABLE_VALID)
57*572ff6f6SMatthew Dillon 			return AH_TRUE;
58*572ff6f6SMatthew Dillon 	}
59*572ff6f6SMatthew Dillon 	return AH_FALSE;
60*572ff6f6SMatthew Dillon }
61*572ff6f6SMatthew Dillon 
62*572ff6f6SMatthew Dillon /*
63*572ff6f6SMatthew Dillon  * Clear the specified key cache entry and any associated MIC entry.
64*572ff6f6SMatthew Dillon  */
65*572ff6f6SMatthew Dillon HAL_BOOL
ar5212ResetKeyCacheEntry(struct ath_hal * ah,uint16_t entry)66*572ff6f6SMatthew Dillon ar5212ResetKeyCacheEntry(struct ath_hal *ah, uint16_t entry)
67*572ff6f6SMatthew Dillon {
68*572ff6f6SMatthew Dillon 	uint32_t keyType;
69*572ff6f6SMatthew Dillon 
70*572ff6f6SMatthew Dillon 	if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {
71*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
72*572ff6f6SMatthew Dillon 		    __func__, entry);
73*572ff6f6SMatthew Dillon 		return AH_FALSE;
74*572ff6f6SMatthew Dillon 	}
75*572ff6f6SMatthew Dillon 	keyType = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry));
76*572ff6f6SMatthew Dillon 
77*572ff6f6SMatthew Dillon 	/* XXX why not clear key type/valid bit first? */
78*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
79*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
80*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
81*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
82*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
83*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
84*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
85*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
86*572ff6f6SMatthew Dillon 	if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) {
87*572ff6f6SMatthew Dillon 		uint16_t micentry = entry+64;	/* MIC goes at slot+64 */
88*572ff6f6SMatthew Dillon 
89*572ff6f6SMatthew Dillon 		HALASSERT(micentry < AH_PRIVATE(ah)->ah_caps.halKeyCacheSize);
90*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
91*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
92*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
93*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
94*572ff6f6SMatthew Dillon 		/* NB: key type and MAC are known to be ok */
95*572ff6f6SMatthew Dillon 	}
96*572ff6f6SMatthew Dillon 	return AH_TRUE;
97*572ff6f6SMatthew Dillon }
98*572ff6f6SMatthew Dillon 
99*572ff6f6SMatthew Dillon /*
100*572ff6f6SMatthew Dillon  * Sets the mac part of the specified key cache entry (and any
101*572ff6f6SMatthew Dillon  * associated MIC entry) and mark them valid.
102*572ff6f6SMatthew Dillon  *
103*572ff6f6SMatthew Dillon  * Since mac[0] is shifted off and not presented to the hardware,
104*572ff6f6SMatthew Dillon  * it does double duty as a "don't use for unicast, use for multicast
105*572ff6f6SMatthew Dillon  * matching" flag. This interface should later be extended to
106*572ff6f6SMatthew Dillon  * explicitly do that rather than overloading a bit in the MAC
107*572ff6f6SMatthew Dillon  * address.
108*572ff6f6SMatthew Dillon  */
109*572ff6f6SMatthew Dillon HAL_BOOL
ar5212SetKeyCacheEntryMac(struct ath_hal * ah,uint16_t entry,const uint8_t * mac)110*572ff6f6SMatthew Dillon ar5212SetKeyCacheEntryMac(struct ath_hal *ah, uint16_t entry, const uint8_t *mac)
111*572ff6f6SMatthew Dillon {
112*572ff6f6SMatthew Dillon 	uint32_t macHi, macLo;
113*572ff6f6SMatthew Dillon 	uint32_t unicast_flag = AR_KEYTABLE_VALID;
114*572ff6f6SMatthew Dillon 
115*572ff6f6SMatthew Dillon 	if (entry >= AH_PRIVATE(ah)->ah_caps.halKeyCacheSize) {
116*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
117*572ff6f6SMatthew Dillon 		    __func__, entry);
118*572ff6f6SMatthew Dillon 		return AH_FALSE;
119*572ff6f6SMatthew Dillon 	}
120*572ff6f6SMatthew Dillon 	/*
121*572ff6f6SMatthew Dillon 	 * Set MAC address -- shifted right by 1.  MacLo is
122*572ff6f6SMatthew Dillon 	 * the 4 MSBs, and MacHi is the 2 LSBs.
123*572ff6f6SMatthew Dillon 	 */
124*572ff6f6SMatthew Dillon 	if (mac != AH_NULL) {
125*572ff6f6SMatthew Dillon 		/*
126*572ff6f6SMatthew Dillon 		 * AR_KEYTABLE_VALID indicates that the address is a unicast
127*572ff6f6SMatthew Dillon 		 * address, which must match the transmitter address for
128*572ff6f6SMatthew Dillon 		 * decrypting frames.
129*572ff6f6SMatthew Dillon 		 * Not setting this bit allows the hardware to use the key
130*572ff6f6SMatthew Dillon 		 * for multicast frame decryption.
131*572ff6f6SMatthew Dillon 		 */
132*572ff6f6SMatthew Dillon 		if (mac[0] & 0x01)
133*572ff6f6SMatthew Dillon 			unicast_flag = 0;
134*572ff6f6SMatthew Dillon 
135*572ff6f6SMatthew Dillon 		macHi = (mac[5] << 8) | mac[4];
136*572ff6f6SMatthew Dillon 		macLo = (mac[3] << 24)| (mac[2] << 16)
137*572ff6f6SMatthew Dillon 		      | (mac[1] << 8) | mac[0];
138*572ff6f6SMatthew Dillon 		macLo >>= 1;
139*572ff6f6SMatthew Dillon 		macLo |= (macHi & 1) << 31;	/* carry */
140*572ff6f6SMatthew Dillon 		macHi >>= 1;
141*572ff6f6SMatthew Dillon 	} else {
142*572ff6f6SMatthew Dillon 		macLo = macHi = 0;
143*572ff6f6SMatthew Dillon 	}
144*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
145*572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
146*572ff6f6SMatthew Dillon 	return AH_TRUE;
147*572ff6f6SMatthew Dillon }
148*572ff6f6SMatthew Dillon 
149*572ff6f6SMatthew Dillon /*
150*572ff6f6SMatthew Dillon  * Sets the contents of the specified key cache entry
151*572ff6f6SMatthew Dillon  * and any associated MIC entry.
152*572ff6f6SMatthew Dillon  */
153*572ff6f6SMatthew Dillon HAL_BOOL
ar5212SetKeyCacheEntry(struct ath_hal * ah,uint16_t entry,const HAL_KEYVAL * k,const uint8_t * mac,int xorKey)154*572ff6f6SMatthew Dillon ar5212SetKeyCacheEntry(struct ath_hal *ah, uint16_t entry,
155*572ff6f6SMatthew Dillon                        const HAL_KEYVAL *k, const uint8_t *mac,
156*572ff6f6SMatthew Dillon                        int xorKey)
157*572ff6f6SMatthew Dillon {
158*572ff6f6SMatthew Dillon 	struct ath_hal_5212 *ahp = AH5212(ah);
159*572ff6f6SMatthew Dillon 	const HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps;
160*572ff6f6SMatthew Dillon 	uint32_t key0, key1, key2, key3, key4;
161*572ff6f6SMatthew Dillon 	uint32_t keyType;
162*572ff6f6SMatthew Dillon 	uint32_t xorMask = xorKey ?
163*572ff6f6SMatthew Dillon 		(KEY_XOR << 24 | KEY_XOR << 16 | KEY_XOR << 8 | KEY_XOR) : 0;
164*572ff6f6SMatthew Dillon 
165*572ff6f6SMatthew Dillon 	if (entry >= pCap->halKeyCacheSize) {
166*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: entry %u out of range\n",
167*572ff6f6SMatthew Dillon 		    __func__, entry);
168*572ff6f6SMatthew Dillon 		return AH_FALSE;
169*572ff6f6SMatthew Dillon 	}
170*572ff6f6SMatthew Dillon 	switch (k->kv_type) {
171*572ff6f6SMatthew Dillon 	case HAL_CIPHER_AES_OCB:
172*572ff6f6SMatthew Dillon 		keyType = AR_KEYTABLE_TYPE_AES;
173*572ff6f6SMatthew Dillon 		break;
174*572ff6f6SMatthew Dillon 	case HAL_CIPHER_AES_CCM:
175*572ff6f6SMatthew Dillon 		if (!pCap->halCipherAesCcmSupport) {
176*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
177*572ff6f6SMatthew Dillon 			    "%s: AES-CCM not supported by mac rev 0x%x\n",
178*572ff6f6SMatthew Dillon 			    __func__, AH_PRIVATE(ah)->ah_macRev);
179*572ff6f6SMatthew Dillon 			return AH_FALSE;
180*572ff6f6SMatthew Dillon 		}
181*572ff6f6SMatthew Dillon 		keyType = AR_KEYTABLE_TYPE_CCM;
182*572ff6f6SMatthew Dillon 		break;
183*572ff6f6SMatthew Dillon 	case HAL_CIPHER_TKIP:
184*572ff6f6SMatthew Dillon 		keyType = AR_KEYTABLE_TYPE_TKIP;
185*572ff6f6SMatthew Dillon 		if (IS_MIC_ENABLED(ah) && entry+64 >= pCap->halKeyCacheSize) {
186*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
187*572ff6f6SMatthew Dillon 			    "%s: entry %u inappropriate for TKIP\n",
188*572ff6f6SMatthew Dillon 			    __func__, entry);
189*572ff6f6SMatthew Dillon 			return AH_FALSE;
190*572ff6f6SMatthew Dillon 		}
191*572ff6f6SMatthew Dillon 		break;
192*572ff6f6SMatthew Dillon 	case HAL_CIPHER_WEP:
193*572ff6f6SMatthew Dillon 		if (k->kv_len < 40 / NBBY) {
194*572ff6f6SMatthew Dillon 			HALDEBUG(ah, HAL_DEBUG_ANY,
195*572ff6f6SMatthew Dillon 			    "%s: WEP key length %u too small\n",
196*572ff6f6SMatthew Dillon 			    __func__, k->kv_len);
197*572ff6f6SMatthew Dillon 			return AH_FALSE;
198*572ff6f6SMatthew Dillon 		}
199*572ff6f6SMatthew Dillon 		if (k->kv_len <= 40 / NBBY)
200*572ff6f6SMatthew Dillon 			keyType = AR_KEYTABLE_TYPE_40;
201*572ff6f6SMatthew Dillon 		else if (k->kv_len <= 104 / NBBY)
202*572ff6f6SMatthew Dillon 			keyType = AR_KEYTABLE_TYPE_104;
203*572ff6f6SMatthew Dillon 		else
204*572ff6f6SMatthew Dillon 			keyType = AR_KEYTABLE_TYPE_128;
205*572ff6f6SMatthew Dillon 		break;
206*572ff6f6SMatthew Dillon 	case HAL_CIPHER_CLR:
207*572ff6f6SMatthew Dillon 		keyType = AR_KEYTABLE_TYPE_CLR;
208*572ff6f6SMatthew Dillon 		break;
209*572ff6f6SMatthew Dillon 	default:
210*572ff6f6SMatthew Dillon 		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: cipher %u not supported\n",
211*572ff6f6SMatthew Dillon 		    __func__, k->kv_type);
212*572ff6f6SMatthew Dillon 		return AH_FALSE;
213*572ff6f6SMatthew Dillon 	}
214*572ff6f6SMatthew Dillon 
215*572ff6f6SMatthew Dillon 	key0 = LE_READ_4(k->kv_val+0) ^ xorMask;
216*572ff6f6SMatthew Dillon 	key1 = (LE_READ_2(k->kv_val+4) ^ xorMask) & 0xffff;
217*572ff6f6SMatthew Dillon 	key2 = LE_READ_4(k->kv_val+6) ^ xorMask;
218*572ff6f6SMatthew Dillon 	key3 = (LE_READ_2(k->kv_val+10) ^ xorMask) & 0xffff;
219*572ff6f6SMatthew Dillon 	key4 = LE_READ_4(k->kv_val+12) ^ xorMask;
220*572ff6f6SMatthew Dillon 	if (k->kv_len <= 104 / NBBY)
221*572ff6f6SMatthew Dillon 		key4 &= 0xff;
222*572ff6f6SMatthew Dillon 
223*572ff6f6SMatthew Dillon 	/*
224*572ff6f6SMatthew Dillon 	 * Note: key cache hardware requires that each double-word
225*572ff6f6SMatthew Dillon 	 * pair be written in even/odd order (since the destination is
226*572ff6f6SMatthew Dillon 	 * a 64-bit register).  Don't reorder these writes w/o
227*572ff6f6SMatthew Dillon 	 * considering this!
228*572ff6f6SMatthew Dillon 	 */
229*572ff6f6SMatthew Dillon 	if (keyType == AR_KEYTABLE_TYPE_TKIP && IS_MIC_ENABLED(ah)) {
230*572ff6f6SMatthew Dillon 		uint16_t micentry = entry+64;	/* MIC goes at slot+64 */
231*572ff6f6SMatthew Dillon 		uint32_t mic0, mic1, mic2, mic3, mic4;
232*572ff6f6SMatthew Dillon 
233*572ff6f6SMatthew Dillon 		/*
234*572ff6f6SMatthew Dillon 		 * Invalidate the encrypt/decrypt key until the MIC
235*572ff6f6SMatthew Dillon 		 * key is installed so pending rx frames will fail
236*572ff6f6SMatthew Dillon 		 * with decrypt errors rather than a MIC error.
237*572ff6f6SMatthew Dillon 		 */
238*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
239*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
240*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
241*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
242*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
243*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
244*572ff6f6SMatthew Dillon 		(void) ar5212SetKeyCacheEntryMac(ah, entry, mac);
245*572ff6f6SMatthew Dillon 
246*572ff6f6SMatthew Dillon 
247*572ff6f6SMatthew Dillon 		/*
248*572ff6f6SMatthew Dillon 		 * Write MIC entry according to new or old key layout.
249*572ff6f6SMatthew Dillon 		 * The MISC_MODE register is assumed already set so
250*572ff6f6SMatthew Dillon 		 * these writes will be handled properly (happens on
251*572ff6f6SMatthew Dillon 		 * attach and at every reset).
252*572ff6f6SMatthew Dillon 		 */
253*572ff6f6SMatthew Dillon 		/* RX mic */
254*572ff6f6SMatthew Dillon 		mic0 = LE_READ_4(k->kv_mic+0);
255*572ff6f6SMatthew Dillon 		mic2 = LE_READ_4(k->kv_mic+4);
256*572ff6f6SMatthew Dillon 		if (ahp->ah_miscMode & AR_MISC_MODE_MIC_NEW_LOC_ENABLE) {
257*572ff6f6SMatthew Dillon 			/*
258*572ff6f6SMatthew Dillon 			 * Both RX and TX mic values can be combined into
259*572ff6f6SMatthew Dillon 			 * one cache slot entry:
260*572ff6f6SMatthew Dillon 			 *  8*N + 800         31:0    RX Michael key 0
261*572ff6f6SMatthew Dillon 			 *  8*N + 804         15:0    TX Michael key 0 [31:16]
262*572ff6f6SMatthew Dillon 			 *  8*N + 808         31:0    RX Michael key 1
263*572ff6f6SMatthew Dillon 			 *  8*N + 80C         15:0    TX Michael key 0 [15:0]
264*572ff6f6SMatthew Dillon 			 *  8*N + 810         31:0    TX Michael key 1
265*572ff6f6SMatthew Dillon 			 *  8*N + 814         15:0    reserved
266*572ff6f6SMatthew Dillon 			 *  8*N + 818         31:0    reserved
267*572ff6f6SMatthew Dillon 			 *  8*N + 81C         14:0    reserved
268*572ff6f6SMatthew Dillon 			 *                    15      key valid == 0
269*572ff6f6SMatthew Dillon 			 */
270*572ff6f6SMatthew Dillon 			/* TX mic */
271*572ff6f6SMatthew Dillon 			mic1 = LE_READ_2(k->kv_txmic+2) & 0xffff;
272*572ff6f6SMatthew Dillon 			mic3 = LE_READ_2(k->kv_txmic+0) & 0xffff;
273*572ff6f6SMatthew Dillon 			mic4 = LE_READ_4(k->kv_txmic+4);
274*572ff6f6SMatthew Dillon 		} else {
275*572ff6f6SMatthew Dillon 			mic1 = mic3 = mic4 = 0;
276*572ff6f6SMatthew Dillon 		}
277*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
278*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
279*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
280*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
281*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
282*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
283*572ff6f6SMatthew Dillon 			AR_KEYTABLE_TYPE_CLR);
284*572ff6f6SMatthew Dillon 		/* NB: MIC key is not marked valid and has no MAC address */
285*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
286*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
287*572ff6f6SMatthew Dillon 
288*572ff6f6SMatthew Dillon 		/* correct intentionally corrupted key */
289*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
290*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
291*572ff6f6SMatthew Dillon 	} else {
292*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
293*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
294*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
295*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
296*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
297*572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
298*572ff6f6SMatthew Dillon 
299*572ff6f6SMatthew Dillon 		(void) ar5212SetKeyCacheEntryMac(ah, entry, mac);
300*572ff6f6SMatthew Dillon 	}
301*572ff6f6SMatthew Dillon 	return AH_TRUE;
302*572ff6f6SMatthew Dillon }
303