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